feat(ui): מתאמי-סוכנים לטבלה + עיצוב-תגים בתור-ההלכות (קטגוריה B #2/#3) #280

Merged
chaim merged 1 commits from worktree-catB-adapters-halacha into main 2026-06-17 03:34:03 +00:00
2 changed files with 108 additions and 54 deletions
Showing only changes of commit 85493502f0 - Show all commits

View File

@@ -27,6 +27,14 @@ import {
SelectContent,
SelectItem,
} from "@/components/ui/select";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import {
Dialog,
DialogContent,
@@ -51,6 +59,18 @@ const ADAPTERS = [
{ value: "deepseek_local", label: "DeepSeek", cls: "bg-gold-wash text-gold-deep border-gold/40" },
] as const;
// Bilingual role subtitle under the agent name (mockup 02d) — display-only,
// keyed by the agent's Hebrew name. Falls back to none for unmapped agents.
const ROLE_SUBTITLE: Record<string, string> = {
"עוזר משפטי": "CEO · מתזמר",
"מנתח משפטי": "analyst",
"כותב החלטה": "writer",
"מנהל ידע": "אוצֵר-הלכות",
"בודק איכות": "qa",
"הגהת מסמכים": "proofreader",
"שטן מליץ": "red-team (Gemini)",
};
function adapterCls(a: string | null | undefined): string {
return ADAPTERS.find((x) => x.value === a)?.cls ?? "bg-rule-soft text-ink-muted border-rule";
}
@@ -157,36 +177,44 @@ export function AgentAdaptersPanel() {
{isLoading || !data ? (
<Skeleton className="h-40 w-full" />
) : (
<div className="grid gap-2">
<div className="overflow-x-auto rounded-md border border-rule-soft">
<Table>
<TableHeader>
<TableRow className="bg-parchment hover:bg-parchment border-rule">
<TableHead className="text-start text-[0.72rem] font-medium text-ink-muted">תפקיד</TableHead>
<TableHead className="text-start text-[0.72rem] font-medium text-ink-muted">מתאם נוכחי</TableHead>
<TableHead className="text-start text-[0.72rem] font-medium text-ink-muted">מודל</TableHead>
<TableHead className="text-start text-[0.72rem] font-medium text-ink-muted">העבר ל־</TableHead>
<TableHead className="text-start text-[0.72rem] font-medium text-ink-muted" aria-label="פעולה" />
<TableHead className="text-start text-[0.72rem] font-medium text-ink-muted">מצב</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.pairs.map((p) => {
const cur = currentOf(p);
const tgt = targetFor(p);
const migrated = cur !== "claude_local" && cur !== null;
const asym = isAsymmetric(p);
const subtitle = ROLE_SUBTITLE[p.name];
return (
<div key={p.name}
className="flex items-center justify-between gap-3 rounded-md border border-rule-soft bg-rule-soft/30 px-3 py-2 flex-wrap">
<div className="min-w-0">
<div className="flex items-center gap-2 flex-wrap">
<span className="text-[0.85rem] text-navy font-semibold">{p.name}</span>
<TableRow key={p.name} className={`border-rule-soft ${asym ? "bg-danger-bg/25" : ""}`}>
<TableCell className="py-2.5 align-middle">
<div className="text-[0.85rem] text-navy font-semibold leading-tight">{p.name}</div>
{subtitle ? (
<div className="text-[0.68rem] text-ink-muted leading-tight">{subtitle}</div>
) : null}
</TableCell>
<TableCell className="py-2.5 align-middle">
<Badge variant="outline" className={`font-normal ${adapterCls(cur)}`}>
{adapterLabel(cur)}
</Badge>
<span className="text-[0.66rem] text-ink-muted font-mono" dir="ltr">
</TableCell>
<TableCell className="py-2.5 align-middle">
<span className="text-[0.68rem] text-ink-soft font-mono" dir="ltr">
{modelOf(p) || "(default)"}
</span>
{asym ? (
<Badge variant="outline" className="font-normal bg-danger-bg text-danger border-danger/40">
א-סימטרי בין החברות
</Badge>
) : migrated ? (
<Badge variant="outline" className="font-normal bg-warn-bg text-warn border-warn/40">
מועבר · fallback
</Badge>
) : null}
</div>
</div>
<div className="flex items-center gap-1.5 shrink-0">
</TableCell>
<TableCell className="py-2.5 align-middle">
<Select value={tgt} onValueChange={(v) => setTargets((t) => ({ ...t, [p.name]: v }))}>
<SelectTrigger size="sm" className="w-[8.5rem]">
<SelectValue />
@@ -197,6 +225,9 @@ export function AgentAdaptersPanel() {
))}
</SelectContent>
</Select>
</TableCell>
<TableCell className="py-2.5 align-middle">
<div className="flex items-center gap-1.5">
<Button size="xs" variant="default" disabled={busy || tgt === cur}
onClick={() => openMigrate(p.name, tgt, `העברת "${p.name}" → ${adapterLabel(tgt)}`)}>
העבר
@@ -208,9 +239,27 @@ export function AgentAdaptersPanel() {
</Button>
) : null}
</div>
</div>
</TableCell>
<TableCell className="py-2.5 align-middle">
{asym ? (
<Badge variant="outline" className="font-normal bg-danger-bg text-danger border-danger/40 whitespace-nowrap">
א-סימטרי
</Badge>
) : migrated ? (
<Badge variant="outline" className="font-normal bg-warn-bg text-warn border-warn/40 whitespace-nowrap">
מועבר · fallback
</Badge>
) : (
<Badge variant="outline" className="font-normal bg-success-bg text-success border-success/40">
תקין
</Badge>
)}
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
)}
</CardContent>

View File

@@ -185,11 +185,16 @@ function HalachaCard({
<div
data-halacha-id={h.id}
className={`
rounded-lg border bg-surface p-4 space-y-3 transition-colors
rounded-lg border p-4 space-y-3 transition-colors
${h.panel_round ? "bg-gold-wash" : "bg-surface"}
${focused ? "border-gold ring-2 ring-gold/40 shadow-md" : "border-rule"}
`}
>
<div className="flex items-start gap-2 text-[0.78rem] text-ink-muted flex-wrap">
{/* gold "הלכה" tag opening the meta row (mockup 19 `.b-hal`) */}
<Badge className="rounded bg-gold text-white border-0 text-[0.62rem] font-bold tracking-wide">
הלכה
</Badge>
{h.page_reference && (
<span className="text-[0.7rem]">{h.page_reference}</span>
)}