fix(editor): Ensure NDV in focus panel reflect changes made in NDV modal (no-changelog) (#19095)

This commit is contained in:
Suguru Inoue
2025-09-02 15:36:48 +02:00
committed by GitHub
parent 0f22f3be92
commit c72acf901f
3 changed files with 100 additions and 3 deletions

View File

@@ -0,0 +1,80 @@
import { createTestNode } from '@/__tests__/mocks';
import { createComponentRenderer } from '@/__tests__/render';
import { cleanupAppModals, createAppModals } from '@/__tests__/utils';
import { SET_NODE_TYPE } from '@/constants';
import { useNDVStore } from '@/stores/ndv.store';
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { createTestingPinia } from '@pinia/testing';
import ExperimentalNodeDetailsDrawer from './ExperimentalNodeDetailsDrawer.vue';
import { nextTick } from 'vue';
const renderComponent = createComponentRenderer(ExperimentalNodeDetailsDrawer);
describe('ExperimentalNodeDetailsDrawer', () => {
let pinia: ReturnType<typeof createTestingPinia>;
let workflowsStore: ReturnType<typeof useWorkflowsStore>;
let nodeTypesStore: ReturnType<typeof useNodeTypesStore>;
let ndvStore: ReturnType<typeof useNDVStore>;
const mockNodes = [
createTestNode({
id: 'node1',
name: 'Node 1',
type: SET_NODE_TYPE,
parameters: { p0: 'before update' },
}),
createTestNode({ id: 'node2', name: 'Node 2', type: SET_NODE_TYPE }),
createTestNode({ id: 'node3', name: 'Node 3', type: SET_NODE_TYPE }),
];
beforeEach(() => {
pinia = createTestingPinia({
stubActions: false,
});
workflowsStore = useWorkflowsStore(pinia);
workflowsStore.setNodes(mockNodes);
nodeTypesStore = useNodeTypesStore(pinia);
nodeTypesStore.setNodeTypes([
{
name: SET_NODE_TYPE,
properties: [{ name: 'p0', displayName: 'P0', type: 'string', default: '' }],
version: 1,
defaults: {},
inputs: ['main'],
outputs: ['main'],
displayName: 'T0',
group: [],
description: '',
},
]);
ndvStore = useNDVStore();
createAppModals();
});
afterEach(() => {
cleanupAppModals();
});
it('should show updated parameter after closing NDV', async () => {
const rendered = renderComponent({
pinia,
props: {
node: mockNodes[0],
nodes: [mockNodes[0]],
},
});
await rendered.findByDisplayValue('before update');
// Simulate parameter update in NDV
ndvStore.setActiveNodeName('Node 1', 'other');
await nextTick();
workflowsStore.setNodeParameters({ name: 'Node 1', value: { p0: 'after update' } });
ndvStore.unsetActiveNodeName();
await nextTick();
await rendered.findByDisplayValue('after update');
});
});

View File

@@ -4,14 +4,31 @@ import { ExpressionLocalResolveContextSymbol } from '@/constants';
import { type INodeUi } from '@/Interface';
import { N8nText } from '@n8n/design-system';
import { type GraphNode } from '@vue-flow/core';
import { computed, provide } from 'vue';
import { computed, provide, ref, watch } from 'vue';
import ExperimentalCanvasNodeSettings from './ExperimentalCanvasNodeSettings.vue';
import { useNDVStore } from '@/stores/ndv.store';
const { node, nodes } = defineProps<{ node: INodeUi; nodes: GraphNode[] }>();
const emit = defineEmits<{ openNdv: [] }>();
const expressionResolveCtx = useExpressionResolveCtx(computed(() => node));
const ndvStore = useNDVStore();
const ndvCloseTimes = ref(0);
// To ensure showing latest parameters, force re-render when NDV is closed
const nodeSettingsViewKey = computed(() => [node.id, ndvCloseTimes.value].join('|'));
// Track closing NDV
watch(
() => ndvStore.activeNodeName,
(name, oldName) => {
if (name === null && oldName !== null) {
ndvCloseTimes.value += 1;
}
},
);
provide(ExpressionLocalResolveContextSymbol, expressionResolveCtx);
</script>
@@ -19,7 +36,7 @@ provide(ExpressionLocalResolveContextSymbol, expressionResolveCtx);
<template>
<div :class="$style.component">
<N8nText v-if="nodes.length > 1" color="text-base"> {{ nodes.length }} nodes selected </N8nText>
<ExperimentalCanvasNodeSettings v-else-if="node" :key="node.id" :node-id="node.id">
<ExperimentalCanvasNodeSettings v-else-if="node" :key="nodeSettingsViewKey" :node-id="node.id">
<template #actions>
<N8nIconButton
icon="maximize-2"

View File

@@ -64,7 +64,7 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, () => {
secureCookie: settings.value.authCookie.secure,
}));
const isEnterpriseFeatureEnabled = computed(() => settings.value.enterprise);
const isEnterpriseFeatureEnabled = computed(() => settings.value.enterprise ?? {});
const nodeJsVersion = computed(() => settings.value.nodeJsVersion);