Merge pull request 'refactor(positions): קיפול "עמדות וטענות", איזון שורה תחתונה, שם-כרטיס מדויק (#226)' (#397) from worktree-positions-collapse-balance into main
This commit was merged in pull request #397.
This commit is contained in:
@@ -157,11 +157,28 @@ export default function CaseDetailPage({
|
||||
issues, with the aggregated by-party arguments collapsible below
|
||||
(merged from the deleted /compose editor, mockup 18f). */}
|
||||
<TabsContent value="arguments" className="mt-0 space-y-4">
|
||||
<Card className="bg-surface border-rule shadow-sm">
|
||||
<CardContent className="px-6 py-5">
|
||||
<PositionsPanel caseNumber={caseNumber} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
{/* עמדות וטענות — collapsed by default (chair preference #226),
|
||||
mirroring the two accordions below. */}
|
||||
<Accordion type="single" collapsible>
|
||||
<AccordionItem
|
||||
value="positions"
|
||||
className="overflow-hidden rounded-xl border border-rule bg-surface shadow-sm"
|
||||
>
|
||||
<AccordionTrigger className="px-6 py-4 hover:no-underline">
|
||||
<span className="flex flex-1 flex-col items-start">
|
||||
<span className="text-navy text-[0.95rem] font-bold">
|
||||
עמדות וטענות
|
||||
</span>
|
||||
<span className="text-ink-muted text-[0.78rem]">
|
||||
סוגיות-המחלוקת ועמדות הצדדים · עורך עמדת-היו״ר מזין את בלוק י׳
|
||||
</span>
|
||||
</span>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="px-6 pb-5 pt-0">
|
||||
<PositionsPanel caseNumber={caseNumber} />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
<Accordion type="single" collapsible>
|
||||
<AccordionItem
|
||||
value="byparty"
|
||||
|
||||
@@ -8,10 +8,6 @@ import { SubsectionCard } from "@/components/compose/subsection-card";
|
||||
import { PrecedentsSection } from "@/components/compose/precedents-section";
|
||||
import { Markdown } from "@/components/ui/markdown";
|
||||
import { useCase } from "@/lib/api/cases";
|
||||
import {
|
||||
useCaseLearningStatus,
|
||||
type CaseLearningStatus,
|
||||
} from "@/lib/api/learning";
|
||||
import { useResearchAnalysis } from "@/lib/api/research";
|
||||
import { useCasePrecedents } from "@/lib/api/precedents";
|
||||
|
||||
@@ -24,45 +20,6 @@ import { useCasePrecedents } from "@/lib/api/precedents";
|
||||
* verification moved to their own top-level tabs; /compose was deleted.
|
||||
*/
|
||||
|
||||
// ── Staged-pipeline indicator text — derived from the live learning-status,
|
||||
// same source as the drafts-panel LearningStatusBadges. ──────────────────────
|
||||
function voiceLearningText(s?: CaseLearningStatus): string {
|
||||
if (!s?.final_uploaded) return "ממתין להעלאת הסופי";
|
||||
const v = s.voice_learning;
|
||||
if (v.outcome === "succeeded") {
|
||||
const bits = [`${v.lessons_count} לקחים הופקו`];
|
||||
if (v.lessons_proposed > 0) bits.push(`${v.lessons_proposed} הוצעו לאישור`);
|
||||
return `✓ הושלם · ${bits.join(" · ")}`;
|
||||
}
|
||||
if (v.outcome === "failed") return v.error ? `✗ נכשל — ${v.error}` : "✗ נכשל";
|
||||
return "ממתין להרצה";
|
||||
}
|
||||
|
||||
function halachaExtractionText(s?: CaseLearningStatus): string {
|
||||
if (!s?.final_uploaded) return "ממתין להעלאת הסופי";
|
||||
const h = s.halacha_extraction;
|
||||
if (!h.enrolled_in_corpus)
|
||||
return h.not_enrolled_reason ?? "לא נכנס לקורפוס-הפסיקה";
|
||||
switch (h.status) {
|
||||
case "completed":
|
||||
return `✓ הושלם · חולצו ${h.halachot_count} · ${h.approved} אושרו · ${h.rejected} נדחו`;
|
||||
case "processing":
|
||||
return "רץ עכשיו…";
|
||||
case "pending":
|
||||
case "busy":
|
||||
return "בתור";
|
||||
case "partial":
|
||||
return `חלקי · חולצו ${h.halachot_count}`;
|
||||
case "failed":
|
||||
case "extraction_failed":
|
||||
return "✗ נכשל";
|
||||
case "no_chunks":
|
||||
return "אין טקסט לחילוץ";
|
||||
default:
|
||||
return "ממתין להרצה";
|
||||
}
|
||||
}
|
||||
|
||||
function ProseSection({ title, content }: { title: string; content?: string }) {
|
||||
if (!content?.trim()) return null;
|
||||
return (
|
||||
@@ -75,7 +32,9 @@ function ProseSection({ title, content }: { title: string; content?: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
// ── "השלמה והעברה" rail card — DOCX export, analysis upload/download (real) ──
|
||||
// ── "ייצוא ועדכון הניתוח" rail card — round-trips the analysis-and-research.md
|
||||
// research analysis: export DOCX, upload an updated version, download the raw MD.
|
||||
// (Post-final learning status lives on the drafts tab, not here — #226.) ──────
|
||||
function FinishRail({
|
||||
caseNumber,
|
||||
hasAnalysis,
|
||||
@@ -88,7 +47,6 @@ function FinishRail({
|
||||
const fileRef = useRef<HTMLInputElement>(null);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const [uploadMsg, setUploadMsg] = useState<{ ok: boolean; text: string } | null>(null);
|
||||
const learning = useCaseLearningStatus(caseNumber);
|
||||
|
||||
async function handleUpload(file: File) {
|
||||
setUploading(true);
|
||||
@@ -119,9 +77,12 @@ function FinishRail({
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="bg-surface border-rule shadow-sm">
|
||||
<Card className="bg-surface border-rule shadow-sm h-full">
|
||||
<CardContent className="px-4 py-4">
|
||||
<h3 className="text-navy text-[0.9rem] font-semibold mb-3">השלמה והעברה</h3>
|
||||
<h3 className="text-navy text-[0.9rem] font-semibold mb-1">ייצוא ועדכון הניתוח</h3>
|
||||
<p className="text-[0.72rem] text-ink-muted mb-3">
|
||||
פעולות על קובץ ניתוח-המחקר (analysis-and-research.md).
|
||||
</p>
|
||||
|
||||
<input
|
||||
ref={fileRef}
|
||||
@@ -176,16 +137,6 @@ function FinishRail({
|
||||
{uploadMsg.text}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* stage indicators — informational pointers, not actions */}
|
||||
<div className="mt-3 space-y-0">
|
||||
<div className="text-[0.78rem] text-ink-muted pt-2 border-t border-rule-soft">
|
||||
<b className="text-navy">הרץ למידת-קול</b> — {voiceLearningText(learning.data)}
|
||||
</div>
|
||||
<div className="text-[0.78rem] text-ink-muted pt-2 mt-2 border-t border-rule-soft">
|
||||
<b className="text-navy">הרץ אימות-הלכות</b> — {halachaExtractionText(learning.data)}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
@@ -214,10 +165,6 @@ export function PositionsPanel({ caseNumber }: { caseNumber: string }) {
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<p className="text-ink-muted text-[0.78rem]">
|
||||
סוגיות-המחלוקת ועמדות הצדדים. עורך עמדת-היו״ר נשמר אוטומטית ומזין את בלוק י׳ (דיון והכרעה).
|
||||
</p>
|
||||
|
||||
{analysis.isPending ? (
|
||||
<Card className="bg-surface border-rule shadow-sm">
|
||||
<CardContent className="px-6 py-5 space-y-3">
|
||||
@@ -322,9 +269,10 @@ export function PositionsPanel({ caseNumber }: { caseNumber: string }) {
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{/* case-level פסיקה מצורפת + finish/export gates (INV-IA3: not removed) */}
|
||||
<div className="grid gap-4 lg:grid-cols-2 items-start pt-2">
|
||||
<Card className="bg-surface border-rule shadow-sm">
|
||||
{/* case-level פסיקה מצורפת + analysis export/update (INV-IA3: not removed).
|
||||
items-stretch keeps both cards the same height (#226). */}
|
||||
<div className="grid gap-4 lg:grid-cols-2 items-stretch pt-2">
|
||||
<Card className="bg-surface border-rule shadow-sm h-full">
|
||||
<CardContent className="px-5 py-4">
|
||||
<h3 className="text-navy text-[0.9rem] font-semibold mb-1">פסיקה מצורפת</h3>
|
||||
<p className="text-[0.72rem] text-ink-muted mb-3">
|
||||
|
||||
Reference in New Issue
Block a user