Merge pull request 'fix(status): render pipeline phase for legacy statuses (analyst_verified)' (#371) from worktree-status-legacy-phase-fix into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 42s
G12 Leak-Guard / leak-guard (push) Successful in 4s
Lint — undefined names / undefined-names (push) Successful in 10s

This commit was merged in pull request #371.
This commit is contained in:
2026-06-30 18:31:57 +00:00
3 changed files with 34 additions and 14 deletions

View File

@@ -1,6 +1,6 @@
"use client";
import { PHASES, type CaseStatus } from "@/lib/api/case-status";
import { PHASES, phaseIndexOf, type CaseStatus } from "@/lib/api/case-status";
import { statusLabel } from "@/lib/api/case-status";
import { StatusChanger } from "@/components/cases/status-changer";
import { StatusGuide } from "@/components/cases/status-guide";
@@ -22,11 +22,6 @@ const EXPECTED_OUTCOME_LABELS: Record<string, string> = Object.fromEntries(
expectedOutcomes.map((o) => [o.value, o.label]),
);
function phaseIndexOf(status?: CaseStatus): number {
if (!status) return -1;
return PHASES.findIndex((p) => p.statuses.includes(status));
}
/** Horizontal RTL stepper over the 5 lifecycle phases (mockup 18b .stepper). */
function HorizontalStepper({ status }: { status?: CaseStatus }) {
const currentIdx = phaseIndexOf(status);

View File

@@ -1,6 +1,6 @@
"use client";
import { PHASES, type CaseStatus, type PhaseKey } from "@/lib/api/case-status";
import { PHASES, phaseIndexOf, type CaseStatus, type PhaseKey } from "@/lib/api/case-status";
import { STATUS_LABELS, STATUS_ICONS, STATUS_DESCRIPTIONS } from "@/components/cases/status-badge";
import {
FolderInput, ClipboardList, Brain, PenLine, CheckCircle2,
@@ -21,11 +21,6 @@ const PHASE_ICONS: Record<PhaseKey, LucideIcon> = {
done: CheckCircle2,
};
function phaseIndexOf(status?: CaseStatus): number {
if (!status) return -1;
return PHASES.findIndex((p) => p.statuses.includes(status));
}
export function WorkflowTimeline({ status }: { status?: CaseStatus }) {
const currentIdx = phaseIndexOf(status);

View File

@@ -40,10 +40,40 @@ export const PHASES: { key: PhaseKey; label: string; statuses: CaseStatus[] }[]
{ key: "done", label: "סגירה", statuses: ["exported", "reviewed", "final"] },
];
/** Which phase a status belongs to (undefined for unknown/legacy values). */
/**
* Legacy/intermediate statuses that the trimmed PHASES list dropped but the
* Paperclip agents still set (e.g. the analyst writes `analyst_verified`, the
* researcher writes `research_complete`). Without this map a case parked on one
* of them renders with NO active phase — the pipeline stepper goes blank and the
* chair can't see where the case stands. Map each to the phase it belongs to for
* display purposes only (these are NOT selectable statuses).
*/
const LEGACY_STATUS_PHASE: Record<string, PhaseKey> = {
analyst_verified: "thinking",
research_complete: "thinking",
analysis_enriched: "thinking",
ready_for_writing: "writing",
drafting: "writing",
in_progress: "thinking",
};
/** Which phase a status belongs to (undefined only for truly unknown values). */
export function phaseOf(status?: CaseStatus | string): PhaseKey | undefined {
if (!status) return undefined;
return PHASES.find((p) => (p.statuses as string[]).includes(status))?.key;
return (
PHASES.find((p) => (p.statuses as string[]).includes(status))?.key ??
LEGACY_STATUS_PHASE[status]
);
}
/**
* Index of a status within the 5-phase pipeline (1 only for unknown values).
* Single source of truth for the stepper — handles legacy statuses via phaseOf,
* so a case on `analyst_verified` lands on "ניתוח וכיוון" instead of blank.
*/
export function phaseIndexOf(status?: CaseStatus | string): number {
const key = phaseOf(status);
return key ? PHASES.findIndex((p) => p.key === key) : -1;
}
export const STATUS_LABELS: Record<CaseStatus, string> = {