diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 6da72882f1..5ddf487f20 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -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" } } diff --git a/packages/editor-ui/src/components/FixedCollectionParameter.vue b/packages/editor-ui/src/components/FixedCollectionParameter.vue index 91980dbdf0..295166137f 100644 --- a/packages/editor-ui/src/components/FixedCollectionParameter.vue +++ b/packages/editor-ui/src/components/FixedCollectionParameter.vue @@ -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); diff --git a/packages/editor-ui/src/components/MultipleParameter.vue b/packages/editor-ui/src/components/MultipleParameter.vue index 3ff362276f..0fdf96fb50 100644 --- a/packages/editor-ui/src/components/MultipleParameter.vue +++ b/packages/editor-ui/src/components/MultipleParameter.vue @@ -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); diff --git a/packages/editor-ui/src/components/NodeSettings.vue b/packages/editor-ui/src/components/NodeSettings.vue index 2ac0c186aa..3ac6fc8bda 100644 --- a/packages/editor-ui/src/components/NodeSettings.vue +++ b/packages/editor-ui/src/components/NodeSettings.vue @@ -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); } }, /** diff --git a/packages/editor-ui/src/components/ParameterInputList.vue b/packages/editor-ui/src/components/ParameterInputList.vue index 1b19909fd4..0ff986bc74 100644 --- a/packages/editor-ui/src/components/ParameterInputList.vue +++ b/packages/editor-ui/src/components/ParameterInputList.vue @@ -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 diff --git a/packages/editor-ui/src/store.ts b/packages/editor-ui/src/store.ts index 8da3d9b723..db32e86dcd 100644 --- a/packages/editor-ui/src/store.ts +++ b/packages/editor-ui/src/store.ts @@ -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) { diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index f338f5f5d9..914f7697e7 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -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);