feat(settings): implement Registrations tab
Replaces stub RegistrationsTab with a full read-only view grouped by client. Handles all 4 states: loading skeleton, fetch error, host_path_unavailable, empty list, and populated data with per-registration detail rows. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1 +1,134 @@
|
||||
export function RegistrationsTab() { return <div>Registrations tab — coming soon</div>; }
|
||||
"use client";
|
||||
|
||||
import { Plug, AlertCircle } from "lucide-react";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useMcpRegistrations } from "@/lib/api/settings";
|
||||
|
||||
export function RegistrationsTab() {
|
||||
const { data, isPending, error } = useMcpRegistrations();
|
||||
|
||||
if (isPending) return <Skeleton className="h-64 w-full" />;
|
||||
if (error) {
|
||||
return (
|
||||
<Card className="bg-surface border-danger/40">
|
||||
<CardContent className="p-6 flex items-center gap-3 text-danger">
|
||||
<AlertCircle className="w-5 h-5" />
|
||||
<span>שגיאה: {error.message}</span>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
if (!data) return null;
|
||||
|
||||
if (data.error === "host_path_unavailable") {
|
||||
return (
|
||||
<Card className="bg-surface border-warn/40">
|
||||
<CardContent className="p-6">
|
||||
<div className="flex items-center gap-3 text-warn mb-2">
|
||||
<AlertCircle className="w-5 h-5" />
|
||||
<span className="font-medium">תיקיית /host לא זמינה בקונטיינר</span>
|
||||
</div>
|
||||
<p className="text-sm text-ink-muted mb-2">
|
||||
כדי להציג רישומי MCP, יש להוסיף volume mounts ב-Coolify.
|
||||
ראה runbook ב-
|
||||
<code dir="ltr" className="mx-1">
|
||||
docs/runbooks/coolify-mcp-settings-volumes.md
|
||||
</code>
|
||||
</p>
|
||||
{data.message && (
|
||||
<p className="text-sm text-ink-muted">{data.message}</p>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
if (!data.registrations.length) {
|
||||
return (
|
||||
<Card className="bg-surface border-rule">
|
||||
<CardContent className="p-6 text-ink-muted text-sm">
|
||||
לא נמצאו רישומי MCP.
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
// Group by client
|
||||
const groups = new Map<string, typeof data.registrations>();
|
||||
for (const r of data.registrations) {
|
||||
const arr = groups.get(r.client) ?? [];
|
||||
arr.push(r);
|
||||
groups.set(r.client, arr);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-2 text-sm text-ink-muted">
|
||||
<Plug className="w-4 h-4" />
|
||||
סה"כ {data.registrations.length} רישומים
|
||||
</div>
|
||||
{[...groups.entries()].map(([client, regs]) => (
|
||||
<Card key={client} className="bg-surface border-rule">
|
||||
<CardContent className="px-6 py-5">
|
||||
<h2 className="text-navy text-lg mb-4 flex items-center gap-2">
|
||||
{client}
|
||||
<Badge variant="outline" className="text-[0.7rem]">
|
||||
{regs.length}
|
||||
</Badge>
|
||||
</h2>
|
||||
<div className="space-y-3">
|
||||
{regs.map((r, i) => (
|
||||
<div
|
||||
key={`${r.server_name}-${i}`}
|
||||
className="rounded-md border border-rule bg-rule-soft/20 p-4 space-y-2 text-sm"
|
||||
>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<code dir="ltr" className="font-mono font-medium text-navy">
|
||||
{r.server_name}
|
||||
</code>
|
||||
<Badge variant="outline" className="text-[0.7rem]" dir="ltr">
|
||||
{r.transport}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-[100px_1fr] gap-x-3 gap-y-1.5 text-[0.82rem]">
|
||||
<span className="text-ink-muted">command:</span>
|
||||
<code dir="ltr" className="font-mono text-ink break-all">
|
||||
{r.command || "—"}
|
||||
</code>
|
||||
<span className="text-ink-muted">args:</span>
|
||||
<code dir="ltr" className="font-mono text-ink break-all">
|
||||
{r.args.length ? JSON.stringify(r.args) : "[]"}
|
||||
</code>
|
||||
<span className="text-ink-muted">cwd:</span>
|
||||
<code dir="ltr" className="font-mono text-ink break-all">
|
||||
{r.cwd || "—"}
|
||||
</code>
|
||||
<span className="text-ink-muted">env keys:</span>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{r.env_keys.length === 0 ? (
|
||||
<span className="text-ink-muted">—</span>
|
||||
) : (
|
||||
r.env_keys.map((k) => (
|
||||
<Badge
|
||||
key={k}
|
||||
variant="outline"
|
||||
className="text-[0.7rem] font-mono"
|
||||
dir="ltr"
|
||||
>
|
||||
{k}
|
||||
</Badge>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user