From a0939449679e033a60533015f72bb9f76cc2d6c8 Mon Sep 17 00:00:00 2001 From: Chaim Date: Tue, 14 Apr 2026 13:05:30 +0000 Subject: [PATCH] Add delete button for draft files in case drafts panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add DELETE /api/cases/{case_number}/exports/{filename} endpoint - Add useDeleteDraft hook in exports API - Add trash icon + confirmation dialog in drafts panel UI - Final files (סופי-) cannot be deleted as a safety measure Co-Authored-By: Claude Opus 4.6 (1M context) --- web-ui/src/components/cases/drafts-panel.tsx | 83 +++++++++++++++++--- web-ui/src/lib/api/exports.ts | 14 ++++ web/app.py | 11 +++ 3 files changed, 98 insertions(+), 10 deletions(-) diff --git a/web-ui/src/components/cases/drafts-panel.tsx b/web-ui/src/components/cases/drafts-panel.tsx index 59a90d0..f7c6589 100644 --- a/web-ui/src/components/cases/drafts-panel.tsx +++ b/web-ui/src/components/cases/drafts-panel.tsx @@ -17,6 +17,7 @@ import { useExportDocx, useUploadDraft, useMarkFinal, + useDeleteDraft, } from "@/lib/api/exports"; import { useCaseFeedback, @@ -37,6 +38,7 @@ import { Loader2, FileOutput, Plus, + Trash2, } from "lucide-react"; /* Statuses at which a draft is considered ready */ @@ -79,9 +81,11 @@ export function DraftsPanel({ const exportDocx = useExportDocx(caseNumber); const uploadDraft = useUploadDraft(caseNumber); const markFinal = useMarkFinal(caseNumber); + const deleteDraft = useDeleteDraft(caseNumber); const resolveMutation = useResolveFeedback(); const fileRef = useRef(null); + const [deleteTarget, setDeleteTarget] = useState(null); const isDraftReady = status && DRAFT_READY.includes(status); const openFeedbacks = feedbacks?.filter((f) => !f.resolved) ?? []; @@ -233,16 +237,26 @@ export function DraftsPanel({ הורד {!file.is_final && ( - + <> + + + )} @@ -252,6 +266,55 @@ export function DraftsPanel({ )} + + {/* Delete confirmation dialog */} + !open && setDeleteTarget(null)} + > + + + מחיקת טיוטה + +

+ למחוק את הקובץ{" "} + {deleteTarget}? +
+ פעולה זו לא ניתנת לביטול. +

+
+ + +
+
+
{/* ── Chair feedback ── */} diff --git a/web-ui/src/lib/api/exports.ts b/web-ui/src/lib/api/exports.ts index a06bb64..223e725 100644 --- a/web-ui/src/lib/api/exports.ts +++ b/web-ui/src/lib/api/exports.ts @@ -71,6 +71,20 @@ export function useUploadDraft(caseNumber: string) { }); } +export function useDeleteDraft(caseNumber: string) { + const qc = useQueryClient(); + return useMutation({ + mutationFn: (filename: string) => + apiRequest<{ deleted: boolean; filename: string }>( + `/api/cases/${caseNumber}/exports/${filename}`, + { method: "DELETE" }, + ), + onSuccess: () => { + qc.invalidateQueries({ queryKey: exportsKeys.list(caseNumber) }); + }, + }); +} + export function useMarkFinal(caseNumber: string) { const qc = useQueryClient(); return useMutation({ diff --git a/web/app.py b/web/app.py index 1882ab9..dae36b6 100644 --- a/web/app.py +++ b/web/app.py @@ -1907,6 +1907,17 @@ async def api_download_export(case_number: str, filename: str): ) +@app.delete("/api/cases/{case_number}/exports/{filename}") +async def api_delete_export(case_number: str, filename: str): + """Delete an exported draft file.""" + export_dir = config.find_case_dir(case_number) / "exports" + path = export_dir / filename + if not path.exists() or not path.parent.samefile(export_dir): + raise HTTPException(404, "קובץ לא נמצא") + path.unlink() + return {"deleted": True, "filename": filename} + + @app.post("/api/cases/{case_number}/exports/upload") async def api_upload_export(case_number: str, file: UploadFile = File(...)): """Upload a revised version of a draft."""