From 022a19c53a84444e102652a54059c36ea81eb036 Mon Sep 17 00:00:00 2001 From: yun Date: Mon, 6 Jul 2026 12:43:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=9A=E8=A7=92=E5=BA=A6=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflowStore.integration.test.ts | 73 +++++++++++++++++++ src/store/workflowStore.ts | 16 +++- 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/store/__tests__/workflowStore.integration.test.ts b/src/store/__tests__/workflowStore.integration.test.ts index 6a383cf4..297da05b 100644 --- a/src/store/__tests__/workflowStore.integration.test.ts +++ b/src/store/__tests__/workflowStore.integration.test.ts @@ -17,6 +17,7 @@ import { POPI_VIDEO_SUBTYPES, } from "@/constants/generationTask"; import type { WorkflowNode, WorkflowEdge } from "@/types"; +import { executeDerivedImage } from "../execution/derivedImageExecutor"; // Mock the Toast hook vi.mock("@/components/Toast", () => ({ @@ -39,6 +40,14 @@ vi.mock("@/utils/logger", () => ({ }, })); +vi.mock("../execution/derivedImageExecutor", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + executeDerivedImage: vi.fn().mockResolvedValue(undefined), + }; +}); + vi.mock("@/lib/popiartTask/runTask", () => ({ runPopiartTask: ({ payload, headers, signal }: { payload: { mediaType?: string }; @@ -1914,6 +1923,70 @@ describe("workflowStore integration tests", () => { }); describe("Group operations with non-standard node types", () => { + it("skips smart image auto task nodes when running a group", async () => { + useWorkflowStore.setState({ + nodes: [ + { ...createTestNode("prompt-1", "prompt", { prompt: "old" }), groupId: "group-1" }, + { + ...createTestNode("crop-1", "smartImage", { + status: "idle", + derivedImage: { + sourceNodeId: "source-1", + operation: "crop", + task: { + cropRect: { x: 0, y: 0, width: 100, height: 100 }, + outputWidth: 100, + outputHeight: 100, + aspectRatio: "1:1", + }, + }, + }), + groupId: "group-1", + }, + { + ...createTestNode("split-1", "smartImage", { + status: "idle", + derivedImage: { + sourceNodeId: "source-1", + operation: "splitGrid", + task: { rows: 2, cols: 2, row: 1, col: 1, cellKey: "1-1" }, + }, + }), + groupId: "group-1", + }, + { + ...createTestNode("angle-1", "smartImage", { + status: "idle", + derivedImage: { + sourceNodeId: "source-1", + operation: "multiAngle", + task: { horizontal: 0, vertical: 0, zoom: 1 }, + }, + }), + groupId: "group-1", + }, + ], + edges: [], + groups: { + "group-1": { + id: "group-1", + name: "Group 1", + color: "neutral", + position: { x: 0, y: 0 }, + size: { width: 600, height: 400 }, + }, + }, + }); + + await useWorkflowStore.getState().runGroup("group-1"); + + expect(executeDerivedImage).not.toHaveBeenCalled(); + expect(useWorkflowStore.getState().nodes.find((node) => node.id === "prompt-1")?.data.prompt) + .toBe("old"); + expect(useWorkflowStore.getState().runningNodeIds.size).toBe(0); + expect(useWorkflowStore.getState().runningGroupIds.size).toBe(0); + }); + describe("createGroup bounding box calculation", () => { it("should correctly calculate bounding box for easeCurve nodes (340x280)", () => { useWorkflowStore.setState({ diff --git a/src/store/workflowStore.ts b/src/store/workflowStore.ts index 915b8746..fad22c5d 100644 --- a/src/store/workflowStore.ts +++ b/src/store/workflowStore.ts @@ -59,7 +59,7 @@ import { GROUP_COLOR_ORDER, } from "./utils/nodeDefaults"; import { createDefaultImageModel } from "./utils/defaultImageModel"; -import { isSmartImageGenerateMode } from "@/utils/smartImageMode"; +import { isSmartImageAutoTaskNode, isSmartImageGenerateMode } from "@/utils/smartImageMode"; import { isSmartAudioGenerateMode } from "@/utils/smartAudioMode"; import { isSmartTextLlmMode } from "@/utils/smartTextMode"; import { isSmartVideoGenerateMode } from "@/utils/smartVideoMode"; @@ -2753,7 +2753,11 @@ const workflowStoreImpl: StateCreator = (set, get) => ({ }, runGroup: async (groupId: string) => { - const memberNodeIds = getGroupMemberNodeIds(get().nodes, groupId); + const currentNodes = get().nodes; + const memberNodeIds = getGroupMemberNodeIds(currentNodes, groupId).filter((nodeId) => { + const node = currentNodes.find((candidate) => candidate.id === nodeId); + return !(node?.type === "smartImage" && isSmartImageAutoTaskNode(node.data)); + }); if (memberNodeIds.length === 0) { logger.warn("node.execution", "No nodes found in group for execution", { groupId }); return; @@ -3039,6 +3043,14 @@ const workflowStoreImpl: StateCreator = (set, get) => ({ throw new DOMException('Aborted', 'AbortError'); } + if (options?.groupId && node.type === "smartImage" && isSmartImageAutoTaskNode(node.data)) { + logger.info("node.execution", "Skipping smart image auto task node during group execution", { + nodeId: node.id, + groupId: options.groupId, + }); + return; + } + logger.info('node.execution', `Executing ${node.type} node`, { nodeId: node.id, nodeType: node.type,