mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(editor): Use correct output for connected nodes in schema view (#10928)
This commit is contained in:
parent
a81256aff5
commit
ad60d49b42
|
@ -42,6 +42,7 @@ type SchemaNode = {
|
|||
depth: number;
|
||||
loading: boolean;
|
||||
open: boolean;
|
||||
connectedOutputIndexes: number[];
|
||||
itemsCount: number | null;
|
||||
schema: Schema | null;
|
||||
};
|
||||
|
@ -94,6 +95,7 @@ const nodes = computed(() => {
|
|||
|
||||
return {
|
||||
node: fullNode,
|
||||
connectedOutputIndexes: node.indicies,
|
||||
depth: node.depth,
|
||||
itemsCount,
|
||||
nodeType,
|
||||
|
@ -141,19 +143,17 @@ const highlight = computed(() => ndvStore.highlightDraggables);
|
|||
const allNodesOpen = computed(() => nodes.value.every((node) => node.open));
|
||||
const noNodesOpen = computed(() => nodes.value.every((node) => !node.open));
|
||||
|
||||
const loadNodeData = async (node: INodeUi) => {
|
||||
const loadNodeData = async ({ node, connectedOutputIndexes }: SchemaNode) => {
|
||||
const pinData = workflowsStore.pinDataByNodeName(node.name);
|
||||
const data =
|
||||
pinData ??
|
||||
executionDataToJson(
|
||||
getNodeInputData(
|
||||
node,
|
||||
props.runIndex,
|
||||
props.outputIndex,
|
||||
props.paneType,
|
||||
props.connectionType,
|
||||
) ?? [],
|
||||
);
|
||||
connectedOutputIndexes
|
||||
.map((outputIndex) =>
|
||||
executionDataToJson(
|
||||
getNodeInputData(node, props.runIndex, outputIndex, props.paneType, props.connectionType),
|
||||
),
|
||||
)
|
||||
.flat();
|
||||
|
||||
nodesData.value[node.name] = {
|
||||
schema: getSchemaForExecutionData(data),
|
||||
|
@ -161,7 +161,8 @@ const loadNodeData = async (node: INodeUi) => {
|
|||
};
|
||||
};
|
||||
|
||||
const toggleOpenNode = async ({ node, schema, open }: SchemaNode, exclusive = false) => {
|
||||
const toggleOpenNode = async (schemaNode: SchemaNode, exclusive = false) => {
|
||||
const { node, schema, open } = schemaNode;
|
||||
disableScrollInView.value = false;
|
||||
if (open) {
|
||||
nodesOpen.value[node.name] = false;
|
||||
|
@ -170,7 +171,7 @@ const toggleOpenNode = async ({ node, schema, open }: SchemaNode, exclusive = fa
|
|||
|
||||
if (!schema) {
|
||||
nodesLoading.value[node.name] = true;
|
||||
await loadNodeData(node);
|
||||
await loadNodeData(schemaNode);
|
||||
nodesLoading.value[node.name] = false;
|
||||
}
|
||||
|
||||
|
@ -182,8 +183,8 @@ const toggleOpenNode = async ({ node, schema, open }: SchemaNode, exclusive = fa
|
|||
};
|
||||
|
||||
const openAllNodes = async () => {
|
||||
const nodesToLoad = nodes.value.filter((node) => !node.schema).map(({ node }) => node);
|
||||
await Promise.all(nodesToLoad.map(async (node) => await loadNodeData(node)));
|
||||
const nodesToLoad = nodes.value.filter((node) => !node.schema);
|
||||
await Promise.all(nodesToLoad.map(loadNodeData));
|
||||
nodesOpen.value = Object.fromEntries(nodes.value.map(({ node }) => [node.name, true]));
|
||||
};
|
||||
|
||||
|
|
|
@ -2,13 +2,19 @@ import { createComponentRenderer } from '@/__tests__/render';
|
|||
import RunDataJsonSchema from '@/components/RunDataSchema.vue';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { userEvent } from '@testing-library/user-event';
|
||||
import { cleanup, within } from '@testing-library/vue';
|
||||
import { cleanup, within, waitFor } from '@testing-library/vue';
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
import { createTestNode, defaultNodeDescriptions } from '@/__tests__/mocks';
|
||||
import { SET_NODE_TYPE } from '@/constants';
|
||||
import {
|
||||
createTestNode,
|
||||
defaultNodeDescriptions,
|
||||
mockNodeTypeDescription,
|
||||
} from '@/__tests__/mocks';
|
||||
import { IF_NODE_TYPE, SET_NODE_TYPE } from '@/constants';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import type { IWorkflowDb } from '@/Interface';
|
||||
import { NodeConnectionType, type IDataObject } from 'n8n-workflow';
|
||||
import * as nodeHelpers from '@/composables/useNodeHelpers';
|
||||
|
||||
const mockNode1 = createTestNode({
|
||||
name: 'Set1',
|
||||
|
@ -31,13 +37,20 @@ const disabledNode = createTestNode({
|
|||
disabled: true,
|
||||
});
|
||||
|
||||
const ifNode = createTestNode({
|
||||
name: 'If',
|
||||
type: IF_NODE_TYPE,
|
||||
typeVersion: 1,
|
||||
disabled: false,
|
||||
});
|
||||
|
||||
async function setupStore() {
|
||||
const workflow = mock<IWorkflowDb>({
|
||||
id: '123',
|
||||
name: 'Test Workflow',
|
||||
connections: {},
|
||||
active: true,
|
||||
nodes: [mockNode1, mockNode2, disabledNode],
|
||||
nodes: [mockNode1, mockNode2, disabledNode, ifNode],
|
||||
});
|
||||
|
||||
const pinia = createPinia();
|
||||
|
@ -46,12 +59,33 @@ async function setupStore() {
|
|||
const workflowsStore = useWorkflowsStore();
|
||||
const nodeTypesStore = useNodeTypesStore();
|
||||
|
||||
nodeTypesStore.setNodeTypes(defaultNodeDescriptions);
|
||||
nodeTypesStore.setNodeTypes([
|
||||
...defaultNodeDescriptions,
|
||||
mockNodeTypeDescription({
|
||||
name: IF_NODE_TYPE,
|
||||
outputs: [NodeConnectionType.Main, NodeConnectionType.Main],
|
||||
}),
|
||||
]);
|
||||
workflowsStore.workflow = workflow;
|
||||
|
||||
return pinia;
|
||||
}
|
||||
|
||||
function mockNodeOutputData(nodeName: string, data: IDataObject[], outputIndex = 0) {
|
||||
const originalNodeHelpers = nodeHelpers.useNodeHelpers();
|
||||
vi.spyOn(nodeHelpers, 'useNodeHelpers').mockImplementation(() => {
|
||||
return {
|
||||
...originalNodeHelpers,
|
||||
getNodeInputData: vi.fn((node, _, output) => {
|
||||
if (node.name === nodeName && output === outputIndex) {
|
||||
return data.map((json) => ({ json }));
|
||||
}
|
||||
return [];
|
||||
}),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
describe('RunDataSchema.vue', () => {
|
||||
let renderComponent: ReturnType<typeof createComponentRenderer>;
|
||||
|
||||
|
@ -122,7 +156,7 @@ describe('RunDataSchema.vue', () => {
|
|||
expect(within(nodes[1]).getByTestId('run-data-schema-node-schema')).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders schema for in output pane', async () => {
|
||||
it('renders schema in output pane', async () => {
|
||||
const { container } = renderComponent({
|
||||
props: {
|
||||
nodes: [],
|
||||
|
@ -183,6 +217,28 @@ describe('RunDataSchema.vue', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('renders schema for correct output branch', async () => {
|
||||
mockNodeOutputData(
|
||||
'If',
|
||||
[
|
||||
{ id: 1, name: 'John' },
|
||||
{ id: 2, name: 'Jane' },
|
||||
],
|
||||
1,
|
||||
);
|
||||
const { getByTestId } = renderComponent({
|
||||
props: {
|
||||
nodes: [{ name: 'If', indicies: [1], depth: 2 }],
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByTestId('run-data-schema-node-name')).toHaveTextContent('If');
|
||||
expect(getByTestId('run-data-schema-node-item-count')).toHaveTextContent('2 items');
|
||||
expect(getByTestId('run-data-schema-node-schema')).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
test.each([[[{ tx: false }, { tx: false }]], [[{ tx: '' }, { tx: '' }]], [[{ tx: [] }]]])(
|
||||
'renders schema instead of showing no data for %o',
|
||||
(data) => {
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue