fix: make footer sole workflow run control

This commit is contained in:
lda
2026-07-12 15:48:17 +07:00 Verified
parent ed2ee043bd
commit 1359a7f8e3
8 changed files with 9 additions and 59 deletions
@@ -64,8 +64,8 @@ const renderBeat = (
demo={demo}
selectedNodeId={null}
selectNode={noop}
openEvidence={openEvidence}
approvalActions={options.approvalActions}
openEvidence={openEvidence}
approvalActions={options.approvalActions}
/>,
);
return { ...rendered, openEvidence };
@@ -181,8 +181,7 @@ describe("OperatorChat", () => {
expect(screen.getByRole("button", { name: /presentation.selectWorkflowNode/i })).toBeInTheDocument();
});
it("shows a chat-owned run prepared workflow action", async () => {
const user = userEvent.setup();
it("does not render the run prepared workflow action", () => {
const runPreparedWorkflow = vi.fn(async () => {});
render(
@@ -200,8 +199,8 @@ describe("OperatorChat", () => {
/>,
);
await user.click(screen.getByRole("button", { name: /run prepared workflow/i }));
expect(runPreparedWorkflow).toHaveBeenCalledTimes(1);
expect(screen.queryByRole("button", { name: /run prepared workflow/i })).not.toBeInTheDocument();
expect(runPreparedWorkflow).not.toHaveBeenCalled();
});
it("routes schema approval submit and revision request through the timeline agent when present", async () => {
@@ -43,7 +43,6 @@ export const OperatorChat = ({ state, messages, timelineAgent, onApprove, onRequ
? () => { timelineAgent.requestRevision().catch(console.error); }
: onRequestRevision;
const composition = compositionForState(state);
const isScene8 = state.location.kind === "main" && state.location.sceneId === "agent-handoff";
const presentationSurface = composition.chatTheme === "light" ? "editorial" : "night";
return (
<aside
@@ -56,11 +55,6 @@ export const OperatorChat = ({ state, messages, timelineAgent, onApprove, onRequ
<AssistantOperatorThread
mode={composition.chatMode}
messages={visibleMessages}
runAction={timelineAgent && !isScene8 ? {
label: timelineAgent.runLabel,
disabled: !timelineAgent.canRun,
run: () => void timelineAgent.runPreparedWorkflow(),
} : undefined}
submitApproval={submit}
requestRevision={requestRevision}
/>
@@ -286,7 +286,7 @@ describe("PresentationRoute", () => {
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
expect(await screen.findAllByRole("button", { name: /run prepared workflow/i })).toHaveLength(2);
expect(await screen.findAllByRole("button", { name: /run prepared workflow/i })).toHaveLength(1);
});
it("owns the live run action in the footer rail", async () => {
@@ -13,7 +13,6 @@ type AuthoringConversationProps = {
readonly requestOverride?: string | undefined;
readonly requestOverrides?: Scene9SubmittedOverrides | undefined;
readonly scrollMode?: "active" | "start" | undefined;
readonly runAction?: { readonly label: string; readonly disabled: boolean; readonly run: () => void } | undefined;
};
/** Renders the same prepared conversation at full-stage or compact-dock scale. */
@@ -24,7 +23,6 @@ export const AuthoringConversation = ({
requestOverride,
requestOverrides,
scrollMode,
runAction,
}: AuthoringConversationProps) => (
<AssistantOperatorThread
mode={surface === "stage" ? "full" : "dock"}
@@ -33,6 +31,5 @@ export const AuthoringConversation = ({
activeToolGroupId={authoringToolGroupId(activePhase)}
scrollMode={scrollMode}
ariaLabel="prepared authoring conversation"
runAction={runAction}
/>
);
@@ -99,19 +99,10 @@ describe("AssistantOperatorThread", () => {
expect(requestRevision).toHaveBeenCalledOnce();
});
it("renders a chat-owned run action", async () => {
const user = userEvent.setup();
const run = vi.fn();
render(
<AssistantOperatorThread
mode="dock"
messages={[]}
runAction={{ label: "Run prepared workflow", disabled: false, run }}
/>,
);
it("does not render a run action", () => {
render(<AssistantOperatorThread mode="dock" messages={[]} />);
await user.click(screen.getByRole("button", { name: /run prepared workflow/i }));
expect(run).toHaveBeenCalledOnce();
expect(screen.queryByRole("button", { name: /run prepared workflow/i })).not.toBeInTheDocument();
});
it("labels and opens the synchronized authoring phase group", () => {
@@ -23,7 +23,6 @@ import {
type AssistantOperatorThreadProps = {
readonly mode: "hidden" | "full" | "rail" | "dock";
readonly messages: ReadonlyArray<AgentMessage>;
readonly runAction?: { readonly label: string; readonly disabled: boolean; readonly run: () => void } | undefined;
readonly scrollMode?: "active" | "start" | undefined;
readonly submitApproval?: (() => void) | undefined;
readonly requestRevision?: (() => void) | undefined;
@@ -250,7 +249,6 @@ const MessageBubble = ({
export const AssistantOperatorThread = ({
mode,
messages,
runAction,
scrollMode = "active",
submitApproval,
requestRevision,
@@ -304,11 +302,6 @@ export const AssistantOperatorThread = ({
});
}, []);
const handleRun = useCallback(() => {
if (!runAction || runAction.disabled) return;
runAction.run();
}, [runAction]);
return (
<section
className="assistant-operator-thread"
@@ -345,13 +338,6 @@ export const AssistantOperatorThread = ({
})}
</div>
</div>
{runAction ? (
<div className="assistant-operator-thread__action">
<button type="button" disabled={runAction.disabled} onClick={handleRun}>
{runAction.label}
</button>
</div>
) : null}
</section>
);
};
@@ -2505,16 +2505,6 @@
}
}
.assistant-operator-thread__action button {
width: 100%;
border: 1px solid var(--accent-cyan);
border-radius: 0.65rem;
background: color-mix(in oklch, var(--accent-cyan) 13%, var(--stage-surface));
color: var(--text-primary);
padding: 0.55rem 0.7rem;
font: 700 0.8rem/1 var(--font-interface);
}
.assistant-thread,
.assistant-thread__viewport {
min-height: 0;
@@ -3287,13 +3277,6 @@
color: var(--authoring-accent);
}
.agent-handoff-scene[data-presentation-surface="editorial"] .assistant-operator-thread__action button {
border-color: var(--authoring-accent);
border-radius: 0.2rem;
background: var(--authoring-accent);
color: var(--authoring-paper);
}
/* Keep the compact Scene 8 request surface centered inside the presentation canvas. */
@media (max-width: 1100px) {
.presentation-stage[data-scene-view="agent"] .presentation-stage__primary {