From 6b15f84fdb41367b622b4e65ab92ec9789c33e6b Mon Sep 17 00:00:00 2001 From: Chaim Date: Mon, 13 Apr 2026 12:43:07 +0000 Subject: [PATCH] WIP: documents panel UI improvements --- .../src/components/cases/documents-panel.tsx | 160 +++++++++++++----- .../src/components/documents/upload-sheet.tsx | 2 +- 2 files changed, 119 insertions(+), 43 deletions(-) diff --git a/web-ui/src/components/cases/documents-panel.tsx b/web-ui/src/components/cases/documents-panel.tsx index 4321529..13550e6 100644 --- a/web-ui/src/components/cases/documents-panel.tsx +++ b/web-ui/src/components/cases/documents-panel.tsx @@ -1,5 +1,7 @@ import { Badge } from "@/components/ui/badge"; +import { Progress } from "@/components/ui/progress"; import { ScrollArea } from "@/components/ui/scroll-area"; +import { CheckCircle2, Clock, Loader2, XCircle } from "lucide-react"; import type { CaseDetail } from "@/lib/api/cases"; /* @@ -43,6 +45,37 @@ const STATUS_LABELS: Record = { error: "שגיאה", }; +/** Sort priority — lower = higher in list */ +const STATUS_ORDER: Record = { + failed: 0, + error: 0, + processing: 1, + pending: 2, + completed: 3, + proofread: 3, +}; + +function statusOrder(s: string): number { + return STATUS_ORDER[s] ?? 3; +} + +function StatusIcon({ status }: { status: string }) { + switch (status) { + case "completed": + case "proofread": + return ; + case "processing": + return ; + case "pending": + return ; + case "failed": + case "error": + return ; + default: + return ; + } +} + function formatDate(iso: string) { if (!iso) return "—"; try { @@ -69,49 +102,92 @@ export function DocumentsPanel({ data }: { data?: CaseDetail }) { ); } + const sorted = [...docs].sort( + (a, b) => statusOrder(a.extraction_status) - statusOrder(b.extraction_status), + ); + + const done = docs.filter( + (d) => d.extraction_status === "completed" || d.extraction_status === "proofread", + ).length; + const processing = docs.filter((d) => d.extraction_status === "processing").length; + const pending = docs.filter((d) => d.extraction_status === "pending").length; + const failed = docs.filter( + (d) => d.extraction_status === "failed" || d.extraction_status === "error", + ).length; + const hasIncomplete = processing > 0 || pending > 0 || failed > 0; + const pct = docs.length > 0 ? Math.round((done / docs.length) * 100) : 0; + return ( - -
    - {docs.map((doc) => { - const displayName = doc.title || filenameFromPath(doc.file_path); - const statusDone = - doc.extraction_status === "completed" || - doc.extraction_status === "proofread"; - return ( -
  • - {/* Title + meta — flex-1 keeps it glued to the start (right in RTL) */} -
    -
    - {displayName} +
    + {hasIncomplete && ( +
    +
    + {done > 0 && ( + + + {done} {STATUS_LABELS.completed} + + )} + {processing > 0 && ( + + + {processing} {STATUS_LABELS.processing} + + )} + {pending > 0 && ( + + + {pending} {STATUS_LABELS.pending} + + )} + {failed > 0 && ( + + + {failed} {STATUS_LABELS.failed} + + )} +
    + 0 && done === 0 ? "[&>div]:bg-danger" : ""} + /> +
    + )} + + +
      + {sorted.map((doc) => { + const displayName = doc.title || filenameFromPath(doc.file_path); + return ( +
    • + +
      +
      + {displayName} +
      +
      + {doc.page_count != null && ( + {doc.page_count} עמ׳ + )} + {doc.created_at && {formatDate(doc.created_at)}} +
      -
      - {doc.page_count != null && ( - {doc.page_count} עמ׳ - )} - {doc.created_at && {formatDate(doc.created_at)}} - {!statusDone && doc.extraction_status && ( - - {STATUS_LABELS[doc.extraction_status] ?? doc.extraction_status} - - )} -
      -
    - {/* Type badge — ms-auto forces it to the inline-end (= left in RTL) */} - {doc.doc_type && ( - - {doctypeLabel(doc.doc_type)} - - )} -
  • - ); - })} -
-
+ {doc.doc_type && ( + + {doctypeLabel(doc.doc_type)} + + )} + + ); + })} + + + ); } diff --git a/web-ui/src/components/documents/upload-sheet.tsx b/web-ui/src/components/documents/upload-sheet.tsx index af03884..6646b78 100644 --- a/web-ui/src/components/documents/upload-sheet.tsx +++ b/web-ui/src/components/documents/upload-sheet.tsx @@ -155,7 +155,7 @@ export function UploadSheet({ caseNumber }: { caseNumber: string }) { -
+