mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
🐛 Fix parameter update bug with identically named parameters
This commit is contained in:
parent
0c28799dac
commit
91bff6e4f6
|
@ -30,6 +30,7 @@
|
||||||
"@types/file-saver": "^2.0.1",
|
"@types/file-saver": "^2.0.1",
|
||||||
"@types/jest": "^23.3.2",
|
"@types/jest": "^23.3.2",
|
||||||
"@types/lodash.get": "^4.4.5",
|
"@types/lodash.get": "^4.4.5",
|
||||||
|
"@types/lodash.set": "^4.3.6",
|
||||||
"@types/quill": "^2.0.1",
|
"@types/quill": "^2.0.1",
|
||||||
"@vue/cli-plugin-babel": "^3.8.0",
|
"@vue/cli-plugin-babel": "^3.8.0",
|
||||||
"@vue/cli-plugin-e2e-cypress": "^3.8.0",
|
"@vue/cli-plugin-e2e-cypress": "^3.8.0",
|
||||||
|
@ -54,6 +55,7 @@
|
||||||
"jsplumb": "^2.10.0",
|
"jsplumb": "^2.10.0",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"lodash.get": "^4.4.2",
|
"lodash.get": "^4.4.2",
|
||||||
|
"lodash.set": "^4.3.2",
|
||||||
"n8n-workflow": "^0.3.0",
|
"n8n-workflow": "^0.3.0",
|
||||||
"node-sass": "^4.12.0",
|
"node-sass": "^4.12.0",
|
||||||
"quill": "^2.0.0-dev.3",
|
"quill": "^2.0.0-dev.3",
|
||||||
|
@ -67,8 +69,8 @@
|
||||||
"vue-cli-plugin-webpack-bundle-analyzer": "^1.3.0",
|
"vue-cli-plugin-webpack-bundle-analyzer": "^1.3.0",
|
||||||
"vue-json-pretty": "^1.4.1",
|
"vue-json-pretty": "^1.4.1",
|
||||||
"vue-router": "^3.0.6",
|
"vue-router": "^3.0.6",
|
||||||
|
"vue-template-compiler": "^2.5.17",
|
||||||
"vue-typed-mixins": "^0.1.0",
|
"vue-typed-mixins": "^0.1.0",
|
||||||
"vuex": "^3.1.1",
|
"vuex": "^3.1.1"
|
||||||
"vue-template-compiler": "^2.5.17"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@ export default mixins(genericHelpers)
|
||||||
deleteOption (optionName: string, index?: number) {
|
deleteOption (optionName: string, index?: number) {
|
||||||
const parameterData = {
|
const parameterData = {
|
||||||
name: this.getPropertyPath(optionName, index),
|
name: this.getPropertyPath(optionName, index),
|
||||||
value: null,
|
value: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.$emit('valueChanged', parameterData);
|
this.$emit('valueChanged', parameterData);
|
||||||
|
|
|
@ -89,7 +89,7 @@ export default mixins(genericHelpers)
|
||||||
deleteItem (index: number) {
|
deleteItem (index: number) {
|
||||||
const parameterData = {
|
const parameterData = {
|
||||||
name: this.getPath(index),
|
name: this.getPath(index),
|
||||||
value: null,
|
value: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.$emit('valueChanged', parameterData);
|
this.$emit('valueChanged', parameterData);
|
||||||
|
|
|
@ -82,7 +82,7 @@ import ParameterInputFull from '@/components/ParameterInputFull.vue';
|
||||||
import ParameterInputList from '@/components/ParameterInputList.vue';
|
import ParameterInputList from '@/components/ParameterInputList.vue';
|
||||||
import NodeCredentials from '@/components/NodeCredentials.vue';
|
import NodeCredentials from '@/components/NodeCredentials.vue';
|
||||||
import NodeWebhooks from '@/components/NodeWebhooks.vue';
|
import NodeWebhooks from '@/components/NodeWebhooks.vue';
|
||||||
import { get } from 'lodash';
|
import { get, set } from 'lodash';
|
||||||
|
|
||||||
import { genericHelpers } from '@/components/mixins/genericHelpers';
|
import { genericHelpers } from '@/components/mixins/genericHelpers';
|
||||||
import { nodeHelpers } from '@/components/mixins/nodeHelpers';
|
import { nodeHelpers } from '@/components/mixins/nodeHelpers';
|
||||||
|
@ -235,7 +235,7 @@ export default mixins(
|
||||||
Vue.set(this.nodeValues, lastNamePart, value);
|
Vue.set(this.nodeValues, lastNamePart, value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Data is on lewer level
|
// Data is on lower level
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
// Property should be deleted
|
// Property should be deleted
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -294,52 +294,102 @@ export default mixins(
|
||||||
newValue = get(this.nodeValues, parameterData.name) as NodeParameterValue;
|
newValue = get(this.nodeValues, parameterData.name) as NodeParameterValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newValue !== undefined) {
|
// Save the node name before we commit the change because
|
||||||
// Save the node name before we commit the change because
|
// we need the old name to rename the node properly
|
||||||
// we need the old name to rename the node properly
|
const nodeNameBefore = parameterData.node || this.node.name;
|
||||||
const nodeNameBefore = parameterData.node || this.node.name;
|
const node = this.$store.getters.nodeByName(nodeNameBefore);
|
||||||
const node = this.$store.getters.nodeByName(nodeNameBefore);
|
if (parameterData.name === 'name') {
|
||||||
|
// Name of node changed so we have to set also the new node name as active
|
||||||
|
|
||||||
this.setValue(parameterData.name, newValue);
|
// Update happens in NodeView so emit event
|
||||||
|
const sendData = {
|
||||||
|
value: newValue,
|
||||||
|
oldValue: nodeNameBefore,
|
||||||
|
name: parameterData.name,
|
||||||
|
};
|
||||||
|
this.$emit('valueChanged', sendData);
|
||||||
|
|
||||||
|
this.$store.commit('setActiveNode', newValue);
|
||||||
|
} else if (parameterData.name === 'color') {
|
||||||
|
// Color of node changed
|
||||||
|
|
||||||
|
// Update color in settings
|
||||||
|
Vue.set(this.nodeValues, 'color', newValue);
|
||||||
|
// Update color in vuex
|
||||||
const updateInformation = {
|
const updateInformation = {
|
||||||
name: node.name,
|
name: node.name,
|
||||||
key: parameterData.name,
|
key: 'color',
|
||||||
value: newValue,
|
value: newValue,
|
||||||
};
|
};
|
||||||
|
this.$store.commit('setNodeValue', updateInformation);
|
||||||
|
} else {
|
||||||
|
// Everything else are node parameters
|
||||||
|
|
||||||
if (parameterData.name === 'name') {
|
const nodeType = this.$store.getters.nodeType(node.type);
|
||||||
// Name of node changed so we have to set also the new node name as active
|
|
||||||
|
|
||||||
const sendData = {
|
// Get only the parameters which are different to the defaults
|
||||||
value: newValue,
|
let nodeParameters = NodeHelpers.getNodeParameters(nodeType.properties, node.parameters, false, false);
|
||||||
oldValue: nodeNameBefore,
|
|
||||||
name: parameterData.name,
|
|
||||||
};
|
|
||||||
this.$emit('valueChanged', sendData);
|
|
||||||
|
|
||||||
this.$store.commit('setActiveNode', newValue);
|
// Copy the data because it is the data of vuex so make sure that
|
||||||
} else {
|
// we do not edit it directly
|
||||||
// For all changes except renames we commit the change. For
|
nodeParameters = JSON.parse(JSON.stringify(nodeParameters));
|
||||||
// renames that happens in NodeView
|
|
||||||
this.$store.commit('setNodeParameter', updateInformation);
|
|
||||||
|
|
||||||
const nodeType = this.$store.getters.nodeType(node.type);
|
// Remove the 'parameters.' from the beginning to just have the
|
||||||
const fullNodeIssues: INodeIssues | null = NodeHelpers.getNodeParametersIssues(nodeType.properties, node);
|
// actual parameter name
|
||||||
|
const parameterPath = parameterData.name.split('.').slice(1).join('.');
|
||||||
|
|
||||||
let newIssues: INodeIssueObjectProperty | null = null;
|
// Check if the path is supposed to change an array and if so get
|
||||||
if (fullNodeIssues !== null) {
|
// the needed data like path and index
|
||||||
newIssues = fullNodeIssues.parameters!;
|
const parameterPathArray = parameterPath.match(/(.*)\[(\d)\]$/);
|
||||||
|
|
||||||
|
// Apply the new value
|
||||||
|
if (parameterData.value === undefined && parameterPathArray !== null) {
|
||||||
|
// Delete array item
|
||||||
|
const path = parameterPathArray[1];
|
||||||
|
const index = parameterPathArray[2];
|
||||||
|
const data = get(nodeParameters, path);
|
||||||
|
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
data.splice(parseInt(index, 10), 1);
|
||||||
|
Vue.set(nodeParameters as object, path, data);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
this.$store.commit('setNodeIssue', {
|
// For everything else
|
||||||
node: node.name,
|
set(nodeParameters as object, parameterPath, newValue);
|
||||||
type: 'parameters',
|
|
||||||
value: newIssues,
|
|
||||||
} as INodeIssueData);
|
|
||||||
|
|
||||||
this.updateNodeCredentialIssues(node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the parameters with the now new defaults according to the
|
||||||
|
// from the user actually defined parameters
|
||||||
|
nodeParameters = NodeHelpers.getNodeParameters(nodeType.properties, nodeParameters as INodeParameters, true, false);
|
||||||
|
|
||||||
|
for (const key of Object.keys(nodeParameters as object)) {
|
||||||
|
if (nodeParameters && nodeParameters[key] !== null && nodeParameters[key] !== undefined) {
|
||||||
|
this.setValue(`parameters.${key}`, nodeParameters[key] as string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the data in vuex
|
||||||
|
const updateInformation = {
|
||||||
|
name: node.name,
|
||||||
|
value: nodeParameters,
|
||||||
|
};
|
||||||
|
this.$store.commit('setNodeParameters', updateInformation);
|
||||||
|
|
||||||
|
// All data got updated everywhere so update now the issues
|
||||||
|
const fullNodeIssues: INodeIssues | null = NodeHelpers.getNodeParametersIssues(nodeType.properties, node);
|
||||||
|
|
||||||
|
let newIssues: INodeIssueObjectProperty | null = null;
|
||||||
|
if (fullNodeIssues !== null) {
|
||||||
|
newIssues = fullNodeIssues.parameters!;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$store.commit('setNodeIssue', {
|
||||||
|
node: node.name,
|
||||||
|
type: 'parameters',
|
||||||
|
value: newIssues,
|
||||||
|
} as INodeIssueData);
|
||||||
|
|
||||||
|
this.updateNodeCredentialIssues(node);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -141,7 +141,7 @@ export default mixins(
|
||||||
deleteOption (optionName: string): void {
|
deleteOption (optionName: string): void {
|
||||||
const parameterData = {
|
const parameterData = {
|
||||||
name: this.getPath(optionName),
|
name: this.getPath(optionName),
|
||||||
value: null,
|
value: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: If there is only one option it should delete the whole one
|
// TODO: If there is only one option it should delete the whole one
|
||||||
|
|
|
@ -348,7 +348,7 @@ export const store = new Vuex.Store({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setNodeParameter (state, updateInformation: IUpdateInformation) {
|
setNodeValue (state, updateInformation: IUpdateInformation) {
|
||||||
// Find the node that should be updated
|
// Find the node that should be updated
|
||||||
const node = state.workflow.nodes.find(node => {
|
const node = state.workflow.nodes.find(node => {
|
||||||
return node.name === updateInformation.name;
|
return node.name === updateInformation.name;
|
||||||
|
@ -358,55 +358,19 @@ export const store = new Vuex.Store({
|
||||||
throw new Error(`Node with the name "${updateInformation.name}" could not be found to set parameter.`);
|
throw new Error(`Node with the name "${updateInformation.name}" could not be found to set parameter.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const nameParts = updateInformation.key.split('.');
|
Vue.set(node, updateInformation.key, updateInformation.value);
|
||||||
let lastNamePart = nameParts.pop();
|
},
|
||||||
|
setNodeParameters (state, updateInformation: IUpdateInformation) {
|
||||||
|
// Find the node that should be updated
|
||||||
|
const node = state.workflow.nodes.find(node => {
|
||||||
|
return node.name === updateInformation.name;
|
||||||
|
});
|
||||||
|
|
||||||
let isArray = false;
|
if (node === undefined || node === null) {
|
||||||
if (lastNamePart !== undefined && lastNamePart.includes('[')) {
|
throw new Error(`Node with the name "${updateInformation.name}" could not be found to set parameter.`);
|
||||||
// It incldues an index so we have to extract it
|
|
||||||
const lastNameParts = lastNamePart.match(/(.*)\[(\d+)\]$/);
|
|
||||||
if (lastNameParts) {
|
|
||||||
nameParts.push(lastNameParts[1]);
|
|
||||||
lastNamePart = lastNameParts[2];
|
|
||||||
isArray = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the value via Vue.set that everything updates correctly in the UI
|
Vue.set(node, 'parameters', updateInformation.value);
|
||||||
|
|
||||||
if (nameParts.length === 0) {
|
|
||||||
// Data is on top level
|
|
||||||
if (updateInformation.value === null) {
|
|
||||||
// Property should be deleted
|
|
||||||
// @ts-ignore
|
|
||||||
Vue.delete(node, lastNamePart);
|
|
||||||
} else {
|
|
||||||
// Value should be set
|
|
||||||
// @ts-ignore
|
|
||||||
Vue.set(node, lastNamePart, updateInformation.value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Data is on lewer level
|
|
||||||
if (updateInformation.value === null) {
|
|
||||||
// Property should be deleted
|
|
||||||
let tempValue = get(node, nameParts.join('.'));
|
|
||||||
|
|
||||||
Vue.delete(tempValue, lastNamePart as string);
|
|
||||||
|
|
||||||
if (isArray === true && tempValue.length === 0) {
|
|
||||||
// If a value from an array got delete and no values are left
|
|
||||||
// delete also the parent
|
|
||||||
lastNamePart = nameParts.pop();
|
|
||||||
tempValue = get(node, nameParts.join('.'));
|
|
||||||
|
|
||||||
Vue.delete(tempValue, lastNamePart as string);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Value should be set
|
|
||||||
Vue.set(get(node, nameParts.join('.')), lastNamePart as string, updateInformation.value);
|
|
||||||
// Vue.set(get(node, nameParts.join('.')), lastNamePart as string, JSON.parse(JSON.stringify(updateInformation.value)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Node-Index
|
// Node-Index
|
||||||
|
@ -460,10 +424,10 @@ export const store = new Vuex.Store({
|
||||||
Vue.set(state, 'endpointWebhookTest', endpointWebhookTest);
|
Vue.set(state, 'endpointWebhookTest', endpointWebhookTest);
|
||||||
},
|
},
|
||||||
|
|
||||||
setSaveDataErrorExecution(state, newValue: string) {
|
setSaveDataErrorExecution (state, newValue: string) {
|
||||||
Vue.set(state, 'saveDataErrorExecution', newValue);
|
Vue.set(state, 'saveDataErrorExecution', newValue);
|
||||||
},
|
},
|
||||||
setSaveDataSuccessExecution(state, newValue: string) {
|
setSaveDataSuccessExecution (state, newValue: string) {
|
||||||
Vue.set(state, 'saveDataSuccessExecution', newValue);
|
Vue.set(state, 'saveDataSuccessExecution', newValue);
|
||||||
},
|
},
|
||||||
setSaveManualExecutions (state, saveManualExecutions: boolean) {
|
setSaveManualExecutions (state, saveManualExecutions: boolean) {
|
||||||
|
|
|
@ -1417,7 +1417,7 @@ export default mixins(
|
||||||
if (nodeType !== null) {
|
if (nodeType !== null) {
|
||||||
let nodeParameters = null;
|
let nodeParameters = null;
|
||||||
try {
|
try {
|
||||||
nodeParameters = NodeHelpers.getNodeParameters(nodeType.properties, node.parameters, true, true);
|
nodeParameters = NodeHelpers.getNodeParameters(nodeType.properties, node.parameters, true, false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`There was a problem loading the node-parameters of node: "${node.name}"`);
|
console.error(`There was a problem loading the node-parameters of node: "${node.name}"`);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|
Loading…
Reference in a new issue