From a445d062270e67dcb101c433e0aa667b3333951f Mon Sep 17 00:00:00 2001 From: jiajia Date: Mon, 11 May 2026 16:39:55 +0800 Subject: [PATCH] Show reference images in input order The generation composer previously collapsed multiple reference images into a single thumbnail with a count badge. The composer now renders each reference thumbnail in sequence, keeps them scrollable in the toolbar, and lets editable drafts remove a specific image by position. Constraint: Reference image ordering matters for multi-image generation context. Rejected: Keep count badge overlay | it hides which images are attached and makes order ambiguous. Confidence: high Scope-risk: narrow Tested: npm test -- --run src/components/__tests__/GenerationComposer.test.tsx Tested: npx tsc --noEmit --pretty false filtered to GenerationComposer files Not-tested: Full tsc remains blocked by existing unrelated test typing errors --- .../__tests__/GenerationComposer.test.tsx | 26 ++++++++++++- .../composer/GenerationComposer.tsx | 38 +++++++++++-------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/components/__tests__/GenerationComposer.test.tsx b/src/components/__tests__/GenerationComposer.test.tsx index 4853919d..8fd0ca28 100644 --- a/src/components/__tests__/GenerationComposer.test.tsx +++ b/src/components/__tests__/GenerationComposer.test.tsx @@ -447,7 +447,7 @@ describe("GenerationComposer", () => { }); await waitFor(() => { - expect(screen.getByLabelText("移除参考图片")).toBeInTheDocument(); + expect(screen.getByLabelText("移除参考图片 1")).toBeInTheDocument(); }); fireEvent.change(screen.getByPlaceholderText(/描述你想生成的内容/), { @@ -465,6 +465,30 @@ describe("GenerationComposer", () => { expect((nodes[0].data as NanoBananaNodeData).inputImages[0]).toMatch(/^data:image\/png;base64,/); }); + it("renders uploaded reference images in order instead of stacking them", async () => { + render(); + + const firstImage = new File(["first-reference"], "first.png", { type: "image/png" }); + const secondImage = new File(["second-reference"], "second.png", { type: "image/png" }); + fireEvent.change(screen.getByLabelText("上传参考图片"), { + target: { files: [firstImage, secondImage] }, + }); + + await waitFor(() => { + expect(screen.getByTitle("参考图片 1")).toBeInTheDocument(); + expect(screen.getByTitle("参考图片 2")).toBeInTheDocument(); + }); + + const removeButtons = screen.getAllByLabelText(/移除参考图片/); + expect(removeButtons).toHaveLength(2); + + fireEvent.click(screen.getByLabelText("移除参考图片 1")); + await waitFor(() => { + expect(screen.queryByTitle("参考图片 2")).not.toBeInTheDocument(); + expect(screen.getByTitle("参考图片 1")).toBeInTheDocument(); + }); + }); + it("keeps upstream text authoritative without overwriting the local fallback prompt", async () => { useWorkflowStore.setState({ nodes: [ diff --git a/src/components/composer/GenerationComposer.tsx b/src/components/composer/GenerationComposer.tsx index 21646084..80ed2b8d 100644 --- a/src/components/composer/GenerationComposer.tsx +++ b/src/components/composer/GenerationComposer.tsx @@ -1023,22 +1023,30 @@ export function GenerationComposer() { 参考 - {primaryReference && ( -
- - - {referenceImages.length} - - {canEditReferenceImages && ( - - )} + + + {imageIndex + 1} + + {canEditReferenceImages && ( + + )} +
+ ))} )}