[UI] Fix MCP Server Table to Match Existing Table Pattern (#11691)

* ui - clean up MCP server table

* ui - clean up table

* fix mb-4

* ui fix
This commit is contained in:
Ishaan Jaff 2025-06-12 22:35:21 -07:00 • committed by GitHub
parent a76cf95401
commit 770917fd0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 135 additions and 140 deletions

View file

@ -66,7 +66,7 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
return (
<div>
<Button
className="mx-auto"
className="mx-auto mb-4"
onClick={() => setModalVisible(true)}
>
+ Add New MCP Server

View file

@ -0,0 +1,101 @@
import React from "react";
import { ColumnDef } from "@tanstack/react-table";
import { Tooltip } from "antd";
import { Icon, Button } from "@tremor/react";
import { PencilAltIcon, TrashIcon } from "@heroicons/react/outline";
import { MCPServer, handleAuth, handleTransport } from "./types";
import { isAdminRole } from "@/utils/roles";
const displayFriendlyId = (id: string) => `${id.slice(0, 7)}...`;
const displayFriendlyUrl = (url: string) => {
if (!url) return "";
return url.length > 30 ? `${url.slice(0, 30)}...` : url;
};
export const mcpServerColumns = (
userRole: string | null,
onSelect: (serverId: string) => void,
onEdit: (serverId: string) => void,
onDelete: (serverId: string) => void
): ColumnDef<MCPServer>[] => [
{
header: "Server ID",
accessorKey: "server_id",
cell: ({ row, getValue }) => (
<div className="overflow-hidden">
<Tooltip title={getValue() as string}>
<Button
size="xs"
variant="light"
className="font-mono text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs font-normal px-2 py-0.5 text-left overflow-hidden truncate max-w-[200px]"
onClick={() => onSelect(row.original.server_id)}
>
{displayFriendlyId(getValue() as string)}
</Button>
</Tooltip>
</div>
),
},
{
header: "Server Name",
accessorKey: "alias",
cell: ({ getValue }) => <span>{getValue() as string}</span>,
},
{
header: "Description",
accessorKey: "description",
cell: ({ getValue }) => <span>{getValue() as string}</span>,
},
{
header: "Transport",
accessorKey: "transport",
cell: ({ getValue }) => <span>{handleTransport(getValue() as string)}</span>,
},
{
header: "Auth Type",
accessorKey: "auth_type",
cell: ({ getValue }) => <span>{handleAuth(getValue() as string)}</span>,
},
{
header: "Url",
accessorKey: "url",
cell: ({ getValue }) => (
<div className="overflow-hidden">
<Tooltip title={getValue() as string}>
<span className="font-mono text-gray-600 text-xs">
{displayFriendlyUrl(getValue() as string)}
</span>
</Tooltip>
</div>
),
},
{
header: "Created",
accessorKey: "created_at",
cell: ({ getValue }) => (
<span>
{getValue() ? new Date(getValue() as string).toLocaleDateString() : "N/A"}
</span>
),
},
{
id: "actions",
header: "Info",
cell: ({ row }) =>
isAdminRole(userRole || "") ? (
<>
<Icon
icon={PencilAltIcon}
size="sm"
onClick={() => onEdit(row.original.server_id)}
/>
<Icon
onClick={() => onDelete(row.original.server_id)}
icon={TrashIcon}
size="sm"
/>
</>
) : null,
},
];

View file

@ -1,7 +1,5 @@
import React, { useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { PencilAltIcon, TrashIcon } from "@heroicons/react/outline";
import { useQuery } from "@tanstack/react-query";
import {
Modal,
@ -10,19 +8,12 @@ import {
} from "antd";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeaderCell,
TableRow,
Icon,
Button,
Grid,
Col,
Title,
TextInput,
} from "@tremor/react";
import { DataTable } from "../view_logs/table";
import { mcpServerColumns } from "./mcp_server_columns";
import {
deleteMCPServer,
@ -38,12 +29,6 @@ import { isAdminRole } from "@/utils/roles";
import { MCPServerView } from "./mcp_server_view";
import CreateMCPServer from "./create_mcp_server";
const displayFriendlyId = (id: string) => {
return `${id.slice(0, 7)}...`;
};
interface DeleteModalProps {
isModalOpen: boolean;
title: string;
@ -105,11 +90,25 @@ const MCPServers: React.FC<MCPServerProps> = ({
const [selectedServerId, setSelectedServerId] = useState<string | null>(null);
const [editServer, setEditServer] = useState(false);
const handleDelete = (server_id: string) => {
const columns = React.useMemo(
() =>
mcpServerColumns(
userRole,
(serverId: string) => setSelectedServerId(serverId),
(serverId: string) => {
setSelectedServerId(serverId);
setEditServer(true);
},
handleDelete
),
[userRole, handleDelete]
);
function handleDelete(server_id: string) {
// Set the team to delete and open the confirmation modal
setServerToDelete(server_id);
setIsDeleteModalOpen(true);
};
}
const confirmDelete = async () => {
if (serverIdToDelete == null || accessToken == null) {
@ -163,133 +162,28 @@ const MCPServers: React.FC<MCPServerProps> = ({
/>
) : (
<div className="w-full p-6">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center justify-between mb-2">
<h1 className="text-xl font-semibold">MCP Servers</h1>
</div>
<Table>
<TableHead>
<TableRow>
<TableHeaderCell>Server ID</TableHeaderCell>
<TableHeaderCell>Server Name</TableHeaderCell>
<TableHeaderCell>Description</TableHeaderCell>
<TableHeaderCell>Transport</TableHeaderCell>
<TableHeaderCell>Auth Type</TableHeaderCell>
<TableHeaderCell>Url</TableHeaderCell>
<TableHeaderCell>Created</TableHeaderCell>
<TableHeaderCell>Info</TableHeaderCell>
</TableRow>
</TableHead>
<TableBody>
{!mcpServers || mcpServers.length == 0
? []
: mcpServers.map((mcpServer: MCPServer) => (
<TableRow key={mcpServer.server_id}>
<TableCell>
<div className="overflow-hidden">
<Tooltip title={mcpServer.server_id}>
<Button
size="xs"
variant="light"
className="font-mono text-blue-500 bg-blue-50 hover:bg-blue-100 text-xs font-normal px-2 py-0.5 text-left overflow-hidden truncate max-w-[200px]"
onClick={() => {
// Add click handler
setSelectedServerId(mcpServer.server_id);
}}
>
{displayFriendlyId(mcpServer.server_id)}
</Button>
</Tooltip>
</div>
</TableCell>
<TableCell
style={{
maxWidth: "4px",
whiteSpace: "pre-wrap",
overflow: "hidden",
}}
>
{mcpServer.alias}
</TableCell>
<TableCell
style={{
maxWidth: "4px",
whiteSpace: "pre-wrap",
overflow: "hidden",
}}
>
{mcpServer.description}
</TableCell>
<TableCell
style={{
maxWidth: "4px",
whiteSpace: "pre-wrap",
overflow: "hidden",
}}
>
{handleTransport(mcpServer.transport)}
</TableCell>
<TableCell
style={{
maxWidth: "4px",
whiteSpace: "pre-wrap",
overflow: "hidden",
}}
>
{handleAuth(mcpServer.auth_type)}
</TableCell>
<TableCell>
<div className="overflow-hidden">
<Tooltip title={mcpServer.url}>
{mcpServer.url}
</Tooltip>
</div>
</TableCell>
<TableCell
style={{
maxWidth: "4px",
whiteSpace: "pre-wrap",
overflow: "hidden",
}}
>
{mcpServer.created_at
? new Date(mcpServer.created_at).toLocaleDateString()
: "N/A"}
</TableCell>
<TableCell>
{isAdminRole(userRole) ? (
<>
<Icon
icon={PencilAltIcon}
size="sm"
onClick={() => {
setSelectedServerId(mcpServer.server_id);
setEditServer(true);
}}
/>
<Icon
onClick={() => handleDelete(mcpServer.server_id)}
icon={TrashIcon}
size="sm"
/>
</>
) : null}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<CreateMCPServer
userRole={userRole}
accessToken={accessToken}
onCreateSuccess={createMCPServer}
/>
<DataTable
columns={columns}
data={mcpServers || []}
renderSubComponent={() => <></>}
getRowCanExpand={() => false}
isLoading={isLoadingServers}
noDataMessage="No MCP Servers found"
/>
<DeleteModal
isModalOpen={isDeleteModalOpen}
title="Delete MCP Server"
confirmDelete={confirmDelete}
cancelDelete={cancelDelete}
/>
<CreateMCPServer
userRole={userRole}
accessToken={accessToken}
onCreateSuccess={createMCPServer}
/>
</div>
)}
</div>