All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 32s
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>
125 lines
3.7 KiB
TypeScript
125 lines
3.7 KiB
TypeScript
"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>
|
||
);
|
||
}
|