From 550faa911f889f70f6034ac838dec236566838b7 Mon Sep 17 00:00:00 2001 From: jiajia Date: Fri, 15 May 2026 15:14:48 +0800 Subject: [PATCH] Preserve collapsed composer action targets The collapsed composer should expand from the surrounding summary area, but the model label and generate button are explicit action targets. This keeps model selection and generation isolated while retaining one-click expansion from the remaining collapsed surface. Constraint: Red-marked collapsed controls have dedicated product actions Rejected: Treat the whole collapsed summary as one expand button | steals the model selector action Confidence: high Scope-risk: narrow Directive: Do not bind collapsed-container expansion over buttons with dedicated actions Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx Tested: npm run build Not-tested: npm run lint | existing script calls unsupported next lint under Next 16 Not-tested: npx tsc --noEmit | existing unrelated test type errors remain --- .../__tests__/GenerationComposer.test.tsx | 24 ++++++++++ .../composer/GenerationComposer.tsx | 47 +++++++++++++------ 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/components/__tests__/GenerationComposer.test.tsx b/src/components/__tests__/GenerationComposer.test.tsx index ce2edb0b..3fcb9463 100644 --- a/src/components/__tests__/GenerationComposer.test.tsx +++ b/src/components/__tests__/GenerationComposer.test.tsx @@ -332,6 +332,30 @@ describe("GenerationComposer", () => { expect(screen.getByDisplayValue("visible prompt")).toBeInTheDocument(); }); + it("opens model selection from the collapsed model label without expanding", () => { + useWorkflowStore.setState({ nodes: [imageNode("img-1", true, { inputPrompt: "visible prompt" })] }); + render(); + + fireEvent.click(screen.getByLabelText("Collapse composer")); + fireEvent.click(screen.getByLabelText("Select model")); + + expect(screen.getByTestId("model-dialog")).toHaveAttribute("data-filter", "image"); + expect(screen.queryByDisplayValue("visible prompt")).not.toBeInTheDocument(); + }); + + it("submits from the collapsed generate button without expanding", async () => { + useWorkflowStore.setState({ nodes: [imageNode("img-1", true, { inputPrompt: "visible prompt" })] }); + render(); + + fireEvent.click(screen.getByLabelText("Collapse composer")); + fireEvent.click(screen.getByLabelText("Generate")); + + await waitFor(() => { + expect(useWorkflowStore.getState().regenerateNode).toHaveBeenCalledWith("img-1"); + }); + expect(screen.queryByDisplayValue("visible prompt")).not.toBeInTheDocument(); + }); + it("uses the video model filter and reruns the selected video node", async () => { useWorkflowStore.setState({ nodes: [videoNode("vid-1", true)] }); render(); diff --git a/src/components/composer/GenerationComposer.tsx b/src/components/composer/GenerationComposer.tsx index f8f054f4..2cf192c8 100644 --- a/src/components/composer/GenerationComposer.tsx +++ b/src/components/composer/GenerationComposer.tsx @@ -985,31 +985,50 @@ export function GenerationComposer() { /> {isComposerCollapsed ? (
- {isProcessNode ? ( - {collapsedStatus} + ) : ( - canChooseModel && setModelDialogOpen(true)} + disabled={!canChooseModel} + aria-label={t("composer.selectModel")} + className="min-w-0 truncate rounded-md text-left text-sm text-neutral-100 transition-colors hover:text-cyan-200 disabled:text-neutral-500" + title={t("composer.selectModelTitle", { model: getComposerModelLabel(draft.selectedModel) })} > {getComposerModelLabel(draft.selectedModel)} - + )} {!isProcessNode && ( - + )} - +