From 171da84680f67d5c4108b7e432ee9590c05cb0e4 Mon Sep 17 00:00:00 2001 From: Chaim Date: Thu, 7 May 2026 06:30:03 +0000 Subject: [PATCH] feat(precedent-library): add halacha-extract button to library list rows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a precedent has not had successful halacha extraction yet, show a small wand icon between the edit and delete buttons. Clicking it queues the precedent for the local MCP worker (request-halachot endpoint). Visibility rule (`needsHalachaExtraction`): show when text extraction is complete AND halacha status is "pending without requested_at" (never tried) or "failed" (allow retry). Hide while processing, after completion, or when already queued — to avoid duplicate requests. Pairs with the metadata-extract button on the edit sheet. --- .../precedents/library-list-panel.tsx | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/web-ui/src/components/precedents/library-list-panel.tsx b/web-ui/src/components/precedents/library-list-panel.tsx index ffeee82..d87c3e1 100644 --- a/web-ui/src/components/precedents/library-list-panel.tsx +++ b/web-ui/src/components/precedents/library-list-panel.tsx @@ -1,7 +1,7 @@ "use client"; import { useState } from "react"; -import { Trash2, Plus, Pencil } from "lucide-react"; +import { Trash2, Plus, Pencil, Wand2 } from "lucide-react"; import { toast } from "sonner"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, @@ -16,6 +16,7 @@ import { import { usePrecedents, useDeletePrecedent, + useRequestHalachotExtraction, isPrecedentActive, type Precedent, type PracticeArea, @@ -38,6 +39,20 @@ function cleanCitation(s: string | null | undefined): string { return s.replace(/[‎‏‪-‮⁦-⁩]/g, "").trim(); } +// Show the "extract halachot" button only when the precedent hasn't had a +// successful (or even attempted) extraction yet. Hide while processing or +// after completion to avoid duplicate requests. +function needsHalachaExtraction(p: Precedent): boolean { + if (p.extraction_status !== "completed") return false; // text not ready + if (p.halacha_extraction_status === "processing") return false; + if (p.halacha_extraction_status === "completed") return false; + if (p.halacha_extraction_status === "pending" && p.halacha_extraction_requested_at) { + return false; // already queued + } + // Remaining cases: pending+no-requested_at (never tried) or failed (retry). + return true; +} + function ActivePill({ label }: { label: string }) { return ( void }) { const del = useDeletePrecedent(); + const reqHalachot = useRequestHalachotExtraction(); const active = isPrecedentActive(p); + const showExtractHalachot = needsHalachaExtraction(p); const onDelete = async () => { if (active) { @@ -119,6 +136,15 @@ function CourtRow({ p, onEdit }: { p: Precedent; onEdit: (id: string) => void }) } }; + const onExtractHalachot = async () => { + try { + await reqHalachot.mutateAsync(p.id); + toast.success("סומן לחילוץ הלכות. הריצי מ-Claude Code: precedent_process_pending_halachot"); + } catch (e) { + toast.error(e instanceof Error ? e.message : "שגיאה"); + } + }; + return ( void }) className="text-ink-muted hover:text-navy"> + {showExtractHalachot && ( + + )} + {showExtractHalachot && ( + + )}