Files
legal-ai/web-ui/src/components/cases/agent-status-widget.tsx
Chaim e5168fe79d refactor(web-ui): disambiguate Paperclip agent DTO; document platform-presentation boundary (R3, G12, #112)
ממצא: התוכנית המקורית (namespace ל-paperclip.* ב-types.ts) בלתי-ישימה — types.ts
נוצר-אוטומטית מ-OpenAPI ("Do not make direct changes"); הפניות-Paperclip שם רק משקפות
את ה-API של ה-backend, ונשלטות ע"י מודלי-ה-Pydantic, לא ע"י הפרונט. הפרונט אינו
שכבת-אינטליגנציה — הפניות-Paperclip בו הן הצגת-נתוני-פלטפורמה (activity feed, קישור
לדאשבורד, סטטוס-ארכוב) או UI-ניהול מוצהר (paperclip-tab/agents-tab) — כולן shell-adjacent
לגיטימי תחת G12.

הבעיה האמיתית-והישימה: התנגשות-שם — `PaperclipAgent` הוגדר פעמיים עם shapes שונים
(config ב-paperclip-agents.ts מול activity ב-agents.ts). פוצל: ה-activity-DTO →
`PaperclipAgentStatus`; ה-config שומר `PaperclipAgent`. + הערת-כותרת שמסמנת את agents.ts
כמודול הצגת-פלטפורמה מוצהר.

מזין את R4 (#113): leak-guard חייב להחריג קבצים-נוצרים (types.ts) ולא לכלול את הפרונט
בהיקף שכבת-האינטליגנציה המוגנת.

אימות: tsc --noEmit נקי; eslint נקי על הקבצים ששונו.

Invariants: G12 (גבול-פלטפורמה מוצהר בפרונט), G2 (הסרת שם-טיפוס כפול-משמעות).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 09:33:44 +00:00

80 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useAgentActivity } from "@/lib/api/agents";
import type { PaperclipAgentStatus } from "@/lib/api/agents";
import { Bot } from "lucide-react";
/* ── Status dot colors ───────────────────────────────────────── */
const STATUS_DOT: Record<string, string> = {
active: "bg-emerald-500 shadow-[0_0_6px_rgba(16,185,129,0.6)]",
running: "bg-emerald-500 shadow-[0_0_6px_rgba(16,185,129,0.6)]",
idle: "bg-gray-300",
error: "bg-red-500",
};
const STATUS_LABEL: Record<string, string> = {
active: "פעיל",
running: "פעיל",
idle: "ממתין",
error: "שגיאה",
};
function statusDot(status: string) {
return STATUS_DOT[status] ?? STATUS_DOT.idle;
}
/* ── Agent row ───────────────────────────────────────────────── */
function AgentRow({ agent }: { agent: PaperclipAgentStatus }) {
return (
<div className="flex items-center gap-2 py-1">
<span
className={`w-2 h-2 rounded-full flex-shrink-0 ${statusDot(agent.status)}`}
/>
<span className="text-xs text-ink truncate">{agent.name}</span>
<span className="text-[10px] text-ink-faint mr-auto">
{STATUS_LABEL[agent.status] ?? agent.status}
</span>
</div>
);
}
/* ── Widget ───────────────────────────────────────────────────── */
export function AgentStatusWidget({
caseNumber,
}: {
caseNumber: string;
}) {
const { data } = useAgentActivity(caseNumber);
// Don't render if no Paperclip project yet
if (!data?.issues?.length) return null;
const agents = data.agents ?? [];
const activeCount = agents.filter((a) => a.status === "active" || a.status === "running").length;
return (
<div className="space-y-2">
<div className="flex items-center justify-between">
<div className="flex items-center gap-1.5 text-xs font-medium text-navy">
<Bot className="w-3.5 h-3.5" />
<span>סוכנים</span>
</div>
{agents.length > 0 && (
<span className="text-[10px] text-ink-faint">
{activeCount} פעילים מתוך {agents.length}
</span>
)}
</div>
<div className="space-y-0.5">
{agents.map((agent) => (
<AgentRow key={agent.id} agent={agent} />
))}
</div>
</div>
);
}