mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-14 23:22:51 +00:00
Render disconnected MCP servers in the stage insights sidebar
A server whose connection closed mid-stage shows an amber warning icon and a "Disconnected" badge, distinct from a server that failed to start. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
3b33730bac
commit
49afaa9025
2 changed files with 59 additions and 15 deletions
|
|
@ -215,6 +215,26 @@ describe("StageInsightsSidebar", () => {
|
|||
expect(dom).toContain("Failed");
|
||||
});
|
||||
|
||||
test("renders a disconnected mcp server as disconnected, still counted as used", () => {
|
||||
const dom = render(
|
||||
makeStage({
|
||||
mcp_servers: [
|
||||
{
|
||||
server_name: "github",
|
||||
tool_count: 4,
|
||||
status: { kind: "disconnected", error: "transport closed" },
|
||||
invoked: true,
|
||||
},
|
||||
],
|
||||
}),
|
||||
null,
|
||||
);
|
||||
expect(dom).toContain("1/1");
|
||||
expect(dom).toContain("github");
|
||||
expect(dom).toContain("Disconnected");
|
||||
expect(dom).not.toContain("Failed");
|
||||
});
|
||||
|
||||
test("shows skill activated/available ratio with source label", () => {
|
||||
const dom = render(
|
||||
makeStage({
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
import {
|
||||
ArrowPathIcon,
|
||||
CheckCircleIcon,
|
||||
ExclamationTriangleIcon,
|
||||
XCircleIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
import {
|
||||
|
|
@ -554,27 +555,15 @@ function McpSection({ servers }: { servers: McpServerProjection[] }) {
|
|||
<ul className="space-y-1">
|
||||
{servers.map((server) => {
|
||||
// Dim unused servers so the eye lands on the invoked ones first;
|
||||
// failed servers stay coral regardless.
|
||||
// failed and disconnected servers keep their tone regardless.
|
||||
const nameClass = server.status.kind === "ready" && !server.invoked
|
||||
? "min-w-0 flex-1 truncate text-xs text-fg-muted"
|
||||
: "min-w-0 flex-1 truncate text-xs text-fg-2";
|
||||
return (
|
||||
<li key={server.server_name} className="flex items-center gap-1.5">
|
||||
{server.status.kind === "ready" ? (
|
||||
<CheckCircleIcon className="size-3.5 shrink-0 text-mint" aria-label="Ready" />
|
||||
) : (
|
||||
<XCircleIcon className="size-3.5 shrink-0 text-coral" aria-label="Failed" />
|
||||
)}
|
||||
<McpStatusIcon status={server.status} />
|
||||
<span className={nameClass}>{server.server_name}</span>
|
||||
{server.status.kind === "ready" ? (
|
||||
<span className="font-mono text-[10px] tabular-nums text-fg-muted">
|
||||
{server.invoked
|
||||
? "used"
|
||||
: `${server.tool_count} ${server.tool_count === 1 ? "tool" : "tools"}`}
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-[10px] uppercase tracking-wider text-coral">Failed</span>
|
||||
)}
|
||||
<McpStatusBadge server={server} />
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
|
@ -582,6 +571,41 @@ function McpSection({ servers }: { servers: McpServerProjection[] }) {
|
|||
);
|
||||
}
|
||||
|
||||
function McpStatusIcon({ status }: { status: McpServerProjection["status"] }) {
|
||||
switch (status.kind) {
|
||||
case "ready":
|
||||
return <CheckCircleIcon className="size-3.5 shrink-0 text-mint" aria-label="Ready" />;
|
||||
case "disconnected":
|
||||
return (
|
||||
<ExclamationTriangleIcon
|
||||
className="size-3.5 shrink-0 text-amber"
|
||||
aria-label="Disconnected"
|
||||
/>
|
||||
);
|
||||
case "failed":
|
||||
return <XCircleIcon className="size-3.5 shrink-0 text-coral" aria-label="Failed" />;
|
||||
}
|
||||
}
|
||||
|
||||
function McpStatusBadge({ server }: { server: McpServerProjection }) {
|
||||
switch (server.status.kind) {
|
||||
case "ready":
|
||||
return (
|
||||
<span className="font-mono text-[10px] tabular-nums text-fg-muted">
|
||||
{server.invoked
|
||||
? "used"
|
||||
: `${server.tool_count} ${server.tool_count === 1 ? "tool" : "tools"}`}
|
||||
</span>
|
||||
);
|
||||
case "disconnected":
|
||||
return (
|
||||
<span className="text-[10px] uppercase tracking-wider text-amber">Disconnected</span>
|
||||
);
|
||||
case "failed":
|
||||
return <span className="text-[10px] uppercase tracking-wider text-coral">Failed</span>;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- helpers ----------
|
||||
|
||||
type IconType = (props: { className?: string }) => ReactNode;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue