mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
fix(editor): Don't mark node as dirty when NDV is opened (#15222)
This commit is contained in:
@@ -55,13 +55,16 @@ describe('Sub-workflow creation and typed usage', () => {
|
||||
|
||||
openNode('Execute Workflow');
|
||||
|
||||
let openedUrl = '';
|
||||
|
||||
// Prevent sub-workflow from opening in new window
|
||||
cy.window().then((win) => {
|
||||
cy.stub(win, 'open').callsFake((url) => {
|
||||
cy.visit(url);
|
||||
openedUrl = url;
|
||||
});
|
||||
});
|
||||
selectResourceLocatorItem('workflowId', 0, 'Create a');
|
||||
cy.then(() => cy.visit(openedUrl));
|
||||
// **************************
|
||||
// NAVIGATE TO CHILD WORKFLOW
|
||||
// **************************
|
||||
|
||||
@@ -13,7 +13,7 @@ import type {
|
||||
ResourceMapperFields,
|
||||
ResourceMapperValue,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeHelpers } from 'n8n-workflow';
|
||||
import { deepCopy, NodeHelpers } from 'n8n-workflow';
|
||||
import { computed, onMounted, reactive, watch } from 'vue';
|
||||
import MappingModeSelect from './MappingModeSelect.vue';
|
||||
import MatchingColumnsSelect from './MatchingColumnsSelect.vue';
|
||||
@@ -537,7 +537,9 @@ function emitValueChanged(): void {
|
||||
pruneParamValues();
|
||||
emit('valueChanged', {
|
||||
name: `${props.path}`,
|
||||
value: state.paramValue,
|
||||
// deepCopy ensures that mutations to state.paramValue that occur in
|
||||
// this component are never visible to the store without explicit event emits
|
||||
value: deepCopy(state.paramValue),
|
||||
node: props.node?.name,
|
||||
});
|
||||
updateNodeIssues();
|
||||
|
||||
@@ -31,6 +31,7 @@ import * as apiUtils from '@/utils/apiUtils';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { useLocalStorage } from '@vueuse/core';
|
||||
import { ref } from 'vue';
|
||||
import { createTestNode } from '@/__tests__/mocks';
|
||||
|
||||
vi.mock('@/stores/ndv.store', () => ({
|
||||
useNDVStore: vi.fn(() => ({
|
||||
@@ -1041,6 +1042,36 @@ describe('useWorkflowsStore', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('setNodeParameters', () => {
|
||||
beforeEach(() => {
|
||||
workflowsStore.setNodes([createTestNode({ name: 'a', parameters: { p: 1, q: true } })]);
|
||||
});
|
||||
|
||||
it('should set node parameters', () => {
|
||||
expect(workflowsStore.nodesByName.a.parameters).toEqual({ p: 1, q: true });
|
||||
|
||||
workflowsStore.setNodeParameters({ name: 'a', value: { q: false, r: 's' } });
|
||||
|
||||
expect(workflowsStore.nodesByName.a.parameters).toEqual({ q: false, r: 's' });
|
||||
});
|
||||
|
||||
it('should set node parameters preserving existing ones if append=true', () => {
|
||||
expect(workflowsStore.nodesByName.a.parameters).toEqual({ p: 1, q: true });
|
||||
|
||||
workflowsStore.setNodeParameters({ name: 'a', value: { q: false, r: 's' } }, true);
|
||||
|
||||
expect(workflowsStore.nodesByName.a.parameters).toEqual({ p: 1, q: false, r: 's' });
|
||||
});
|
||||
|
||||
it('should not update last parameter update time if parameters are set to the same value', () => {
|
||||
expect(workflowsStore.getParametersLastUpdate('a')).toEqual(undefined);
|
||||
|
||||
workflowsStore.setNodeParameters({ name: 'a', value: { p: 1, q: true } });
|
||||
|
||||
expect(workflowsStore.getParametersLastUpdate('a')).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('renameNodeSelectedAndExecution', () => {
|
||||
it('should rename node and update execution data', () => {
|
||||
const nodeName = 'Rename me';
|
||||
|
||||
@@ -1290,12 +1290,12 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||
return false;
|
||||
}
|
||||
|
||||
function setNodeIssue(nodeIssueData: INodeIssueData): boolean {
|
||||
function setNodeIssue(nodeIssueData: INodeIssueData): void {
|
||||
const nodeIndex = workflow.value.nodes.findIndex((node) => {
|
||||
return node.name === nodeIssueData.node;
|
||||
});
|
||||
if (nodeIndex === -1) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
const node = workflow.value.nodes[nodeIndex];
|
||||
@@ -1304,7 +1304,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||
// Remove the value if one exists
|
||||
if (node.issues?.[nodeIssueData.type] === undefined) {
|
||||
// No values for type exist so nothing has to get removed
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
const { [nodeIssueData.type]: removedNodeIssue, ...remainingNodeIssues } = node.issues;
|
||||
@@ -1319,7 +1319,6 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||
},
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function addNode(nodeData: INodeUi): void {
|
||||
@@ -1390,12 +1389,14 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||
|
||||
if (nodeIndex !== -1) {
|
||||
for (const key of Object.keys(updateInformation.properties)) {
|
||||
uiStore.stateIsDirty = true;
|
||||
|
||||
const typedKey = key as keyof INodeUpdatePropertiesInformation['properties'];
|
||||
const property = updateInformation.properties[typedKey];
|
||||
|
||||
updateNodeAtIndex(nodeIndex, { [key]: property });
|
||||
const changed = updateNodeAtIndex(nodeIndex, { [key]: property });
|
||||
|
||||
if (changed) {
|
||||
uiStore.stateIsDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1420,7 +1421,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||
|
||||
const excludeKeys = ['position', 'notes', 'notesInFlow'];
|
||||
|
||||
if (!excludeKeys.includes(updateInformation.key)) {
|
||||
if (changed && !excludeKeys.includes(updateInformation.key)) {
|
||||
nodeMetadata.value[workflow.value.nodes[nodeIndex].name].parametersLastUpdatedAt = Date.now();
|
||||
}
|
||||
}
|
||||
@@ -1439,17 +1440,19 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||
|
||||
const node = workflow.value.nodes[nodeIndex];
|
||||
|
||||
uiStore.stateIsDirty = true;
|
||||
const newParameters =
|
||||
!!append && isObject(updateInformation.value)
|
||||
? { ...node.parameters, ...updateInformation.value }
|
||||
: updateInformation.value;
|
||||
|
||||
updateNodeAtIndex(nodeIndex, {
|
||||
const changed = updateNodeAtIndex(nodeIndex, {
|
||||
parameters: newParameters as INodeParameters,
|
||||
});
|
||||
|
||||
nodeMetadata.value[node.name].parametersLastUpdatedAt = Date.now();
|
||||
if (changed) {
|
||||
uiStore.stateIsDirty = true;
|
||||
nodeMetadata.value[node.name].parametersLastUpdatedAt = Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
function setLastNodeParameters(updateInformation: IUpdateInformation): void {
|
||||
|
||||
Reference in New Issue
Block a user