mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
fix(editor): Prevent tooltip flickering when a trigger node is pinned (#19233)
This commit is contained in:
@@ -12,7 +12,7 @@ import type {
|
||||
INodeIssues,
|
||||
ITaskData,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeConnectionTypes, NodeHelpers, Workflow } from 'n8n-workflow';
|
||||
import { FORM_TRIGGER_NODE_TYPE, NodeConnectionTypes, NodeHelpers, Workflow } from 'n8n-workflow';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
@@ -68,6 +68,7 @@ export const mockNodeTypeDescription = ({
|
||||
hidden,
|
||||
description,
|
||||
webhooks,
|
||||
eventTriggerDescription,
|
||||
}: {
|
||||
name?: INodeTypeDescription['name'];
|
||||
displayName?: INodeTypeDescription['displayName'];
|
||||
@@ -82,6 +83,7 @@ export const mockNodeTypeDescription = ({
|
||||
hidden?: INodeTypeDescription['hidden'];
|
||||
description?: INodeTypeDescription['description'];
|
||||
webhooks?: INodeTypeDescription['webhooks'];
|
||||
eventTriggerDescription?: INodeTypeDescription['eventTriggerDescription'];
|
||||
} = {}) =>
|
||||
mock<INodeTypeDescription>({
|
||||
name,
|
||||
@@ -105,6 +107,7 @@ export const mockNodeTypeDescription = ({
|
||||
webhooks,
|
||||
parameterPane: undefined,
|
||||
hidden,
|
||||
eventTriggerDescription,
|
||||
});
|
||||
|
||||
export const mockLoadedNodeType = (name: string) =>
|
||||
@@ -121,6 +124,7 @@ export const mockNodes = [
|
||||
mockNode({ name: 'Code', type: CODE_NODE_TYPE }),
|
||||
mockNode({ name: 'Rename', type: SET_NODE_TYPE }),
|
||||
mockNode({ name: 'Chat Trigger', type: CHAT_TRIGGER_NODE_TYPE }),
|
||||
mockNode({ name: 'Form Trigger', type: FORM_TRIGGER_NODE_TYPE }),
|
||||
mockNode({ name: 'Agent', type: AGENT_NODE_TYPE }),
|
||||
mockNode({ name: 'Sticky', type: STICKY_NODE_TYPE }),
|
||||
mockNode({ name: 'Simulate', type: SIMULATE_NODE_TYPE }),
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import type { INode, NodeApiError, Workflow } from 'n8n-workflow';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
import { setActivePinia } from 'pinia';
|
||||
import type { Ref } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
import type { Workflow, INode, NodeApiError } from 'n8n-workflow';
|
||||
import { setActivePinia } from 'pinia';
|
||||
|
||||
import { useCanvasMapping } from '@/composables/useCanvasMapping';
|
||||
import type { INodeUi } from '@/Interface';
|
||||
import {
|
||||
createTestNode,
|
||||
createTestWorkflowObject,
|
||||
@@ -13,16 +11,23 @@ import {
|
||||
mockNodes,
|
||||
mockNodeTypeDescription,
|
||||
} from '@/__tests__/mocks';
|
||||
import { STORES } from '@n8n/stores';
|
||||
import { MANUAL_TRIGGER_NODE_TYPE, SET_NODE_TYPE, STICKY_NODE_TYPE } from '@/constants';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { createCanvasConnectionHandleString, createCanvasConnectionId } from '@/utils/canvasUtils';
|
||||
import { CanvasConnectionMode, CanvasNodeRenderType } from '@/types';
|
||||
import { MarkerType } from '@vue-flow/core';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { mockedStore } from '@/__tests__/utils';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { useCanvasMapping } from '@/composables/useCanvasMapping';
|
||||
import {
|
||||
FORM_TRIGGER_NODE_TYPE,
|
||||
MANUAL_TRIGGER_NODE_TYPE,
|
||||
SET_NODE_TYPE,
|
||||
STICKY_NODE_TYPE,
|
||||
} from '@/constants';
|
||||
import type { INodeUi } from '@/Interface';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { CanvasConnectionMode, CanvasNodeRenderType, type CanvasNodeDefaultRender } from '@/types';
|
||||
import { createCanvasConnectionHandleString, createCanvasConnectionId } from '@/utils/canvasUtils';
|
||||
import { STORES } from '@n8n/stores';
|
||||
import { useRootStore } from '@n8n/stores/useRootStore';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { MarkerType } from '@vue-flow/core';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
|
||||
beforeEach(() => {
|
||||
const pinia = createTestingPinia({
|
||||
@@ -35,6 +40,14 @@ beforeEach(() => {
|
||||
[MANUAL_TRIGGER_NODE_TYPE]: {
|
||||
1: mockNodeTypeDescription({
|
||||
name: MANUAL_TRIGGER_NODE_TYPE,
|
||||
group: ['trigger'],
|
||||
}),
|
||||
},
|
||||
[FORM_TRIGGER_NODE_TYPE]: {
|
||||
1: mockNodeTypeDescription({
|
||||
name: FORM_TRIGGER_NODE_TYPE,
|
||||
group: ['trigger'],
|
||||
eventTriggerDescription: 'Waiting for you to submit the form',
|
||||
}),
|
||||
},
|
||||
[SET_NODE_TYPE]: {
|
||||
@@ -1690,6 +1703,124 @@ describe('useCanvasMapping', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('trigger tooltip behavior with pinned data', () => {
|
||||
it('should show tooltip for trigger node with no pinned data when workflow is running', () => {
|
||||
const workflowsStore = mockedStore(useWorkflowsStore);
|
||||
const triggerNode = mockNode({
|
||||
name: 'Manual Trigger',
|
||||
type: MANUAL_TRIGGER_NODE_TYPE,
|
||||
disabled: false,
|
||||
});
|
||||
const nodesList = [triggerNode];
|
||||
const connections = {};
|
||||
const workflowObject = createTestWorkflowObject({
|
||||
nodes: nodesList,
|
||||
connections,
|
||||
});
|
||||
|
||||
workflowsStore.isWorkflowRunning = true;
|
||||
workflowsStore.getWorkflowRunData = {};
|
||||
workflowsStore.pinDataByNodeName.mockReturnValue(undefined);
|
||||
|
||||
const { nodes: mappedNodes } = useCanvasMapping({
|
||||
nodes: ref(nodesList),
|
||||
connections: ref(connections),
|
||||
workflowObject: ref(workflowObject) as Ref<Workflow>,
|
||||
});
|
||||
|
||||
const renderOptions = mappedNodes.value[0]?.data?.render as CanvasNodeDefaultRender;
|
||||
expect(renderOptions.options.tooltip).toBe(
|
||||
'Waiting for you to create an event in n8n-nodes-base.manualTrigger',
|
||||
);
|
||||
});
|
||||
|
||||
describe('when the node has a custom eventTriggerDescription', () => {
|
||||
it('should show tooltip for trigger node with no pinned data when workflow is running', () => {
|
||||
const workflowsStore = mockedStore(useWorkflowsStore);
|
||||
const triggerNode = mockNode({
|
||||
name: 'Form Trigger',
|
||||
type: FORM_TRIGGER_NODE_TYPE,
|
||||
disabled: false,
|
||||
});
|
||||
const nodesList = [triggerNode];
|
||||
const connections = {};
|
||||
const workflowObject = createTestWorkflowObject({
|
||||
nodes: nodesList,
|
||||
connections,
|
||||
});
|
||||
|
||||
workflowsStore.isWorkflowRunning = true;
|
||||
workflowsStore.getWorkflowRunData = {};
|
||||
workflowsStore.pinDataByNodeName.mockReturnValue(undefined);
|
||||
|
||||
const { nodes: mappedNodes } = useCanvasMapping({
|
||||
nodes: ref(nodesList),
|
||||
connections: ref(connections),
|
||||
workflowObject: ref(workflowObject) as Ref<Workflow>,
|
||||
});
|
||||
|
||||
const renderOptions = mappedNodes.value[0]?.data?.render as CanvasNodeDefaultRender;
|
||||
expect(renderOptions.options.tooltip).toBe('Waiting for you to submit the form');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not show tooltip for trigger node with pinned data when workflow is running', () => {
|
||||
const workflowsStore = mockedStore(useWorkflowsStore);
|
||||
const triggerNode = mockNode({
|
||||
name: 'Manual Trigger',
|
||||
type: MANUAL_TRIGGER_NODE_TYPE,
|
||||
disabled: false,
|
||||
});
|
||||
const nodesList = [triggerNode];
|
||||
const connections = {};
|
||||
const workflowObject = createTestWorkflowObject({
|
||||
nodes: nodesList,
|
||||
connections,
|
||||
});
|
||||
|
||||
workflowsStore.isWorkflowRunning = true;
|
||||
workflowsStore.getWorkflowRunData = {};
|
||||
workflowsStore.pinDataByNodeName.mockReturnValue([{ json: {} }]); // Node has pinned data
|
||||
|
||||
const { nodes: mappedNodes } = useCanvasMapping({
|
||||
nodes: ref(nodesList),
|
||||
connections: ref(connections),
|
||||
workflowObject: ref(workflowObject) as Ref<Workflow>,
|
||||
});
|
||||
|
||||
const renderOptions = mappedNodes.value[0]?.data?.render as CanvasNodeDefaultRender;
|
||||
expect(renderOptions.options.tooltip).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not show tooltip when workflow is not running', () => {
|
||||
const workflowsStore = mockedStore(useWorkflowsStore);
|
||||
const triggerNode = mockNode({
|
||||
name: 'Manual Trigger',
|
||||
type: MANUAL_TRIGGER_NODE_TYPE,
|
||||
disabled: false,
|
||||
});
|
||||
const nodesList = [triggerNode];
|
||||
const connections = {};
|
||||
const workflowObject = createTestWorkflowObject({
|
||||
nodes: nodesList,
|
||||
connections,
|
||||
});
|
||||
|
||||
workflowsStore.isWorkflowRunning = false;
|
||||
workflowsStore.getWorkflowRunData = {};
|
||||
workflowsStore.pinDataByNodeName.mockReturnValue(undefined);
|
||||
|
||||
const { nodes: mappedNodes } = useCanvasMapping({
|
||||
nodes: ref(nodesList),
|
||||
connections: ref(connections),
|
||||
workflowObject: ref(workflowObject) as Ref<Workflow>,
|
||||
});
|
||||
|
||||
const renderOptions = mappedNodes.value[0]?.data?.render as CanvasNodeDefaultRender;
|
||||
expect(renderOptions.options.tooltip).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('connections', () => {
|
||||
it('should map connections to canvas connections', () => {
|
||||
const [manualTriggerNode, setNode] = mockNodes.slice(0, 2);
|
||||
|
||||
@@ -299,12 +299,13 @@ export function useCanvasMapping({
|
||||
if (
|
||||
!!node.disabled ||
|
||||
(triggerNodeName !== undefined && triggerNodeName !== node.name) ||
|
||||
!['new', 'unknown', 'waiting'].includes(nodeExecutionStatusById.value[node.id])
|
||||
!['new', 'unknown', 'waiting'].includes(nodeExecutionStatusById.value[node.id]) ||
|
||||
nodePinnedDataById.value[node.id]
|
||||
) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
if ('eventTriggerDescription' in nodeTypeDescription) {
|
||||
if (typeof nodeTypeDescription.eventTriggerDescription === 'string') {
|
||||
const nodeName = i18n.shortNodeType(nodeTypeDescription.name);
|
||||
const { eventTriggerDescription } = nodeTypeDescription;
|
||||
acc[node.id] = i18n
|
||||
|
||||
Reference in New Issue
Block a user