feat(ui): מתאמי-סוכנים לטבלה + אימוץ עיצוב-תגים בתור-ההלכות (קטגוריה B #2/#3)
הכרעות-מוצר מדוח-הנאמנות: - agent-adapters-panel: כרטיסונים → טבלה (6 עמודות: תפקיד+תת-תפקיד / מתאם / מודל / העבר-ל / פעולה / מצב) לפי מוקאפ 02d. כל הלוגיקה נשמרה (preflight-dialog, revert, relax-tools, fallback-bar, דגל-א-סימטרי). עמודת "מצב": תקין/מועבר· fallback/⚠ א-סימטרי. תת-תפקיד דו-לשוני (analyst/writer/qa…). - halacha review card: אימוץ שפת-התגים/צבעים ממוקאפ 19 — תג-זהב "הלכה" בפתח שורת-המטא, ורקע gold-wash לכרטיסים עם התלבטות-פאנל (כמו .rc מול .rc.plain). מבנה-האקורדיון נשמר (החלטת חיים). יישור-קוד למוקאפים-מאושרים — ללא סבב-עיצוב חדש. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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,60 +177,89 @@ export function AgentAdaptersPanel() {
|
||||
{isLoading || !data ? (
|
||||
<Skeleton className="h-40 w-full" />
|
||||
) : (
|
||||
<div className="grid gap-2">
|
||||
{data.pairs.map((p) => {
|
||||
const cur = currentOf(p);
|
||||
const tgt = targetFor(p);
|
||||
const migrated = cur !== "claude_local" && cur !== null;
|
||||
const asym = isAsymmetric(p);
|
||||
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>
|
||||
<Badge variant="outline" className={`font-normal ${adapterCls(cur)}`}>
|
||||
{adapterLabel(cur)}
|
||||
</Badge>
|
||||
<span className="text-[0.66rem] text-ink-muted font-mono" dir="ltr">
|
||||
{modelOf(p) || "(default)"}
|
||||
</span>
|
||||
{asym ? (
|
||||
<Badge variant="outline" className="font-normal bg-danger-bg text-danger border-danger/40">
|
||||
⚠ א-סימטרי בין החברות
|
||||
<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 (
|
||||
<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>
|
||||
) : 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">
|
||||
<Select value={tgt} onValueChange={(v) => setTargets((t) => ({ ...t, [p.name]: v }))}>
|
||||
<SelectTrigger size="sm" className="w-[8.5rem]">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{ADAPTERS.map((a) => (
|
||||
<SelectItem key={a.value} value={a.value}>{a.label}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button size="xs" variant="default" disabled={busy || tgt === cur}
|
||||
onClick={() => openMigrate(p.name, tgt, `העברת "${p.name}" → ${adapterLabel(tgt)}`)}>
|
||||
העבר
|
||||
</Button>
|
||||
{migrated ? (
|
||||
<Button size="xs" variant="ghost" disabled={busy}
|
||||
onClick={() => openRevert(p.name, `החזרת "${p.name}" למצב-מקור`)}>
|
||||
החזר
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</TableCell>
|
||||
<TableCell className="py-2.5 align-middle">
|
||||
<span className="text-[0.68rem] text-ink-soft font-mono" dir="ltr">
|
||||
{modelOf(p) || "(default)"}
|
||||
</span>
|
||||
</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 />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{ADAPTERS.map((a) => (
|
||||
<SelectItem key={a.value} value={a.value}>{a.label}</SelectItem>
|
||||
))}
|
||||
</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)}`)}>
|
||||
העבר
|
||||
</Button>
|
||||
{migrated ? (
|
||||
<Button size="xs" variant="ghost" disabled={busy}
|
||||
onClick={() => openRevert(p.name, `החזרת "${p.name}" למצב-מקור`)}>
|
||||
החזר
|
||||
</Button>
|
||||
) : null}
|
||||
</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>
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user