feat(editor): Add execution indication to canvas v2 (no-changelog) (#9984)
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
||||
} from '@/__tests__/mocks';
|
||||
import { MANUAL_TRIGGER_NODE_TYPE, SET_NODE_TYPE } from '@/constants';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||
import { useWorkflowsStore } from '../stores/workflows.store';
|
||||
|
||||
beforeEach(() => {
|
||||
const pinia = createPinia();
|
||||
@@ -80,6 +81,7 @@ describe('useCanvasMapping', () => {
|
||||
disabled: false,
|
||||
execution: {
|
||||
status: 'new',
|
||||
running: false,
|
||||
waiting: undefined,
|
||||
},
|
||||
issues: {
|
||||
@@ -137,6 +139,27 @@ describe('useCanvasMapping', () => {
|
||||
expect(elements.value[0]?.data?.disabled).toEqual(true);
|
||||
});
|
||||
|
||||
it('should handle execution state', () => {
|
||||
const manualTriggerNode = mockNode({
|
||||
name: 'Manual Trigger',
|
||||
type: MANUAL_TRIGGER_NODE_TYPE,
|
||||
disabled: true,
|
||||
});
|
||||
const workflow = mock<IWorkflowDb>({
|
||||
nodes: [manualTriggerNode],
|
||||
});
|
||||
const workflowObject = createTestWorkflowObject(workflow);
|
||||
|
||||
useWorkflowsStore().addExecutingNode(manualTriggerNode.name);
|
||||
|
||||
const { elements } = useCanvasMapping({
|
||||
workflow: ref(workflow),
|
||||
workflowObject: ref(workflowObject) as Ref<Workflow>,
|
||||
});
|
||||
|
||||
expect(elements.value[0]?.data?.execution.running).toEqual(true);
|
||||
});
|
||||
|
||||
it('should handle input and output connections', () => {
|
||||
const [manualTriggerNode, setNode] = mockNodes.slice(0, 2);
|
||||
const workflow = mock<IWorkflowDb>({
|
||||
@@ -217,6 +240,7 @@ describe('useCanvasMapping', () => {
|
||||
target: setNode.id,
|
||||
targetHandle: `inputs/${NodeConnectionType.Main}/0`,
|
||||
type: 'canvas-edge',
|
||||
animated: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -264,6 +288,7 @@ describe('useCanvasMapping', () => {
|
||||
target: setNode.id,
|
||||
targetHandle: `inputs/${NodeConnectionType.AiTool}/0`,
|
||||
type: 'canvas-edge',
|
||||
animated: false,
|
||||
},
|
||||
{
|
||||
data: {
|
||||
@@ -285,6 +310,7 @@ describe('useCanvasMapping', () => {
|
||||
target: setNode.id,
|
||||
targetHandle: `inputs/${NodeConnectionType.AiDocument}/1`,
|
||||
type: 'canvas-edge',
|
||||
animated: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -110,6 +110,13 @@ export function useCanvasMapping({
|
||||
}, {}),
|
||||
);
|
||||
|
||||
const nodeExecutionRunningById = computed(() =>
|
||||
workflow.value.nodes.reduce<Record<string, boolean>>((acc, node) => {
|
||||
acc[node.id] = workflowsStore.isNodeExecuting(node.name);
|
||||
return acc;
|
||||
}, {}),
|
||||
);
|
||||
|
||||
const nodeExecutionStatusById = computed(() =>
|
||||
workflow.value.nodes.reduce<Record<string, ExecutionStatus>>((acc, node) => {
|
||||
acc[node.id] =
|
||||
@@ -221,6 +228,7 @@ export function useCanvasMapping({
|
||||
execution: {
|
||||
status: nodeExecutionStatusById.value[node.id],
|
||||
waiting: nodeExecutionWaitingById.value[node.id],
|
||||
running: nodeExecutionRunningById.value[node.id],
|
||||
},
|
||||
runData: {
|
||||
count: nodeExecutionRunDataById.value[node.id]?.length ?? 0,
|
||||
@@ -255,6 +263,7 @@ export function useCanvasMapping({
|
||||
data,
|
||||
type,
|
||||
label,
|
||||
animated: data.status === 'running',
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -266,7 +275,12 @@ export function useCanvasMapping({
|
||||
|
||||
let status: CanvasConnectionData['status'];
|
||||
if (fromNode) {
|
||||
if (nodePinnedDataById.value[fromNode.id] && nodeExecutionRunDataById.value[fromNode.id]) {
|
||||
if (nodeExecutionRunningById.value[fromNode.id]) {
|
||||
status = 'running';
|
||||
} else if (
|
||||
nodePinnedDataById.value[fromNode.id] &&
|
||||
nodeExecutionRunDataById.value[fromNode.id]
|
||||
) {
|
||||
status = 'pinned';
|
||||
} else if (nodeHasIssuesById.value[fromNode.id]) {
|
||||
status = 'error';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useCanvasNode } from '@/composables/useCanvasNode';
|
||||
import { inject, ref } from 'vue';
|
||||
import type { CanvasNodeInjectionData } from '../types';
|
||||
|
||||
vi.mock('vue', async () => {
|
||||
const actual = await vi.importActual('vue');
|
||||
@@ -27,38 +28,38 @@ describe('useCanvasNode', () => {
|
||||
expect(result.hasIssues.value).toBe(false);
|
||||
expect(result.executionStatus.value).toBeUndefined();
|
||||
expect(result.executionWaiting.value).toBeUndefined();
|
||||
expect(result.executionRunning.value).toBe(false);
|
||||
});
|
||||
|
||||
it('should return node data when node is provided', () => {
|
||||
const node = {
|
||||
data: {
|
||||
value: {
|
||||
id: 'node1',
|
||||
type: 'nodeType1',
|
||||
typeVersion: 1,
|
||||
disabled: true,
|
||||
inputs: ['input1'],
|
||||
outputs: ['output1'],
|
||||
connections: { input: { '0': ['node2'] }, output: {} },
|
||||
issues: { items: ['issue1'], visible: true },
|
||||
execution: { status: 'running', waiting: false },
|
||||
runData: { count: 1, visible: true },
|
||||
pinnedData: { count: 1, visible: true },
|
||||
renderType: 'default',
|
||||
},
|
||||
},
|
||||
data: ref({
|
||||
id: 'node1',
|
||||
type: 'nodeType1',
|
||||
typeVersion: 1,
|
||||
disabled: true,
|
||||
inputs: [{ type: 'main', index: 0 }],
|
||||
outputs: [{ type: 'main', index: 0 }],
|
||||
connections: { input: { '0': [] }, output: {} },
|
||||
issues: { items: ['issue1'], visible: true },
|
||||
execution: { status: 'running', waiting: 'waiting', running: true },
|
||||
runData: { count: 1, visible: true },
|
||||
pinnedData: { count: 1, visible: true },
|
||||
renderType: 'default',
|
||||
}),
|
||||
id: ref('1'),
|
||||
label: ref('Node 1'),
|
||||
selected: ref(true),
|
||||
};
|
||||
} satisfies Partial<CanvasNodeInjectionData>;
|
||||
|
||||
vi.mocked(inject).mockReturnValue(node);
|
||||
|
||||
const result = useCanvasNode();
|
||||
|
||||
expect(result.label.value).toBe('Node 1');
|
||||
expect(result.inputs.value).toEqual(['input1']);
|
||||
expect(result.outputs.value).toEqual(['output1']);
|
||||
expect(result.connections.value).toEqual({ input: { '0': ['node2'] }, output: {} });
|
||||
expect(result.inputs.value).toEqual([{ type: 'main', index: 0 }]);
|
||||
expect(result.outputs.value).toEqual([{ type: 'main', index: 0 }]);
|
||||
expect(result.connections.value).toEqual({ input: { '0': [] }, output: {} });
|
||||
expect(result.isDisabled.value).toBe(true);
|
||||
expect(result.isSelected.value).toBe(true);
|
||||
expect(result.pinnedDataCount.value).toBe(1);
|
||||
@@ -68,6 +69,7 @@ describe('useCanvasNode', () => {
|
||||
expect(result.issues.value).toEqual(['issue1']);
|
||||
expect(result.hasIssues.value).toBe(true);
|
||||
expect(result.executionStatus.value).toBe('running');
|
||||
expect(result.executionWaiting.value).toBe(false);
|
||||
expect(result.executionWaiting.value).toBe('waiting');
|
||||
expect(result.executionRunning.value).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,7 +21,9 @@ export function useCanvasNode() {
|
||||
connections: { input: {}, output: {} },
|
||||
issues: { items: [], visible: false },
|
||||
pinnedData: { count: 0, visible: false },
|
||||
execution: {},
|
||||
execution: {
|
||||
running: false,
|
||||
},
|
||||
runData: { count: 0, visible: false },
|
||||
renderType: 'default',
|
||||
},
|
||||
@@ -45,6 +47,7 @@ export function useCanvasNode() {
|
||||
|
||||
const executionStatus = computed(() => data.value.execution.status);
|
||||
const executionWaiting = computed(() => data.value.execution.waiting);
|
||||
const executionRunning = computed(() => data.value.execution.running);
|
||||
|
||||
const runDataCount = computed(() => data.value.runData.count);
|
||||
const hasRunData = computed(() => data.value.runData.visible);
|
||||
@@ -65,5 +68,6 @@ export function useCanvasNode() {
|
||||
hasIssues,
|
||||
executionStatus,
|
||||
executionWaiting,
|
||||
executionRunning,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user