From b03ceabc6319ce09f884ceef53fa5d45c19bbd7e Mon Sep 17 00:00:00 2001 From: TianYun Date: Thu, 28 May 2026 17:16:44 +0800 Subject: [PATCH] =?UTF-8?q?node=20x=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/GenerationComposer.test.tsx | 10 ++++- .../composer/GenerationComposer.tsx | 44 +++++++++++++++---- src/components/nodes/PromptNode.tsx | 8 +++- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/components/__tests__/GenerationComposer.test.tsx b/src/components/__tests__/GenerationComposer.test.tsx index 3c52cefd..b7864209 100644 --- a/src/components/__tests__/GenerationComposer.test.tsx +++ b/src/components/__tests__/GenerationComposer.test.tsx @@ -1010,13 +1010,19 @@ describe("GenerationComposer", () => { expect(data.durationSeconds).toBe(4); }); - it("shows custom selected video duration in quick settings", () => { + it("defaults gateway video dimension quick settings to the first schema option", async () => { useWorkflowStore.setState({ nodes: [videoNode("vid-1", true, { durationSeconds: 6 })], }); render(); - expect(screen.getByLabelText("Duration")).toHaveValue("6"); + expect(screen.getByLabelText("Duration")).toHaveValue("4"); + await waitFor(() => { + expect((useWorkflowStore.getState().nodes[0].data as GenerateVideoNodeData).parameters).toMatchObject({ + duration: "4", + resolution: "720p", + }); + }); }); it("uses the audio model filter and reruns the selected audio node", async () => { diff --git a/src/components/composer/GenerationComposer.tsx b/src/components/composer/GenerationComposer.tsx index bbbf2087..ff55ad04 100644 --- a/src/components/composer/GenerationComposer.tsx +++ b/src/components/composer/GenerationComposer.tsx @@ -196,10 +196,6 @@ function buildGatewayDimensionSelects( .map((parameter) => { const options = getSchemaSelectOptions(parameter); const value = draft.parameters?.[parameter.name] - ?? (parameter.name === "ratio" ? draft.aspectRatio : undefined) - ?? (parameter.name === "resolution" ? draft.resolution : undefined) - ?? (parameter.name === "duration" ? draft.durationSeconds : undefined) - ?? parameter.default ?? options[0]?.value; return { parameter, @@ -209,6 +205,24 @@ function buildGatewayDimensionSelects( }); } +function applyGatewayDimensionParameterDefaults( + schema: ModelParameter[] | undefined, + parameters: Record | undefined +): { parameters: Record; changed: boolean } { + const next = { ...(parameters ?? {}) }; + let changed = false; + const nameSet = new Set(GATEWAY_DIMENSION_PARAMETER_NAMES); + + for (const parameter of schema ?? []) { + if (!nameSet.has(parameter.name) || !parameter.options || parameter.options.length === 0) continue; + if (next[parameter.name] !== undefined && next[parameter.name] !== null && next[parameter.name] !== "") continue; + next[parameter.name] = parameter.options[0]?.value; + changed = true; + } + + return { parameters: next, changed }; +} + function getImageCountOptions(schema: ModelParameter[] | undefined): ImageGenerationCount[] { return getSchemaOptionValues(schema, IMAGE_COUNT_PARAMETER_NAMES) .map((value) => Number(value)) @@ -876,7 +890,7 @@ function buildInitialDataForNode(nodeType: NodeType, draft: ComposerDraft): Part model: getLegacyImageModel(draft.selectedModel), selectedModel: draft.selectedModel, imageCount: draft.imageCount, - parameters: {}, + parameters: draft.parameters ?? {}, inputSchema: undefined, useGoogleSearch: false, useImageSearch: false, @@ -892,7 +906,7 @@ function buildInitialDataForNode(nodeType: NodeType, draft: ComposerDraft): Part resolution: draft.resolution, durationSeconds: normalizeVideoDurationSeconds(draft.durationSeconds), soundEnabled: modelSupportsVideoSound(draft.selectedModel) ? draft.soundEnabled ?? true : undefined, - parameters: {}, + parameters: draft.parameters ?? {}, inputSchema: undefined, status: "idle", error: null, @@ -903,7 +917,7 @@ function buildInitialDataForNode(nodeType: NodeType, draft: ComposerDraft): Part inputImages: draft.inputImages, inputPrompt: draft.prompt.trim(), selectedModel: draft.selectedModel, - parameters: {}, + parameters: draft.parameters ?? {}, inputSchema: undefined, status: "idle", error: null, @@ -913,7 +927,7 @@ function buildInitialDataForNode(nodeType: NodeType, draft: ComposerDraft): Part return { inputPrompt: draft.prompt.trim(), selectedModel: draft.selectedModel, - parameters: {}, + parameters: draft.parameters ?? {}, inputSchema: undefined, status: "idle", error: null, @@ -1403,6 +1417,20 @@ export function GenerationComposer() { ? context.node?.data as NanoBananaNodeData | GenerateVideoNodeData | GenerateAudioNodeData | undefined : undefined; const activeParameterSchema = generationNodeData?.parameterSchema ?? []; + useEffect(() => { + if (context.mode !== "node-edit" || !context.node || activeParameterSchema.length === 0) return; + const normalized = applyGatewayDimensionParameterDefaults(activeParameterSchema, draftRef.current.parameters); + if (!normalized.changed) return; + + setDraft((current) => { + const currentNormalized = applyGatewayDimensionParameterDefaults(activeParameterSchema, current.parameters); + if (!currentNormalized.changed) return current; + const next = { ...current, parameters: currentNormalized.parameters }; + draftRef.current = next; + return next; + }); + updateNodeData(context.node.id, { parameters: normalized.parameters }); + }, [activeParameterSchema, context, updateNodeData]); const gatewayDimensionSelects = buildGatewayDimensionSelects(activeParameterSchema, draft); const imageCountOptions = getImageCountOptions(activeParameterSchema); const visibleImageCountOptions = imageCountOptions.length > 0 diff --git a/src/components/nodes/PromptNode.tsx b/src/components/nodes/PromptNode.tsx index fa8e5a7b..f07fef72 100644 --- a/src/components/nodes/PromptNode.tsx +++ b/src/components/nodes/PromptNode.tsx @@ -235,10 +235,14 @@ export function PromptNode({ id, data, selected }: NodeProps) { setIsEditing(true); } }} - className="flex h-full w-full cursor-text items-center justify-center rounded-lg bg-neutral-800 p-8 text-center outline-none" + className={`nodrag nopan nowheel flex h-full w-full cursor-text rounded-lg bg-neutral-800 p-8 outline-none ${ + promptText + ? "items-start justify-start overflow-auto text-left select-text" + : "items-center justify-center text-center" + }`} > {promptText ? ( -
+
{localPrompt}
) : (