feat(missing-precedents): חיפוש-טקסט לפי מראה-מקום בדף פסיקה-חסרה
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 5s
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 5s
הבעיה: בדף /missing-precedents לא ניתן היה לאתר פסיקה חסרה לפי מספר ההחלטה החסרה עצמה (למשל 85074). השדה היחיד לחיפוש-תיק עשה get_case_by_number על מספר ה-ערר שבו צוטטה הפסיקה — ולכן הקלדת מספר-הפסיקה החזירה רשימה ריקה, למרות שהרשומה קיימת (ערר (ת"א 85074-04-25) ... status=open). התיקון (הרחבת השדה הקיים, ללא עמוד/שדה חדש — בהנחיית חיים): - db.list_missing_precedents: פרמטר q חדש — ILIKE על mp.citation + mp.case_name + cited-in c.case_number (אינדקס-פרמטר יחיד, additive; שאר הקוראים לא נוגעים). - GET /api/missing-precedents: פרמטר q; case_id/case_number נשארים מסננים-מדויקים לקוראים תכנותיים. - web-ui: התווית "תיק (מספר ערר)" → "מספר תיק", placeholder "85074 או 1017-03-26"; השדה שולח q (חיפוש חופשי) במקום case_number. Debounce 350ms נשמר. api:types לא חודש: ה-hook בונה את ה-querystring ידנית וה-response לא השתנה; חידוש מול prod (שעוד לא נפרס) רק היה מושך drift לא-קשור. בדיקות: tsc --noEmit נקי, eslint נקי על הקבצים שהשתנו, py_compile נקי. Invariants: G2 (הרחבת היכולת הקיימת, לא מסלול-חיפוש מקביל), INV-IA1 (שער/דף יחיד לפסיקה-חסרה — בלי עמוד חדש), §6 (ללא בליעת-שגיאות). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,19 +31,19 @@ const STATUS_CHIPS: { value: StatusFilter; label: string }[] = [
|
||||
];
|
||||
|
||||
export default function MissingPrecedentsPage() {
|
||||
const [caseNumber, setCaseNumber] = useState("");
|
||||
const [search, setSearch] = useState("");
|
||||
const [legalTopic, setLegalTopic] = useState("");
|
||||
const [filter, setFilter] = useState<StatusFilter>("open");
|
||||
|
||||
/* Debounce the filters so the table fires one query after the user stops
|
||||
* typing — not one per keystroke. Each intermediate value used to
|
||||
* round-trip to the API (and a non-existent case number errored mid-typing). */
|
||||
const [caseNumberQ, setCaseNumberQ] = useState("");
|
||||
* typing — not one per keystroke. The search term matches the gap's own
|
||||
* מראה-מקום, case name, and cited-in appeal number (server-side ILIKE). */
|
||||
const [searchQ, setSearchQ] = useState("");
|
||||
const [legalTopicQ, setLegalTopicQ] = useState("");
|
||||
useEffect(() => {
|
||||
const t = setTimeout(() => setCaseNumberQ(caseNumber.trim()), 350);
|
||||
const t = setTimeout(() => setSearchQ(search.trim()), 350);
|
||||
return () => clearTimeout(t);
|
||||
}, [caseNumber]);
|
||||
}, [search]);
|
||||
useEffect(() => {
|
||||
const t = setTimeout(() => setLegalTopicQ(legalTopic.trim()), 350);
|
||||
return () => clearTimeout(t);
|
||||
@@ -87,11 +87,11 @@ export default function MissingPrecedentsPage() {
|
||||
{/* shared filters */}
|
||||
<div className="flex items-end gap-3 flex-wrap">
|
||||
<div className="flex-1 min-w-[200px]">
|
||||
<label className="block text-[0.78rem] text-ink-muted mb-1.5">תיק (מספר ערר)</label>
|
||||
<label className="block text-[0.78rem] text-ink-muted mb-1.5">מספר תיק</label>
|
||||
<Input
|
||||
value={caseNumber}
|
||||
onChange={(e) => setCaseNumber(e.target.value)}
|
||||
placeholder="1017-03-26"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder="85074 או 1017-03-26"
|
||||
dir="rtl"
|
||||
/>
|
||||
</div>
|
||||
@@ -137,7 +137,7 @@ export default function MissingPrecedentsPage() {
|
||||
|
||||
<MissingPrecedentsTable
|
||||
status={filter === "all" ? "" : filter}
|
||||
caseNumber={caseNumberQ || undefined}
|
||||
q={searchQ || undefined}
|
||||
legalTopic={legalTopicQ || undefined}
|
||||
/>
|
||||
|
||||
|
||||
@@ -81,15 +81,15 @@ function TableSkeleton({ cols }: { cols: number }) {
|
||||
|
||||
type Props = {
|
||||
status?: MissingPrecedentStatus | "";
|
||||
caseNumber?: string;
|
||||
q?: string;
|
||||
legalTopic?: string;
|
||||
};
|
||||
|
||||
export function MissingPrecedentsTable({ status, caseNumber, legalTopic }: Props) {
|
||||
export function MissingPrecedentsTable({ status, q, legalTopic }: Props) {
|
||||
const [openId, setOpenId] = useState<string | null>(null);
|
||||
const { data, isPending, error } = useMissingPrecedents({
|
||||
status: status === "" ? undefined : status,
|
||||
caseNumber,
|
||||
q,
|
||||
legalTopic,
|
||||
limit: 200,
|
||||
});
|
||||
|
||||
@@ -91,6 +91,9 @@ export type MissingPrecedentFilters = {
|
||||
caseNumber?: string;
|
||||
caseId?: string;
|
||||
legalTopic?: string;
|
||||
/** Free-text term — matched across the gap's מראה-מקום, case name, and
|
||||
* cited-in appeal number (find a gap by the missing decision's number). */
|
||||
q?: string;
|
||||
limit?: number;
|
||||
};
|
||||
|
||||
@@ -110,6 +113,7 @@ export function useMissingPrecedents(filters: MissingPrecedentFilters = {}) {
|
||||
if (filters.caseNumber) p.set("case_number", filters.caseNumber);
|
||||
if (filters.caseId) p.set("case_id", filters.caseId);
|
||||
if (filters.legalTopic) p.set("legal_topic", filters.legalTopic);
|
||||
if (filters.q) p.set("q", filters.q);
|
||||
if (filters.limit) p.set("limit", String(filters.limit));
|
||||
const qs = p.toString();
|
||||
return apiRequest<MissingPrecedentListResponse>(
|
||||
|
||||
Reference in New Issue
Block a user