docs: define console product design contract

This commit is contained in:
lda
2026-07-03 07:12:52 +07:00 Verified
parent 241897eaa3
commit 47ac422965
8 changed files with 419 additions and 7 deletions
@@ -19,8 +19,8 @@ export const NodeSpotlight = ({ nodeId, close }: NodeSpotlightProps) => {
const node = presentationNodes.find((candidate) => candidate.id === nodeId);
if (!node) return null;
return (
<aside className="node-spotlight" role="dialog" aria-modal="true" aria-label={node.label}>
return (
<aside className="node-spotlight" role="dialog" aria-modal="true" aria-label={node.label}>
<button type="button" onClick={close}>Close</button>
<p>NodeUse</p>
<h2>{node.label}</h2>
@@ -45,4 +45,14 @@ describe("PresentationRoute", () => {
expect(await screen.findByText(/workflow.runs.start/i)).toBeInTheDocument();
});
it("shows resume and trace operation blocks for later beats", async () => {
render(<PresentationRoute />);
await userEvent.click(screen.getByRole("button", { name: /resume output/i }));
expect(await screen.findByText(/workflow.runs.resume/i)).toBeInTheDocument();
await userEvent.click(screen.getByRole("button", { name: /trace evidence/i }));
expect(await screen.findByText(/workflow.runs.trace/i)).toBeInTheDocument();
});
});
@@ -9,6 +9,7 @@ import { StageCaption } from "./StageCaption.js";
import { WorkflowGraphStage } from "./WorkflowGraphStage.js";
import type { PresentationState } from "./presentation-state.js";
import type { DemoTimelineController } from "../demo/useDemoTimeline.js";
import type { DemoEventStage } from "../demo/timeline/models.js";
type PresentationStageProps = {
readonly state: PresentationState;
@@ -21,6 +22,13 @@ type PresentationStageProps = {
readonly closeOverlay: () => void;
};
const operationStageByBeat: Partial<Record<BeatId, DemoEventStage>> = {
"tool-call-start": "run_start",
"interrupt-approval": "interrupt",
"resume-output": "run_resume",
"trace-evidence": "trace_read",
};
export const PresentationStage = ({
state,
demo,
@@ -32,11 +40,11 @@ export const PresentationStage = ({
closeOverlay,
}: PresentationStageProps) => {
const beat = presentationBeats.find((candidate) => candidate.id === state.beat) ?? presentationBeats[0]!;
const operationStage = operationStageByBeat[state.beat] ?? null;
const operationEvent =
demo.state.events.find((event) => event.stage === "run_start") ??
demo.state.events.find((event) => event.operation !== null) ??
null;
const operationEvent = operationStage
? demo.state.events.find((event) => event.stage === operationStage) ?? null
: null;
return (
<div className="presentation-stage" data-beat={state.beat}>