Skip to content

Commit 3dd70a1

Browse files
fix(editor): Drop outgoing connections on order changed event for nodes with dynamic outputs (#9055)
1 parent 936682e commit 3dd70a1

File tree

8 files changed

+304
-2
lines changed

8 files changed

+304
-2
lines changed

cypress/e2e/5-ndv.cy.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,26 @@ describe('NDV', () => {
5656
cy.shouldNotHaveConsoleErrors();
5757
});
5858

59+
it('should disconect Switch outputs if rules order was changed', () => {
60+
cy.createFixtureWorkflow('NDV-test-switch_reorder.json', `NDV test switch reorder`);
61+
workflowPage.actions.zoomToFit();
62+
63+
workflowPage.actions.executeWorkflow();
64+
workflowPage.actions.openNode('Merge');
65+
ndv.getters.outputPanel().contains('2 items').should('exist');
66+
cy.contains('span', 'first').should('exist');
67+
ndv.getters.backToCanvas().click();
68+
69+
workflowPage.actions.openNode('Switch');
70+
cy.get('.cm-line').realMouseMove(100, 100);
71+
cy.get('.fa-angle-down').click();
72+
ndv.getters.backToCanvas().click();
73+
workflowPage.actions.executeWorkflow();
74+
workflowPage.actions.openNode('Merge');
75+
ndv.getters.outputPanel().contains('1 item').should('exist');
76+
cy.contains('span', 'zero').should('exist');
77+
});
78+
5979
it('should show correct validation state for resource locator params', () => {
6080
workflowPage.actions.addNodeToCanvas('Typeform', true, true);
6181
ndv.getters.container().should('be.visible');
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
{
2+
"name": "switch reorder",
3+
"nodes": [
4+
{
5+
"parameters": {},
6+
"id": "b3f0815d-b733-413f-ab3f-74e48277bd3a",
7+
"name": "When clicking \"Test workflow\"",
8+
"type": "n8n-nodes-base.manualTrigger",
9+
"typeVersion": 1,
10+
"position": [
11+
-20,
12+
620
13+
]
14+
},
15+
{
16+
"parameters": {},
17+
"id": "fbc5b12a-6165-4cab-80a1-9fd6e4fbe39f",
18+
"name": "One",
19+
"type": "n8n-nodes-base.noOp",
20+
"typeVersion": 1,
21+
"position": [
22+
620,
23+
720
24+
]
25+
},
26+
{
27+
"parameters": {
28+
"duplicateItem": true,
29+
"duplicateCount": 1,
30+
"assignments": {
31+
"assignments": [
32+
{
33+
"id": "ec6c1d1d-a17a-4537-8135-d474df7fded1",
34+
"name": "entry",
35+
"value": "first",
36+
"type": "string"
37+
}
38+
]
39+
},
40+
"options": {}
41+
},
42+
"id": "8c5a72a5-17ef-40e0-8477-764f24770174",
43+
"name": "Edit Fields",
44+
"type": "n8n-nodes-base.set",
45+
"typeVersion": 3.3,
46+
"position": [
47+
160,
48+
740
49+
]
50+
},
51+
{
52+
"parameters": {
53+
"assignments": {
54+
"assignments": [
55+
{
56+
"id": "d8ec7c46-d02f-4bf5-931e-5ec2fb8bea22",
57+
"name": "entry",
58+
"value": "zero",
59+
"type": "string"
60+
}
61+
]
62+
},
63+
"options": {}
64+
},
65+
"id": "bc3fb81d-2ddf-4b28-a93d-762a48e8fd6b",
66+
"name": "Edit Fields1",
67+
"type": "n8n-nodes-base.set",
68+
"typeVersion": 3.3,
69+
"position": [
70+
160,
71+
500
72+
]
73+
},
74+
{
75+
"parameters": {
76+
"rules": {
77+
"values": [
78+
{
79+
"conditions": {
80+
"options": {
81+
"caseSensitive": true,
82+
"leftValue": "",
83+
"typeValidation": "strict"
84+
},
85+
"conditions": [
86+
{
87+
"leftValue": "={{ $json.entry }}",
88+
"rightValue": "first",
89+
"operator": {
90+
"type": "string",
91+
"operation": "equals"
92+
}
93+
}
94+
],
95+
"combinator": "and"
96+
},
97+
"renameOutput": true,
98+
"outputKey": "1"
99+
},
100+
{
101+
"conditions": {
102+
"options": {
103+
"caseSensitive": true,
104+
"leftValue": "",
105+
"typeValidation": "strict"
106+
},
107+
"conditions": [
108+
{
109+
"id": "ffa570ef-fc16-49ec-87be-56159f14a44b",
110+
"leftValue": "={{ $json.entry }}",
111+
"rightValue": "=second",
112+
"operator": {
113+
"type": "string",
114+
"operation": "equals"
115+
}
116+
}
117+
],
118+
"combinator": "and"
119+
},
120+
"renameOutput": true,
121+
"outputKey": "2"
122+
}
123+
]
124+
},
125+
"options": {}
126+
},
127+
"id": "296ba553-c6c5-4c84-89fb-9056b24bab30",
128+
"name": "Switch",
129+
"type": "n8n-nodes-base.switch",
130+
"typeVersion": 3,
131+
"position": [
132+
360,
133+
740
134+
]
135+
},
136+
{
137+
"parameters": {},
138+
"id": "da787dd6-8e85-4dd5-8326-198705b4ae4b",
139+
"name": "Merge",
140+
"type": "n8n-nodes-base.merge",
141+
"typeVersion": 2.1,
142+
"position": [
143+
880,
144+
520
145+
]
146+
}
147+
],
148+
"pinData": {
149+
"Edit Fields": [
150+
{
151+
"json": {
152+
"entry": "first"
153+
}
154+
},
155+
{
156+
"json": {
157+
"entry": "second"
158+
}
159+
}
160+
]
161+
},
162+
"connections": {
163+
"When clicking \"Test workflow\"": {
164+
"main": [
165+
[
166+
{
167+
"node": "Edit Fields",
168+
"type": "main",
169+
"index": 0
170+
},
171+
{
172+
"node": "Edit Fields1",
173+
"type": "main",
174+
"index": 0
175+
}
176+
]
177+
]
178+
},
179+
"Edit Fields": {
180+
"main": [
181+
[
182+
{
183+
"node": "Switch",
184+
"type": "main",
185+
"index": 0
186+
}
187+
]
188+
]
189+
},
190+
"One": {
191+
"main": [
192+
[
193+
{
194+
"node": "Merge",
195+
"type": "main",
196+
"index": 1
197+
}
198+
]
199+
]
200+
},
201+
"Edit Fields1": {
202+
"main": [
203+
[
204+
{
205+
"node": "Merge",
206+
"type": "main",
207+
"index": 0
208+
}
209+
]
210+
]
211+
},
212+
"Switch": {
213+
"main": [
214+
[
215+
{
216+
"node": "One",
217+
"type": "main",
218+
"index": 0
219+
}
220+
]
221+
]
222+
}
223+
},
224+
"active": false,
225+
"settings": {
226+
"executionOrder": "v1"
227+
},
228+
"versionId": "ce5db792-5e38-4d54-895b-88d85f2545d0",
229+
"meta": {
230+
"templateCredsSetupCompleted": true,
231+
"instanceId": "be251a83c052a9862eeac953816fbb1464f89dfbf79d7ac490a8e336a8cc8bfd"
232+
},
233+
"id": "uMpL0bN7t1NYZDJS",
234+
"tags": []
235+
}

packages/editor-ui/src/Interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ export interface IUpdateInformation {
139139
| INodeParameters; // with null makes problems in NodeSettings.vue
140140
node?: string;
141141
oldValue?: string | number;
142+
type?: 'optionsOrderChanged';
142143
}
143144

144145
export interface INodeUpdatePropertiesInformation {

packages/editor-ui/src/components/FixedCollectionParameter.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ export default defineComponent({
254254
const parameterData = {
255255
name: this.getPropertyPath(optionName),
256256
value: this.mutableValues[optionName],
257+
type: 'optionsOrderChanged',
257258
};
258259
259260
this.$emit('valueChanged', parameterData);
@@ -270,6 +271,7 @@ export default defineComponent({
270271
const parameterData = {
271272
name: this.getPropertyPath(optionName),
272273
value: this.mutableValues[optionName],
274+
type: 'optionsOrderChanged',
273275
};
274276
275277
this.$emit('valueChanged', parameterData);

packages/editor-ui/src/components/NodeSettings.vue

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ import {
200200
CUSTOM_NODES_DOCS_URL,
201201
MAIN_NODE_PANEL_WIDTH,
202202
IMPORT_CURL_MODAL_KEY,
203+
SHOULD_CLEAR_NODE_OUTPUTS,
203204
} from '@/constants';
204205
205206
import NodeTitle from '@/components/NodeTitle.vue';
@@ -223,6 +224,7 @@ import { useCredentialsStore } from '@/stores/credentials.store';
223224
import type { EventBus } from 'n8n-design-system';
224225
import { useExternalHooks } from '@/composables/useExternalHooks';
225226
import { useNodeHelpers } from '@/composables/useNodeHelpers';
227+
import { useToast } from '@/composables/useToast';
226228
227229
export default defineComponent({
228230
name: 'NodeSettings',
@@ -238,10 +240,12 @@ export default defineComponent({
238240
setup() {
239241
const nodeHelpers = useNodeHelpers();
240242
const externalHooks = useExternalHooks();
243+
const { showMessage } = useToast();
241244
242245
return {
243246
externalHooks,
244247
nodeHelpers,
248+
showMessage,
245249
};
246250
},
247251
computed: {
@@ -853,6 +857,20 @@ export default defineComponent({
853857
return;
854858
}
855859
860+
if (
861+
parameterData.type &&
862+
this.workflowsStore.nodeHasOutputConnection(node.name) &&
863+
SHOULD_CLEAR_NODE_OUTPUTS[nodeType.name]?.eventTypes.includes(parameterData.type) &&
864+
SHOULD_CLEAR_NODE_OUTPUTS[nodeType.name]?.parameterPaths.includes(parameterData.name)
865+
) {
866+
this.workflowsStore.removeAllNodeConnection(node, { preserveInputConnections: true });
867+
this.showMessage({
868+
type: 'warning',
869+
title: this.$locale.baseText('nodeSettings.outputCleared.title'),
870+
message: this.$locale.baseText('nodeSettings.outputCleared.message'),
871+
});
872+
}
873+
856874
// Get only the parameters which are different to the defaults
857875
let nodeParameters = NodeHelpers.getNodeParameters(
858876
nodeType.properties,

packages/editor-ui/src/constants.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,20 @@ export const MFA_AUTHENTICATION_RECOVERY_CODE_INPUT_MAX_LENGTH = 36;
653653

654654
export const NODE_TYPES_EXCLUDED_FROM_OUTPUT_NAME_APPEND = [FILTER_NODE_TYPE, SWITCH_NODE_TYPE];
655655

656+
type ClearOutgoingConnectonsEvents = {
657+
[nodeName: string]: {
658+
parameterPaths: string[];
659+
eventTypes: string[];
660+
};
661+
};
662+
663+
export const SHOULD_CLEAR_NODE_OUTPUTS: ClearOutgoingConnectonsEvents = {
664+
[SWITCH_NODE_TYPE]: {
665+
parameterPaths: ['parameters.rules.values'],
666+
eventTypes: ['optionsOrderChanged'],
667+
},
668+
};
669+
656670
export const ALLOWED_HTML_ATTRIBUTES = ['href', 'name', 'target', 'title', 'class', 'id', 'style'];
657671

658672
export const ALLOWED_HTML_TAGS = [

packages/editor-ui/src/plugins/i18n/locales/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,8 @@
10931093
"nodeSettings.latest": "Latest",
10941094
"nodeSettings.deprecated": "Deprecated",
10951095
"nodeSettings.latestVersion": "Latest version: {version}",
1096+
"nodeSettings.outputCleared.title": "Parameters changed",
1097+
"nodeSettings.outputCleared.message": "Order of parameters changed, outgoing connections were cleared",
10961098
"nodeSettings.nodeVersion": "{node} node version {version}",
10971099
"nodeView.addNode": "Add node",
10981100
"nodeView.openNodesPanel": "Open nodes panel",

0 commit comments

Comments
 (0)