Files
legal-ai/web-ui/src/components/cases/case-archive-action.tsx
Chaim 7d86ed4a62
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 32s
Archive: also cancel open Paperclip issues to clear agent widget
When a case is archived, the legal-ai UI's AgentStatusWidget kept showing
"agents started working, waiting for first report" because related
Paperclip issues remained in 'todo' / 'in_progress' status. Concrete
example: case 1130-25 had two open issues (CMP-15 ניתוח תכנוני, CMP-21
כתיבת החלטה) that lingered after the case was finalized; 1194-25 had
two more (CMP-37, CMP-44).

Extended pc_archive_project to also UPDATE issues SET status='cancelled',
cancelled_at=now() WHERE project_id matches AND status IN
('backlog','todo','in_progress','blocked','in_review'). Returns the list
of cancelled issues so the toast can announce the count.

Updated cases.ts ArchiveResult.paperclip.issues_cancelled type and the
toast message in case-archive-action to surface "(N משימות פתוחות בוטלו)"
when relevant.

Restore is intentionally unchanged — we don't auto-recreate cancelled
issues; if work needs to resume, a fresh issue should be created.

Stale issues for 1130-25 / 1194-25 cancelled directly in DB as a one-off
cleanup (CMP-15, CMP-21, CMP-37, CMP-44).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:14:12 +00:00

125 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useState } from "react";
import { toast } from "sonner";
import { Archive, RotateCcw, Loader2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { useArchiveCase, useRestoreCase, type ArchiveResult } from "@/lib/api/cases";
function paperclipMessage(res: ArchiveResult, action: "archive" | "restore"): string {
const verb = action === "archive" ? "אורכן" : "שוחזר";
switch (res.paperclip?.status) {
case "archived": {
const cancelled = res.paperclip.issues_cancelled?.length ?? 0;
const issuesNote = cancelled > 0 ? ` (${cancelled} משימות פתוחות בוטלו)` : "";
return `התיק ${verb}. גם הפרויקט ב-Paperclip${issuesNote}.`;
}
case "restored":
return `התיק ${verb}. גם הפרויקט ב-Paperclip ${verb}.`;
case "not_found":
return `התיק ${verb}. לא נמצא פרויקט מקביל ב-Paperclip.`;
case "error":
return `התיק ${verb} ב-legal-ai, אך סנכרון Paperclip נכשל${
res.paperclip?.message ? `: ${res.paperclip.message}` : "."
}`;
default:
return `התיק ${verb}.`;
}
}
export function CaseArchiveAction({
caseNumber,
archivedAt,
}: {
caseNumber: string;
archivedAt?: string | null;
}) {
const [open, setOpen] = useState(false);
const archive = useArchiveCase(caseNumber);
const restore = useRestoreCase(caseNumber);
const isArchived = Boolean(archivedAt);
const pending = archive.isPending || restore.isPending;
function handleArchive() {
archive.mutate(undefined, {
onSuccess: (res) => {
setOpen(false);
toast.success(paperclipMessage(res, "archive"));
},
onError: (err) =>
toast.error(err instanceof Error ? err.message : "שגיאה בארכוב"),
});
}
function handleRestore() {
restore.mutate(undefined, {
onSuccess: (res) => {
toast.success(paperclipMessage(res, "restore"));
},
onError: (err) =>
toast.error(err instanceof Error ? err.message : "שגיאה בשחזור"),
});
}
if (isArchived) {
return (
<Button
variant="outline"
size="sm"
disabled={pending}
onClick={handleRestore}
>
{pending ? (
<Loader2 className="me-1 h-3.5 w-3.5 animate-spin" />
) : (
<RotateCcw className="me-1 h-3.5 w-3.5" />
)}
שחזר מהארכיון
</Button>
);
}
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="outline" size="sm" disabled={pending}>
{pending ? (
<Loader2 className="me-1 h-3.5 w-3.5 animate-spin" />
) : (
<Archive className="me-1 h-3.5 w-3.5" />
)}
ארכן תיק
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>ארכון תיק {caseNumber}</DialogTitle>
<DialogDescription>
התיק יוסר מרשימת התיקים הראשית ויעבור לעמוד הארכיון. הפרויקט
המקביל ב-Paperclip יסומן גם הוא כארכוב. ניתן לשחזר בכל עת.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">בטל</Button>
</DialogClose>
<Button onClick={handleArchive} disabled={pending}>
{pending ? "מארכן..." : "ארכן"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}