🐛 Fix parameter update bug with identically named parameters

This commit is contained in:
Jan Oberhauser 2019-07-14 14:10:16 +02:00
parent 0c28799dac
commit 91bff6e4f6
7 changed files with 106 additions and 90 deletions

View file

@ -30,6 +30,7 @@
"@types/file-saver": "^2.0.1",
"@types/jest": "^23.3.2",
"@types/lodash.get": "^4.4.5",
"@types/lodash.set": "^4.3.6",
"@types/quill": "^2.0.1",
"@vue/cli-plugin-babel": "^3.8.0",
"@vue/cli-plugin-e2e-cypress": "^3.8.0",
@ -54,6 +55,7 @@
"jsplumb": "^2.10.0",
"lodash.debounce": "^4.0.8",
"lodash.get": "^4.4.2",
"lodash.set": "^4.3.2",
"n8n-workflow": "^0.3.0",
"node-sass": "^4.12.0",
"quill": "^2.0.0-dev.3",
@ -67,8 +69,8 @@
"vue-cli-plugin-webpack-bundle-analyzer": "^1.3.0",
"vue-json-pretty": "^1.4.1",
"vue-router": "^3.0.6",
"vue-template-compiler": "^2.5.17",
"vue-typed-mixins": "^0.1.0",
"vuex": "^3.1.1",
"vue-template-compiler": "^2.5.17"
"vuex": "^3.1.1"
}
}

View file

@ -116,7 +116,7 @@ export default mixins(genericHelpers)
deleteOption (optionName: string, index?: number) {
const parameterData = {
name: this.getPropertyPath(optionName, index),
value: null,
value: undefined,
};
this.$emit('valueChanged', parameterData);

View file

@ -89,7 +89,7 @@ export default mixins(genericHelpers)
deleteItem (index: number) {
const parameterData = {
name: this.getPath(index),
value: null,
value: undefined,
};
this.$emit('valueChanged', parameterData);

View file

@ -82,7 +82,7 @@ import ParameterInputFull from '@/components/ParameterInputFull.vue';
import ParameterInputList from '@/components/ParameterInputList.vue';
import NodeCredentials from '@/components/NodeCredentials.vue';
import NodeWebhooks from '@/components/NodeWebhooks.vue';
import { get } from 'lodash';
import { get, set } from 'lodash';
import { genericHelpers } from '@/components/mixins/genericHelpers';
import { nodeHelpers } from '@/components/mixins/nodeHelpers';
@ -235,7 +235,7 @@ export default mixins(
Vue.set(this.nodeValues, lastNamePart, value);
}
} else {
// Data is on lewer level
// Data is on lower level
if (value === null) {
// Property should be deleted
// @ts-ignore
@ -294,52 +294,102 @@ export default mixins(
newValue = get(this.nodeValues, parameterData.name) as NodeParameterValue;
}
if (newValue !== undefined) {
// Save the node name before we commit the change because
// we need the old name to rename the node properly
const nodeNameBefore = parameterData.node || this.node.name;
const node = this.$store.getters.nodeByName(nodeNameBefore);
// Save the node name before we commit the change because
// we need the old name to rename the node properly
const nodeNameBefore = parameterData.node || this.node.name;
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 = {
name: node.name,
key: parameterData.name,
key: 'color',
value: newValue,
};
this.$store.commit('setNodeValue', updateInformation);
} else {
// Everything else are node parameters
if (parameterData.name === 'name') {
// Name of node changed so we have to set also the new node name as active
const nodeType = this.$store.getters.nodeType(node.type);
const sendData = {
value: newValue,
oldValue: nodeNameBefore,
name: parameterData.name,
};
this.$emit('valueChanged', sendData);
// Get only the parameters which are different to the defaults
let nodeParameters = NodeHelpers.getNodeParameters(nodeType.properties, node.parameters, false, false);
this.$store.commit('setActiveNode', newValue);
} else {
// For all changes except renames we commit the change. For
// renames that happens in NodeView
this.$store.commit('setNodeParameter', updateInformation);
// Copy the data because it is the data of vuex so make sure that
// we do not edit it directly
nodeParameters = JSON.parse(JSON.stringify(nodeParameters));
const nodeType = this.$store.getters.nodeType(node.type);
const fullNodeIssues: INodeIssues | null = NodeHelpers.getNodeParametersIssues(nodeType.properties, node);
// Remove the 'parameters.' from the beginning to just have the
// actual parameter name
const parameterPath = parameterData.name.split('.').slice(1).join('.');
let newIssues: INodeIssueObjectProperty | null = null;
if (fullNodeIssues !== null) {
newIssues = fullNodeIssues.parameters!;
// Check if the path is supposed to change an array and if so get
// the needed data like path and index
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);
}
this.$store.commit('setNodeIssue', {
node: node.name,
type: 'parameters',
value: newIssues,
} as INodeIssueData);
this.updateNodeCredentialIssues(node);
} else {
// For everything else
set(nodeParameters as object, parameterPath, newValue);
}
// 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);
}
},
/**

View file

@ -141,7 +141,7 @@ export default mixins(
deleteOption (optionName: string): void {
const parameterData = {
name: this.getPath(optionName),
value: null,
value: undefined,
};
// TODO: If there is only one option it should delete the whole one

View file

@ -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
const node = state.workflow.nodes.find(node => {
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.`);
}
const nameParts = updateInformation.key.split('.');
let lastNamePart = nameParts.pop();
Vue.set(node, updateInformation.key, updateInformation.value);
},
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 (lastNamePart !== undefined && lastNamePart.includes('[')) {
// 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;
}
if (node === undefined || node === null) {
throw new Error(`Node with the name "${updateInformation.name}" could not be found to set parameter.`);
}
// Set the value via Vue.set that everything updates correctly in the UI
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)));
}
}
Vue.set(node, 'parameters', updateInformation.value);
},
// Node-Index
@ -460,10 +424,10 @@ export const store = new Vuex.Store({
Vue.set(state, 'endpointWebhookTest', endpointWebhookTest);
},
setSaveDataErrorExecution(state, newValue: string) {
setSaveDataErrorExecution (state, newValue: string) {
Vue.set(state, 'saveDataErrorExecution', newValue);
},
setSaveDataSuccessExecution(state, newValue: string) {
setSaveDataSuccessExecution (state, newValue: string) {
Vue.set(state, 'saveDataSuccessExecution', newValue);
},
setSaveManualExecutions (state, saveManualExecutions: boolean) {

View file

@ -1417,7 +1417,7 @@ export default mixins(
if (nodeType !== null) {
let nodeParameters = null;
try {
nodeParameters = NodeHelpers.getNodeParameters(nodeType.properties, node.parameters, true, true);
nodeParameters = NodeHelpers.getNodeParameters(nodeType.properties, node.parameters, true, false);
} catch (e) {
console.error(`There was a problem loading the node-parameters of node: "${node.name}"`);
console.error(e);