feat(ui): פאנל אישור-תכניות — טאב /precedents + מרכז-אישורים (PR-B)
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 4s
Lint — undefined names / undefined-names (pull_request) Successful in 9s

הטמעת ה-UI למרשם-התכניות אחרי אישור-עיצוב ב-Claude Design (מוקאפ 22-plans-review).
- web-ui/src/lib/api/plans.ts: hooks (usePlansPending, usePlanDuplicates,
  useUpsertPlan, useUpdatePlan, useReviewPlan, useMergePlans) + טיפוס Plan מקומי.
- plans-review-panel.tsx: כרטיס-תכנית עם משפט-הציטוט הקנוני (כפי שייכתב בבלוק ט),
  שדות-תוקף, סימון חוסר-תאריך, באנר "כפילות אפשרית → מזג לכאן" (find_similar_plans,
  מיזוג ידני — G10), עריכה/הוספה inline עם תצוגה-מקדימה חיה של הציטוט.
- precedents/page.tsx: טאב "תכניות" + PlansPendingPill + deep-link tab=plans.
- web/app.py: href קטגוריית-התכניות במרכז-האישורים → /precedents?tab=plans.
- api:types: types.ts מחודש מ-openapi החי (5 נתיבי /api/plans).

מרכז-האישורים (/approvals) מרנדר קטגוריות גנרית — קטגוריית-התכניות (PR-A) מופיעה
אוטומטית. אימות: api:types ✓, tsc --noEmit ✓, lint exit=0 (ללא אזהרות חדשות).

Invariants: G10 (אישור אנושי + מיזוג ידני) · INV-AH (ציטוט דטרמיניסטי, תצוגה-מקדימה
תואמת format_plan_citation) · INV-IA (שער-אחד: טאב קיים + מרכז-אישורים, ללא עמוד חדש) ·
X6 (UI↔API, apiRequest + טיפוסים). עבר שער-העיצוב Claude Design (feedback_claude_design_gate).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-14 15:27:36 +00:00
parent 70ac888592
commit 5d75d36e2a
5 changed files with 1025 additions and 5 deletions

View File

@@ -7,8 +7,10 @@ import { AppShell } from "@/components/app-shell";
import { LibraryListPanel } from "@/components/precedents/library-list-panel";
import { LibrarySearchPanel } from "@/components/precedents/library-search-panel";
import { HalachaReviewPanel } from "@/components/precedents/halacha-review-panel";
import { PlansReviewPanel } from "@/components/precedents/plans-review-panel";
import { LibraryStatsPanel } from "@/components/precedents/library-stats-panel";
import { useHalachotPending } from "@/lib/api/precedent-library";
import { usePlansPending } from "@/lib/api/plans";
import { useMissingPrecedents } from "@/lib/api/missing-precedents";
/**
@@ -47,13 +49,18 @@ function PendingPill() {
return <CountPill n={data?.count ?? 0} tone="warn" />;
}
function PlansPendingPill() {
const { data } = usePlansPending();
return <CountPill n={data?.count ?? 0} tone="warn" />;
}
function IncomingPill() {
// "פסיקה נכנסת" = open missing-precedents waiting for the chair to upload.
const { data } = useMissingPrecedents({ status: "open", limit: 1 });
return <CountPill n={data?.by_status?.open ?? 0} tone="info" />;
}
const PRECEDENT_TABS = new Set(["library", "search", "review", "incoming", "stats"]);
const PRECEDENT_TABS = new Set(["library", "search", "review", "plans", "incoming", "stats"]);
export default function PrecedentsPage() {
// Controlled so a deep link like /precedents?tab=review (e.g. from a pending
@@ -92,6 +99,7 @@ export default function PrecedentsPage() {
{ value: "library", label: "ספרייה", pill: null },
{ value: "search", label: "חיפוש בקורפוס", pill: null },
{ value: "review", label: "תור הלכות", pill: <PendingPill /> },
{ value: "plans", label: "תכניות", pill: <PlansPendingPill /> },
{
value: "incoming",
label: "פסיקה נכנסת",
@@ -123,6 +131,10 @@ export default function PrecedentsPage() {
<HalachaReviewPanel />
</TabsContent>
<TabsContent value="plans" className="mt-0">
<PlansReviewPanel />
</TabsContent>
{/* "פסיקה נכנסת" — the incoming/missing-precedent queue. Kept as a
tab per the mockup; full management lives on /missing-precedents. */}
<TabsContent value="incoming" className="mt-0">