mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-17 23:51:30 +00:00
redesign credentials table to use Tremor table layout matching Keys page
This commit is contained in:
parent
ae9b2f93ef
commit
940e957ebe
1 changed files with 63 additions and 78 deletions
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { Spin, message } from "antd";
|
||||
import { CheckCircleOutlined, DeleteOutlined, LinkOutlined } from "@ant-design/icons";
|
||||
import { DeleteOutlined, LinkOutlined } from "@ant-design/icons";
|
||||
import { Badge, Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from "@tremor/react";
|
||||
import {
|
||||
deleteMCPOAuthUserCredential,
|
||||
listMCPUserCredentials,
|
||||
|
|
@ -86,98 +87,82 @@ const MCPCredentialsTab: React.FC<Props> = ({ accessToken }) => {
|
|||
c.alias || c.server_name || c.server_id;
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%" }}>
|
||||
<div className="w-full">
|
||||
{/* Header */}
|
||||
<div style={{ marginBottom: 20 }}>
|
||||
<h2 style={{ margin: "0 0 4px", fontSize: 18, fontWeight: 600, color: "#111827" }}>
|
||||
App Credentials
|
||||
</h2>
|
||||
<p style={{ margin: 0, fontSize: 13, color: "#6b7280" }}>
|
||||
<div className="mb-4">
|
||||
<h2 className="text-base font-semibold text-gray-900 mb-0.5">App Credentials</h2>
|
||||
<p className="text-sm text-gray-500 m-0">
|
||||
Your stored OAuth connections — used automatically in chat.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
<div style={{ display: "flex", justifyContent: "center", padding: "48px 0" }}>
|
||||
<div className="flex justify-center py-12">
|
||||
<Spin />
|
||||
</div>
|
||||
) : credentials.length === 0 ? (
|
||||
<div style={{
|
||||
textAlign: "center", color: "#9ca3af", fontSize: 13,
|
||||
padding: "48px 12px", border: "1px dashed #e5e7eb", borderRadius: 10,
|
||||
}}>
|
||||
<LinkOutlined style={{ fontSize: 28, marginBottom: 12, display: "block", color: "#d1d5db" }} />
|
||||
<div className="text-center text-gray-400 text-sm py-12 border border-dashed border-gray-200 rounded-lg">
|
||||
<LinkOutlined className="text-2xl mb-3 block text-gray-300" />
|
||||
No connections yet.
|
||||
<br />
|
||||
Go to <strong>Apps</strong> and click <strong>Connect</strong> to authorize an MCP server.
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
|
||||
{credentials.map((cred) => {
|
||||
const name = displayName(cred);
|
||||
const isRevoking = revoking.has(cred.server_id);
|
||||
const exp = expiryLabel(cred.expires_at);
|
||||
const connected = relativeTime(cred.connected_at);
|
||||
const isExpired = exp === "Expired";
|
||||
<div className="rounded-lg border border-gray-200 overflow-hidden">
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableHeaderCell className="text-xs font-medium text-gray-500 py-2 px-4">
|
||||
App
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell className="text-xs font-medium text-gray-500 py-2 px-4">
|
||||
Connected
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell className="text-xs font-medium text-gray-500 py-2 px-4">
|
||||
Status
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell className="text-xs font-medium text-gray-500 py-2 px-4 text-right">
|
||||
Actions
|
||||
</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{credentials.map((cred) => {
|
||||
const name = displayName(cred);
|
||||
const isRevoking = revoking.has(cred.server_id);
|
||||
const exp = expiryLabel(cred.expires_at);
|
||||
const connected = relativeTime(cred.connected_at);
|
||||
const isExpired = exp === "Expired";
|
||||
|
||||
return (
|
||||
<div
|
||||
key={cred.server_id}
|
||||
style={{
|
||||
display: "flex", alignItems: "center", gap: 12,
|
||||
padding: "14px 16px", border: "1px solid #e5e7eb",
|
||||
borderRadius: 10, background: "#fff",
|
||||
}}
|
||||
>
|
||||
{/* Status dot */}
|
||||
<div style={{ flexShrink: 0 }}>
|
||||
<CheckCircleOutlined style={{ fontSize: 20, color: isExpired ? "#d1d5db" : "#52c41a" }} />
|
||||
</div>
|
||||
|
||||
{/* Info */}
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
<div style={{ fontSize: 14, fontWeight: 600, color: "#111827", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
|
||||
{name}
|
||||
</div>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 10, marginTop: 2, flexWrap: "wrap" }}>
|
||||
{connected && (
|
||||
<span style={{ fontSize: 12, color: "#9ca3af" }}>
|
||||
Connected {connected}
|
||||
</span>
|
||||
)}
|
||||
<span style={{
|
||||
fontSize: 11, fontWeight: 600,
|
||||
color: isExpired ? "#ef4444" : "#16a34a",
|
||||
background: isExpired ? "#fef2f2" : "#f0fdf4",
|
||||
borderRadius: 4, padding: "1px 6px",
|
||||
}}>
|
||||
{exp}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Revoke */}
|
||||
<button
|
||||
onClick={() => handleRevoke(cred.server_id)}
|
||||
disabled={isRevoking}
|
||||
title="Revoke connection"
|
||||
style={{
|
||||
background: "none", border: "1px solid #e5e7eb",
|
||||
borderRadius: 6, padding: "4px 8px",
|
||||
cursor: isRevoking ? "not-allowed" : "pointer",
|
||||
color: "#9ca3af", display: "flex", alignItems: "center",
|
||||
opacity: isRevoking ? 0.5 : 1, flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
{isRevoking ? (
|
||||
<Spin size="small" />
|
||||
) : (
|
||||
<DeleteOutlined style={{ fontSize: 14 }} />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
return (
|
||||
<TableRow key={cred.server_id} className="h-10 hover:bg-gray-50">
|
||||
<TableCell className="py-2 px-4">
|
||||
<span className="text-sm font-medium text-gray-900">{name}</span>
|
||||
</TableCell>
|
||||
<TableCell className="py-2 px-4">
|
||||
<span className="text-sm text-gray-500">{connected || "—"}</span>
|
||||
</TableCell>
|
||||
<TableCell className="py-2 px-4">
|
||||
<Badge color={isExpired ? "red" : "green"} size="xs">
|
||||
{exp}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="py-2 px-4 text-right">
|
||||
<button
|
||||
onClick={() => handleRevoke(cred.server_id)}
|
||||
disabled={isRevoking}
|
||||
title="Revoke connection"
|
||||
className={`inline-flex items-center justify-center rounded-md border border-gray-200 px-2 py-1 text-gray-400 hover:text-red-500 hover:border-red-200 transition-colors ${isRevoking ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}`}
|
||||
style={{ background: "none" }}
|
||||
>
|
||||
{isRevoking ? <Spin size="small" /> : <DeleteOutlined className="text-sm" />}
|
||||
</button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue