fix(frontend,harness): phase-stepper wiring, central tail, activity-panel markdown
- WorkflowBar: center the phase pills (add justify-center).
- tht-gate.js: the gate was sending the descriptive phase name (e.g.
"chiarimento") instead of the workflow.yaml id ("F1") in the widget's
`phase` field, so the frontend's F1..F8 match never hit and pills never
lit up. Rename phaseName -> phaseId, return p.id.
- CentralStatus: expand the live "working" tail from a single truncated
line to up to 5 lines (line-clamp-5 safety net for unbroken paragraphs).
- ModelActivityPanel: render the streamed tail through react-markdown +
remark-gfm instead of raw per-line <p> tags, so emphasis/headings render
and blank-line paragraph breaks (previously stripped) are preserved;
tail-cut now operates on paragraphs instead of physical lines.
Updated tests accordingly (WorkflowBar/CentralStatus/ModelActivityPanel/
AppShell.session-mgmt); full frontend suite (98/98) + harness gate node
tests (34/34) + tsc -b pass.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,12 @@ test("renders the streamed model transcript", () => {
|
||||
expect(screen.getByText(/Promoting table dim_patient/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("renders markdown emphasis instead of literal asterisks", () => {
|
||||
useSessionStore.getState().applyEvent({ type: "text_delta", text: "Chiarimento su **fibrillazione atriale**." });
|
||||
render(<ModelActivityPanel onClose={vi.fn()} />);
|
||||
expect(screen.getByText("fibrillazione atriale").tagName).toBe("STRONG");
|
||||
});
|
||||
|
||||
test("close button calls onClose", async () => {
|
||||
const onClose = vi.fn();
|
||||
render(<ModelActivityPanel onClose={onClose} />);
|
||||
@@ -19,20 +25,32 @@ test("close button calls onClose", async () => {
|
||||
expect(onClose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
const EIGHT = ["line-01", "line-02", "line-03", "line-04", "line-05", "line-06", "line-07", "line-08"].join("\n");
|
||||
const EIGHT = ["para-01", "para-02", "para-03", "para-04", "para-05", "para-06", "para-07", "para-08"].join("\n\n");
|
||||
|
||||
test("collapsed shows only the last 5 lines of the model-stream tail", () => {
|
||||
test("collapsed shows only the last 5 paragraphs of the model-stream tail", () => {
|
||||
useSessionStore.getState().applyEvent({ type: "text_delta", text: EIGHT });
|
||||
render(<ModelActivityPanel onClose={vi.fn()} />);
|
||||
expect(screen.getByText("line-08")).toBeInTheDocument();
|
||||
expect(screen.getByText("line-04")).toBeInTheDocument();
|
||||
expect(screen.queryByText("line-03")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("line-01")).not.toBeInTheDocument();
|
||||
expect(screen.getByText("para-08")).toBeInTheDocument();
|
||||
expect(screen.getByText("para-04")).toBeInTheDocument();
|
||||
expect(screen.queryByText("para-03")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("para-01")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("expanding reveals the full stream", async () => {
|
||||
useSessionStore.getState().applyEvent({ type: "text_delta", text: EIGHT });
|
||||
render(<ModelActivityPanel onClose={vi.fn()} />);
|
||||
await userEvent.click(screen.getByRole("button", { name: /show more/i }));
|
||||
expect(screen.getByText("line-01")).toBeInTheDocument();
|
||||
expect(screen.getByText("para-01")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("paragraphs stay separated as distinct blocks", () => {
|
||||
useSessionStore
|
||||
.getState()
|
||||
.applyEvent({ type: "text_delta", text: "Primo paragrafo.\n\nSecondo paragrafo." });
|
||||
render(<ModelActivityPanel onClose={vi.fn()} />);
|
||||
const first = screen.getByText("Primo paragrafo.");
|
||||
const second = screen.getByText("Secondo paragrafo.");
|
||||
expect(first.tagName).toBe("P");
|
||||
expect(second.tagName).toBe("P");
|
||||
expect(first).not.toBe(second);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user