feat(precedent-library): add halacha-extract button to library list rows
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m8s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m8s
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.
This commit is contained in:
@@ -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 (
|
||||
<Badge
|
||||
@@ -103,7 +118,9 @@ function StatusPill({ p }: { p: Precedent }) {
|
||||
|
||||
function CourtRow({ p, onEdit }: { p: Precedent; onEdit: (id: string) => 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 (
|
||||
<TableRow className="border-rule hover:bg-gold-wash/30 align-top">
|
||||
<TableCell
|
||||
@@ -150,6 +176,15 @@ function CourtRow({ p, onEdit }: { p: Precedent; onEdit: (id: string) => void })
|
||||
className="text-ink-muted hover:text-navy">
|
||||
<Pencil className="w-4 h-4" />
|
||||
</Button>
|
||||
{showExtractHalachot && (
|
||||
<Button variant="ghost" size="sm" onClick={onExtractHalachot}
|
||||
disabled={reqHalachot.isPending}
|
||||
aria-label={`חלץ הלכות מ-${p.case_number}`}
|
||||
title="חלץ הלכות"
|
||||
className="text-gold-deep hover:text-gold-deep hover:bg-gold-wash disabled:opacity-30">
|
||||
<Wand2 className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="ghost" size="sm" onClick={onDelete}
|
||||
disabled={del.isPending || active}
|
||||
aria-label={`מחק את ${p.case_number}`}
|
||||
@@ -165,7 +200,9 @@ function CourtRow({ p, onEdit }: { p: Precedent; onEdit: (id: string) => void })
|
||||
|
||||
function CommitteeRow({ p, onEdit }: { p: Precedent; onEdit: (id: string) => void }) {
|
||||
const del = useDeletePrecedent();
|
||||
const reqHalachot = useRequestHalachotExtraction();
|
||||
const active = isPrecedentActive(p);
|
||||
const showExtractHalachot = needsHalachaExtraction(p);
|
||||
|
||||
const onDelete = async () => {
|
||||
if (active) {
|
||||
@@ -181,6 +218,15 @@ function CommitteeRow({ p, onEdit }: { p: Precedent; onEdit: (id: string) => voi
|
||||
}
|
||||
};
|
||||
|
||||
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 (
|
||||
<TableRow className="border-rule hover:bg-gold-wash/30 align-top">
|
||||
<TableCell
|
||||
@@ -214,6 +260,15 @@ function CommitteeRow({ p, onEdit }: { p: Precedent; onEdit: (id: string) => voi
|
||||
className="text-ink-muted hover:text-navy">
|
||||
<Pencil className="w-4 h-4" />
|
||||
</Button>
|
||||
{showExtractHalachot && (
|
||||
<Button variant="ghost" size="sm" onClick={onExtractHalachot}
|
||||
disabled={reqHalachot.isPending}
|
||||
aria-label={`חלץ הלכות מ-${p.case_number}`}
|
||||
title="חלץ הלכות"
|
||||
className="text-gold-deep hover:text-gold-deep hover:bg-gold-wash disabled:opacity-30">
|
||||
<Wand2 className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="ghost" size="sm" onClick={onDelete}
|
||||
disabled={del.isPending || active}
|
||||
aria-label={`מחק את ${p.case_number}`}
|
||||
|
||||
Reference in New Issue
Block a user