Files
Jyotisha/frontend/src/components/rectification-question-gap-notices.tsx
T
jesse-uxandGrok (agent loop) 56a3c08145 显示生时校正里还活着的时间段,不再把空档涂进目前范围。
交付卡、旁白和遥测在有簇区间时按段书写。打分、出题和进区间门槛未改;对半出题和门槛 6 因为没有真值保留回放而没有交付。

Co-Authored-By: Grok (agent loop)
2026-10-17 03:07:25 +08:00

155 lines
5.8 KiB
TypeScript

"use client";
import {
RECTIFICATION_DELIVERED_COPY,
RECTIFICATION_QUESTION_PREPARING_LABEL,
RECTIFICATION_QUESTION_RELOAD_LABEL,
RECTIFICATION_QUESTION_REPAIR_FAILED_COPY,
RECTIFICATION_QUESTION_REPAIR_LIMIT,
RECTIFICATION_QUESTION_UNAVAILABLE_COPY,
RECTIFICATION_SNAPSHOT_RETRY_LABEL,
RECTIFICATION_SNAPSHOT_UNAVAILABLE_COPY,
persistedQuestionSurface,
rectificationReadonlyRangeCopy,
type RectificationSnapshotFailure,
} from "@/lib/rectification-surface-state";
import type { ChoiceKey, RectificationChoiceCard as ChoiceCardModel } from "@/lib/rectification-agentic/v9/choice-card";
import type { CurrentQuestionModel } from "@/lib/rectification-chat-snapshot";
import type { RectificationChatView } from "@/lib/rectification-chat-view";
import { Button } from "@/components/ui/button";
import { ConsultationTimelineLiveRow } from "./consultation-run-timeline";
import { RectificationChoiceCard } from "./rectification-choice-card";
export function RectificationReadonlyRange({
range,
displayLabel,
sessionOutcome,
discriminatingEventProbes,
contrastProbes,
}: Readonly<{
range: readonly [string, string];
displayLabel?: string | null;
sessionOutcome: string | null;
discriminatingEventProbes: unknown;
contrastProbes: unknown;
}>) {
return (
<p className="rectification-readonly-range" role="status">
{rectificationReadonlyRangeCopy({
range,
displayLabel,
sessionOutcome,
discriminatingEventProbes,
contrastProbes,
})}
</p>
);
}
/**
* The blocks under the transcript that stand in for a missing next question:
* the standalone persisted question (only when no assistant message can carry
* it), the preparing row, the delivered note, the snapshot-failure retry, the
* repair button, and the verified-idle note. Moved out of
* RectificationAgenticChat unchanged (TASK-rectification-code-split-20260926).
*/
export function RectificationQuestionGapNotices({
view,
currentQuestion,
choiceCard,
choiceNonce,
busy,
readonly,
snapshotFailure,
questionRepairAttempts,
questionRepairing,
submitChoice,
submitStop,
refetchQuestion,
repairQuestion,
}: Readonly<{
view: Pick<RectificationChatView, "showStandaloneQuestion" | "questionGap" | "showSelectionCards" | "verifiedIdleCopy">;
currentQuestion: CurrentQuestionModel | null;
choiceCard: ChoiceCardModel | null;
choiceNonce: number;
busy: boolean;
readonly: boolean;
snapshotFailure: RectificationSnapshotFailure | null;
questionRepairAttempts: number;
questionRepairing: boolean;
submitChoice: (key: ChoiceKey) => void;
submitStop: () => void;
refetchQuestion: () => Promise<void>;
repairQuestion: () => Promise<void>;
}>) {
const { showStandaloneQuestion, questionGap, showSelectionCards, verifiedIdleCopy } = view;
return (
<>
{showStandaloneQuestion && currentQuestion?.prompt && (
<div className="rectification-message-wrap rectification-message-entry" data-testid="persisted-question">
<div className="rectification-message-question is-standalone">
{persistedQuestionSurface({
questionKind: currentQuestion.kind,
hasChoiceCard: Boolean(choiceCard),
questionPersisted: true,
}) === "choice_card" && choiceCard ? (
<>
<p className="rectification-message-question__prompt">{currentQuestion.prompt}</p>
<RectificationChoiceCard
key={`${choiceCard.question_id}:${choiceNonce}:persisted`}
variant="embedded"
card={choiceCard}
pending={busy}
disabled={busy || readonly}
selectedKey=""
onSelect={submitChoice}
onStop={submitStop}
/>
</>
) : (
<p className="rectification-message-question__prompt">{currentQuestion.prompt}</p>
)}
</div>
</div>
)}
{questionGap === "preparing" && (
<div className="rectification-message-wrap rectification-message-entry rectification-question-gap">
<ConsultationTimelineLiveRow id="question-preparing" label={RECTIFICATION_QUESTION_PREPARING_LABEL} />
</div>
)}
{questionGap === "delivered" && !showSelectionCards && (
<p className="rectification-pending-note" role="status">
{RECTIFICATION_DELIVERED_COPY}
</p>
)}
{snapshotFailure && (
<div className="rectification-message-wrap rectification-message-entry rectification-question-gap" role="status">
<p className="rectification-question-gap__copy">{RECTIFICATION_SNAPSHOT_UNAVAILABLE_COPY}</p>
<Button type="button" variant="outline" onClick={() => void refetchQuestion()}>
{RECTIFICATION_SNAPSHOT_RETRY_LABEL}
</Button>
</div>
)}
{questionGap === "unavailable" && !snapshotFailure && (
<div className="rectification-message-wrap rectification-message-entry rectification-question-gap" role="status">
{questionRepairAttempts >= RECTIFICATION_QUESTION_REPAIR_LIMIT ? (
<p className="rectification-question-gap__copy">{RECTIFICATION_QUESTION_REPAIR_FAILED_COPY}</p>
) : (
<>
<p className="rectification-question-gap__copy">{RECTIFICATION_QUESTION_UNAVAILABLE_COPY}</p>
<Button type="button" variant="outline" onClick={() => void repairQuestion()} disabled={questionRepairing}>
{RECTIFICATION_QUESTION_RELOAD_LABEL}
</Button>
</>
)}
</div>
)}
{questionGap === "verified_idle" && verifiedIdleCopy && !showSelectionCards && (
<p className="rectification-pending-note" role="status">
{verifiedIdleCopy}
</p>
)}
</>
);
}