mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
fix(editor): Fix nodes and connection debouncing during execution (no-changelog) (#14208)
This commit is contained in:
@@ -14,16 +14,13 @@ import {
|
||||
defaultNodeDescriptions,
|
||||
} from '@/__tests__/mocks';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||
import * as lodash from 'lodash-es';
|
||||
import * as vueuse from '@vueuse/core';
|
||||
|
||||
vi.mock('lodash-es', async () => {
|
||||
const actual = await vi.importActual('lodash-es');
|
||||
vi.mock('@vueuse/core', async () => {
|
||||
const actual = await vi.importActual('@vueuse/core');
|
||||
return {
|
||||
...actual,
|
||||
debounce: vi.fn((fn) => {
|
||||
// Return a function that immediately calls the provided function
|
||||
return (...args: unknown[]) => fn(...args);
|
||||
}),
|
||||
debouncedRef: vi.fn(actual.debouncedRef as typeof vueuse.debouncedRef),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -157,34 +154,6 @@ describe('WorkflowCanvas', () => {
|
||||
});
|
||||
|
||||
describe('debouncing behavior', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should initialize debounced watchers on component mount', async () => {
|
||||
renderComponent();
|
||||
|
||||
expect(lodash.debounce).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('should configure debouncing with no delay when not executing', async () => {
|
||||
renderComponent({
|
||||
props: {
|
||||
executing: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(lodash.debounce).toHaveBeenCalledTimes(3);
|
||||
|
||||
// Find calls related to our specific debouncing logic
|
||||
const calls = vi.mocked(lodash.debounce).mock.calls;
|
||||
const nonExecutingCalls = calls.filter((call) => call[1] === 0 && call[2]?.maxWait === 0);
|
||||
|
||||
expect(nonExecutingCalls.length).toBeGreaterThanOrEqual(2);
|
||||
expect(nonExecutingCalls[0][1]).toBe(0);
|
||||
expect(nonExecutingCalls[0][2]).toEqual({ maxWait: 0 });
|
||||
});
|
||||
|
||||
it('should configure debouncing with delay when executing', async () => {
|
||||
renderComponent({
|
||||
props: {
|
||||
@@ -192,10 +161,10 @@ describe('WorkflowCanvas', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(lodash.debounce).toHaveBeenCalledTimes(3);
|
||||
expect(vueuse.debouncedRef).toHaveBeenCalledTimes(2);
|
||||
|
||||
// Find calls related to our specific debouncing logic
|
||||
const calls = vi.mocked(lodash.debounce).mock.calls;
|
||||
const calls = vi.mocked(vueuse.debouncedRef).mock.calls;
|
||||
const executingCalls = calls.filter((call) => call[1] === 200 && call[2]?.maxWait === 50);
|
||||
|
||||
expect(executingCalls.length).toBeGreaterThanOrEqual(2);
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import Canvas from '@/components/canvas/Canvas.vue';
|
||||
import type { WatchStopHandle } from 'vue';
|
||||
import { computed, ref, toRef, useCssModule, watch } from 'vue';
|
||||
import { computed, ref, toRef, useCssModule } from 'vue';
|
||||
import type { Workflow } from 'n8n-workflow';
|
||||
import type { IWorkflowDb } from '@/Interface';
|
||||
import { useCanvasMapping } from '@/composables/useCanvasMapping';
|
||||
import type { EventBus } from '@n8n/utils/event-bus';
|
||||
import { createEventBus } from '@n8n/utils/event-bus';
|
||||
import type { CanvasConnection, CanvasEventBusEvents, CanvasNode } from '@/types';
|
||||
import type { CanvasEventBusEvents } from '@/types';
|
||||
import { useVueFlow } from '@vue-flow/core';
|
||||
import { debounce } from 'lodash-es';
|
||||
import { debouncedRef } from '@vueuse/core';
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
@@ -62,56 +61,8 @@ onNodesInitialized(() => {
|
||||
}
|
||||
});
|
||||
|
||||
// Debounced versions of nodes and connections and watchers
|
||||
const nodesDebounced = ref<CanvasNode[]>([]);
|
||||
const connectionsDebounced = ref<CanvasConnection[]>([]);
|
||||
const debounceNodesWatcher = ref<WatchStopHandle>();
|
||||
const debounceConnectionsWatcher = ref<WatchStopHandle>();
|
||||
|
||||
// Update debounce watchers when execution state changes
|
||||
watch(() => props.executing, setupDebouncedWatchers, { immediate: true });
|
||||
|
||||
/**
|
||||
* Sets up debounced watchers for nodes and connections
|
||||
* Uses different debounce times based on execution state:
|
||||
* - During execution: Debounce updates to reduce performance impact for large number of nodes/items
|
||||
* - Otherwise: Update immediately
|
||||
*/
|
||||
function setupDebouncedWatchers() {
|
||||
// Clear existing watchers if they exist
|
||||
debounceNodesWatcher.value?.();
|
||||
debounceConnectionsWatcher.value?.();
|
||||
|
||||
// Configure debounce parameters based on execution state
|
||||
const debounceTime = props.executing ? 200 : 0;
|
||||
const maxWait = props.executing ? 50 : 0;
|
||||
|
||||
// Set up debounced watcher for nodes
|
||||
debounceNodesWatcher.value = watch(
|
||||
mappedNodes,
|
||||
debounce(
|
||||
(value) => {
|
||||
nodesDebounced.value = value;
|
||||
},
|
||||
debounceTime,
|
||||
{ maxWait },
|
||||
),
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
// Set up debounced watcher for connections
|
||||
debounceConnectionsWatcher.value = watch(
|
||||
mappedConnections,
|
||||
debounce(
|
||||
(value) => {
|
||||
connectionsDebounced.value = value;
|
||||
},
|
||||
debounceTime,
|
||||
{ maxWait },
|
||||
),
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
}
|
||||
const mappedNodesDebounced = debouncedRef(mappedNodes, 200, { maxWait: 50 });
|
||||
const mappedConnectionsDebounced = debouncedRef(mappedConnections, 200, { maxWait: 50 });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -120,8 +71,8 @@ function setupDebouncedWatchers() {
|
||||
<Canvas
|
||||
v-if="workflow"
|
||||
:id="id"
|
||||
:nodes="nodesDebounced"
|
||||
:connections="connectionsDebounced"
|
||||
:nodes="executing ? mappedNodesDebounced : mappedNodes"
|
||||
:connections="executing ? mappedConnectionsDebounced : mappedConnections"
|
||||
:event-bus="eventBus"
|
||||
:read-only="readOnly"
|
||||
v-bind="$attrs"
|
||||
|
||||
Reference in New Issue
Block a user