All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 5s
הבאג: ה-StatusBadge מציג מחרוזת גולמית באנגלית ("in_progress") כשהשרת
פולט סטטוס שאינו במפת-התוויות. CaseStatus ב-web-ui החסיר שני סטטוסים
שהשרת אכן פולט — in_progress (workflow.set_outcome) ו-qa_failed
(app.py human-gate) — ולכן נפלו ל-fallback `?? status` (אנגלית גולמית).
התיקון (יישור frontend↔backend SoT, X6 UI-API contract):
- CaseStatus type: הוספת "in_progress" + "qa_failed".
- status-badge.tsx: 4 מפות Record<CaseStatus> — LABELS (בעבודה / בדיקת
איכות נכשלה), ICONS (Hammer / AlertTriangle), DESCRIPTIONS, TONE
(warn / danger).
- status-donut.tsx: GROUP_OF — in_progress→intake, qa_failed→writing.
ללא שינוי-עיצוב ויזואלי (תיקון-תוכן/i18n של רכיב קיים) → חוסה תחת
החריג המפורש בשער-העיצוב ב-web-ui/AGENTS.md.
invariants: מקיים X6 (UI↔API contract — הטיפוס תואם לסטטוסי-השרת);
לא G2 (אין מסלול מקביל), לא G1-symptom (מתקן את מקור-הדריפט בטיפוס).
tsc --noEmit עובר נקי.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
119 lines
5.3 KiB
TypeScript
119 lines
5.3 KiB
TypeScript
import { Badge } from "@/components/ui/badge";
|
||
import {
|
||
FilePlus2, Upload, Loader2, FileCheck, Target,
|
||
Lightbulb, Compass, PenLine, SearchCheck, FileText,
|
||
FileOutput, CheckCircle2, Award, ShieldCheck, BookOpen,
|
||
Microscope, PlayCircle, Hammer, AlertTriangle,
|
||
} from "lucide-react";
|
||
import type { CaseStatus } from "@/lib/api/cases";
|
||
import type { LucideIcon } from "lucide-react";
|
||
|
||
const STATUS_LABELS: Record<CaseStatus, string> = {
|
||
new: "חדש",
|
||
in_progress: "בעבודה",
|
||
uploading: "מעלה",
|
||
processing: "בעיבוד",
|
||
documents_ready: "מסמכים מוכנים",
|
||
analyst_verified: "ניתוח אומת",
|
||
research_complete: "מחקר הושלם",
|
||
outcome_set: "תוצאה נקבעה",
|
||
brainstorming: "סיעור מוחות",
|
||
direction_approved: "כיוון אושר",
|
||
analysis_enriched: "ניתוח הועמק",
|
||
ready_for_writing: "מוכן לכתיבה",
|
||
drafting: "בכתיבה",
|
||
qa_review: "בדיקת איכות",
|
||
qa_failed: "בדיקת איכות נכשלה",
|
||
drafted: "טיוטה",
|
||
exported: "יוצא",
|
||
reviewed: "נבדק",
|
||
final: "סופי",
|
||
};
|
||
|
||
const STATUS_ICONS: Record<CaseStatus, LucideIcon> = {
|
||
new: FilePlus2,
|
||
in_progress: Hammer,
|
||
uploading: Upload,
|
||
processing: Loader2,
|
||
documents_ready: FileCheck,
|
||
analyst_verified: ShieldCheck,
|
||
research_complete: BookOpen,
|
||
outcome_set: Target,
|
||
brainstorming: Lightbulb,
|
||
direction_approved: Compass,
|
||
analysis_enriched: Microscope,
|
||
ready_for_writing: PlayCircle,
|
||
drafting: PenLine,
|
||
qa_review: SearchCheck,
|
||
qa_failed: AlertTriangle,
|
||
drafted: FileText,
|
||
exported: FileOutput,
|
||
reviewed: CheckCircle2,
|
||
final: Award,
|
||
};
|
||
|
||
const STATUS_DESCRIPTIONS: Record<CaseStatus, string> = {
|
||
new: "התיק נוצר וממתין להעלאת מסמכים",
|
||
in_progress: "התיק בעבודה",
|
||
uploading: "מסמכים בתהליך העלאה לשרת",
|
||
processing: "המערכת מעבדת ומנתחת את המסמכים",
|
||
documents_ready: "כל המסמכים עובדו ומוכנים לעבודה",
|
||
analyst_verified: "ניתוח ראשוני אומת — ממתין למחקר תקדימים",
|
||
research_complete: "מחקר תקדימים הושלם — ממתין לבחירת תוצאה",
|
||
outcome_set: "נקבעה תוצאה צפויה לערר",
|
||
brainstorming: "ניתוח כיוונים אפשריים להחלטה",
|
||
direction_approved: "כיוון ההחלטה אושר — בהעמקת ניתוח",
|
||
analysis_enriched: "ניתוח הועמק ופסיקה אומתה — מוכן לכתיבה",
|
||
ready_for_writing: "הכל מוכן — ממתין לכותב ההחלטה",
|
||
drafting: "טיוטת ההחלטה בתהליך כתיבה",
|
||
qa_review: "הטיוטה בבדיקת איכות אוטומטית",
|
||
qa_failed: "בדיקת האיכות נכשלה — נדרש תיקון",
|
||
drafted: "טיוטה מוכנה לעיון",
|
||
exported: "ההחלטה יוצאה לקובץ DOCX",
|
||
reviewed: "ההחלטה נבדקה ע\"י היו\"ר",
|
||
final: "החלטה סופית — מוכנה להגשה",
|
||
};
|
||
|
||
/* Status color groups:
|
||
* intake → new, uploading, processing (muted parchment)
|
||
* prep → documents_ready, outcome_set (info blue)
|
||
* thinking→ brainstorming, direction_approved (gold)
|
||
* writing → drafting, qa_review, drafted (warn amber)
|
||
* done → exported, reviewed, final (success green) */
|
||
const STATUS_TONE: Record<CaseStatus, string> = {
|
||
new: "bg-rule-soft text-ink-muted border-rule",
|
||
in_progress: "bg-warn-bg text-warn border-warn/40",
|
||
uploading: "bg-rule-soft text-ink-muted border-rule",
|
||
processing: "bg-info-bg text-info border-info/30",
|
||
documents_ready: "bg-info-bg text-info border-info/40",
|
||
analyst_verified: "bg-info-bg text-info border-info/40",
|
||
research_complete:"bg-info-bg text-info border-info/40",
|
||
outcome_set: "bg-info-bg text-info border-info/40",
|
||
brainstorming: "bg-gold-wash text-gold-deep border-gold/40",
|
||
direction_approved:"bg-gold-wash text-gold-deep border-gold/50",
|
||
analysis_enriched:"bg-gold-wash text-gold-deep border-gold/50",
|
||
ready_for_writing:"bg-gold-wash text-gold-deep border-gold/50",
|
||
drafting: "bg-warn-bg text-warn border-warn/40",
|
||
qa_review: "bg-warn-bg text-warn border-warn/40",
|
||
qa_failed: "bg-danger-bg text-danger border-danger/40",
|
||
drafted: "bg-warn-bg text-warn border-warn/50",
|
||
exported: "bg-success-bg text-success border-success/40",
|
||
reviewed: "bg-success-bg text-success border-success/50",
|
||
final: "bg-success-bg text-success border-success/60 font-semibold",
|
||
};
|
||
|
||
export function StatusBadge({ status }: { status: CaseStatus }) {
|
||
const Icon = STATUS_ICONS[status];
|
||
return (
|
||
<Badge
|
||
variant="outline"
|
||
className={`rounded-full px-2.5 py-0.5 text-[0.72rem] font-medium inline-flex items-center gap-1 ${STATUS_TONE[status] ?? ""}`}
|
||
>
|
||
{Icon && <Icon className="w-3 h-3 shrink-0" />}
|
||
{STATUS_LABELS[status] ?? status}
|
||
</Badge>
|
||
);
|
||
}
|
||
|
||
export { STATUS_LABELS, STATUS_ICONS, STATUS_DESCRIPTIONS, STATUS_TONE };
|