From 42d7623cc6e8b38aa0913d1e006f22205b12a962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=9E=E6=B3=95=E6=93=8D=E4=BD=9C?= Date: Wed, 1 Apr 2026 10:32:01 +0800 Subject: [PATCH] fix: Variable Aggregator cannot click group swich (#34361) --- .../__tests__/use-config.spec.tsx | 30 +++++++++++++++ .../variable-assigner/use-config.helpers.ts | 23 +++++++++++- .../nodes/variable-assigner/use-config.ts | 37 +++++++++++++------ 3 files changed, 77 insertions(+), 13 deletions(-) diff --git a/web/app/components/workflow/nodes/variable-assigner/__tests__/use-config.spec.tsx b/web/app/components/workflow/nodes/variable-assigner/__tests__/use-config.spec.tsx index 1137f20a0c5..cb8c2db52f9 100644 --- a/web/app/components/workflow/nodes/variable-assigner/__tests__/use-config.spec.tsx +++ b/web/app/components/workflow/nodes/variable-assigner/__tests__/use-config.spec.tsx @@ -91,6 +91,15 @@ const createPayload = (overrides: Partial = {}): Varia ...overrides, }) +const createPayloadWithoutAdvancedSettings = (): VariableAssignerNodeType => { + const payload = createPayload() as Omit & { + advanced_settings?: VariableAssignerNodeType['advanced_settings'] + } + delete payload.advanced_settings + + return payload as VariableAssignerNodeType +} + describe('useConfig', () => { beforeEach(() => { vi.clearAllMocks() @@ -252,4 +261,25 @@ describe('useConfig', () => { advanced_settings: expect.objectContaining({ group_enabled: false }), })) }) + + it('should not throw when enabling groups with missing advanced settings', () => { + const { result } = renderHook(() => useConfig('assigner-node', createPayloadWithoutAdvancedSettings())) + + expect(() => { + result.current.handleGroupEnabledChange(true) + }).not.toThrow() + + expect(mockHandleOutVarRenameChange).toHaveBeenCalledWith( + 'assigner-node', + ['assigner-node', 'output'], + ['assigner-node', 'Group1', 'output'], + ) + expect(mockSetInputs).toHaveBeenCalledWith(expect.objectContaining({ + advanced_settings: expect.objectContaining({ + group_enabled: true, + groups: [expect.objectContaining({ group_name: 'Group1' })], + }), + })) + expect(mockDeleteNodeInspectorVars).toHaveBeenCalledWith('assigner-node') + }) }) diff --git a/web/app/components/workflow/nodes/variable-assigner/use-config.helpers.ts b/web/app/components/workflow/nodes/variable-assigner/use-config.helpers.ts index 31300557b2c..2cc91c65aca 100644 --- a/web/app/components/workflow/nodes/variable-assigner/use-config.helpers.ts +++ b/web/app/components/workflow/nodes/variable-assigner/use-config.helpers.ts @@ -26,7 +26,13 @@ export const updateNestedVarGroupItem = ( groupId: string, payload: VarGroupItem, ) => produce(inputs, (draft) => { + if (!draft.advanced_settings) + return + const index = draft.advanced_settings.groups.findIndex(item => item.groupId === groupId) + if (index < 0) + return + draft.advanced_settings.groups[index] = { ...draft.advanced_settings.groups[index], ...payload, @@ -37,6 +43,11 @@ export const removeGroupByIndex = ( inputs: VariableAssignerNodeType, index: number, ) => produce(inputs, (draft) => { + if (!draft.advanced_settings) + return + if (index < 0 || index >= draft.advanced_settings.groups.length) + return + draft.advanced_settings.groups.splice(index, 1) }) @@ -70,7 +81,8 @@ export const toggleGroupEnabled = ({ export const addGroup = (inputs: VariableAssignerNodeType) => { let maxInGroupName = 1 - inputs.advanced_settings.groups.forEach((item) => { + const groups = inputs.advanced_settings?.groups ?? [] + groups.forEach((item) => { const match = /(\d+)$/.exec(item.group_name) if (match) { const num = Number.parseInt(match[1], 10) @@ -80,6 +92,9 @@ export const addGroup = (inputs: VariableAssignerNodeType) => { }) return produce(inputs, (draft) => { + if (!draft.advanced_settings) + draft.advanced_settings = { group_enabled: false, groups: [] } + draft.advanced_settings.groups.push({ output_type: VarType.any, variables: [], @@ -94,6 +109,12 @@ export const renameGroup = ( groupId: string, name: string, ) => produce(inputs, (draft) => { + if (!draft.advanced_settings) + return + const index = draft.advanced_settings.groups.findIndex(item => item.groupId === groupId) + if (index < 0) + return + draft.advanced_settings.groups[index].group_name = name }) diff --git a/web/app/components/workflow/nodes/variable-assigner/use-config.ts b/web/app/components/workflow/nodes/variable-assigner/use-config.ts index 6d4b27e50b7..cecf185d4f4 100644 --- a/web/app/components/workflow/nodes/variable-assigner/use-config.ts +++ b/web/app/components/workflow/nodes/variable-assigner/use-config.ts @@ -54,10 +54,15 @@ const useConfig = (id: string, payload: VariableAssignerNodeType) => { const [removedGroupIndex, setRemovedGroupIndex] = useState(-1) const handleGroupRemoved = useCallback((groupId: string) => { return () => { - const index = inputs.advanced_settings.groups.findIndex(item => item.groupId === groupId) - if (isVarUsedInNodes([id, inputs.advanced_settings.groups[index].group_name, 'output'])) { + const groups = inputs.advanced_settings?.groups ?? [] + const index = groups.findIndex(item => item.groupId === groupId) + if (index < 0) + return + + const groupName = groups[index].group_name + if (isVarUsedInNodes([id, groupName, 'output'])) { showRemoveVarConfirm() - setRemovedVars([[id, inputs.advanced_settings.groups[index].group_name, 'output']]) + setRemovedVars([[id, groupName, 'output']]) setRemoveType('group') setRemovedGroupIndex(index) return @@ -67,13 +72,15 @@ const useConfig = (id: string, payload: VariableAssignerNodeType) => { }, [id, inputs, isVarUsedInNodes, setInputs, showRemoveVarConfirm]) const handleGroupEnabledChange = useCallback((enabled: boolean) => { - if (enabled && inputs.advanced_settings.groups.length === 0) { + const groups = inputs.advanced_settings?.groups ?? [] + + if (enabled && groups.length === 0) { handleOutVarRenameChange(id, [id, 'output'], [id, 'Group1', 'output']) } - if (!enabled && inputs.advanced_settings.groups.length > 0) { - if (inputs.advanced_settings.groups.length > 1) { - const useVars = inputs.advanced_settings.groups.filter((item, index) => index > 0 && isVarUsedInNodes([id, item.group_name, 'output'])) + if (!enabled && groups.length > 0) { + if (groups.length > 1) { + const useVars = groups.filter((item, index) => index > 0 && isVarUsedInNodes([id, item.group_name, 'output'])) if (useVars.length > 0) { showRemoveVarConfirm() setRemovedVars(useVars.map(item => [id, item.group_name, 'output'])) @@ -82,7 +89,7 @@ const useConfig = (id: string, payload: VariableAssignerNodeType) => { } } - handleOutVarRenameChange(id, [id, inputs.advanced_settings.groups[0].group_name, 'output'], [id, 'output']) + handleOutVarRenameChange(id, [id, groups[0].group_name, 'output'], [id, 'output']) } setInputs(toggleGroupEnabled({ inputs, enabled })) @@ -110,11 +117,16 @@ const useConfig = (id: string, payload: VariableAssignerNodeType) => { const handleVarGroupNameChange = useCallback((groupId: string) => { return (name: string) => { - const index = inputs.advanced_settings.groups.findIndex(item => item.groupId === groupId) - handleOutVarRenameChange(id, [id, inputs.advanced_settings.groups[index].group_name, 'output'], [id, name, 'output']) + const groups = inputs.advanced_settings?.groups ?? [] + const index = groups.findIndex(item => item.groupId === groupId) + if (index < 0) + return + + const oldName = groups[index].group_name + handleOutVarRenameChange(id, [id, oldName, 'output'], [id, name, 'output']) setInputs(renameGroup(inputs, groupId, name)) if (!(id in oldNameRef.current)) - oldNameRef.current[id] = inputs.advanced_settings.groups[index].group_name + oldNameRef.current[id] = oldName renameInspectNameWithDebounce(id, name) } }, [handleOutVarRenameChange, id, inputs, renameInspectNameWithDebounce, setInputs]) @@ -125,7 +137,8 @@ const useConfig = (id: string, payload: VariableAssignerNodeType) => { }) hideRemoveVarConfirm() if (removeType === 'group') { - setInputs(removeGroupByIndex(inputs, removedGroupIndex)) + if (removedGroupIndex >= 0) + setInputs(removeGroupByIndex(inputs, removedGroupIndex)) } else { // removeType === 'enableChanged' to enabled