mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(editor): Show previous nodes autocomplete in AI tool nodes (#11111)
This commit is contained in:
parent
05d267954c
commit
8566b3a999
|
@ -1,5 +1,16 @@
|
|||
import { expressionWithFirstItem } from '../utils';
|
||||
import { createTestNode, createTestWorkflowObject } from '@/__tests__/mocks';
|
||||
import * as workflowHelpers from '@/composables/useWorkflowHelpers';
|
||||
import { javascriptLanguage } from '@codemirror/lang-javascript';
|
||||
import { autocompletableNodeNames, expressionWithFirstItem } from '../utils';
|
||||
import type { MockInstance } from 'vitest';
|
||||
import * as ndvStore from '@/stores/ndv.store';
|
||||
import { NodeConnectionType, type IConnections } from 'n8n-workflow';
|
||||
|
||||
vi.mock('@/composables/useWorkflowHelpers', () => ({
|
||||
useWorkflowHelpers: vi.fn().mockReturnValue({
|
||||
getCurrentWorkflow: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('completion utils', () => {
|
||||
describe('expressionWithFirstItem', () => {
|
||||
|
@ -43,4 +54,72 @@ describe('completion utils', () => {
|
|||
expect(result).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('autocompletableNodeNames', () => {
|
||||
it('should work for normal nodes', () => {
|
||||
const nodes = [
|
||||
createTestNode({ name: 'Node 1' }),
|
||||
createTestNode({ name: 'Node 2' }),
|
||||
createTestNode({ name: 'Node 3' }),
|
||||
];
|
||||
const connections = {
|
||||
[nodes[0].name]: {
|
||||
[NodeConnectionType.Main]: [
|
||||
[{ node: nodes[1].name, type: NodeConnectionType.Main, index: 0 }],
|
||||
],
|
||||
},
|
||||
[nodes[1].name]: {
|
||||
[NodeConnectionType.Main]: [
|
||||
[{ node: nodes[2].name, type: NodeConnectionType.Main, index: 0 }],
|
||||
],
|
||||
},
|
||||
};
|
||||
const workflowObject = createTestWorkflowObject({
|
||||
nodes,
|
||||
connections,
|
||||
});
|
||||
|
||||
const workflowHelpersMock: MockInstance = vi.spyOn(workflowHelpers, 'useWorkflowHelpers');
|
||||
workflowHelpersMock.mockReturnValue({
|
||||
getCurrentWorkflow: vi.fn(() => workflowObject),
|
||||
});
|
||||
const ndvStoreMock: MockInstance = vi.spyOn(ndvStore, 'useNDVStore');
|
||||
ndvStoreMock.mockReturnValue({ activeNode: nodes[2] });
|
||||
|
||||
expect(autocompletableNodeNames()).toEqual(['Node 2', 'Node 1']);
|
||||
});
|
||||
|
||||
it('should work for AI tool nodes', () => {
|
||||
const nodes = [
|
||||
createTestNode({ name: 'Normal Node' }),
|
||||
createTestNode({ name: 'Agent' }),
|
||||
createTestNode({ name: 'Tool' }),
|
||||
];
|
||||
const connections: IConnections = {
|
||||
[nodes[0].name]: {
|
||||
[NodeConnectionType.Main]: [
|
||||
[{ node: nodes[1].name, type: NodeConnectionType.Main, index: 0 }],
|
||||
],
|
||||
},
|
||||
[nodes[2].name]: {
|
||||
[NodeConnectionType.AiMemory]: [
|
||||
[{ node: nodes[1].name, type: NodeConnectionType.AiMemory, index: 0 }],
|
||||
],
|
||||
},
|
||||
};
|
||||
const workflowObject = createTestWorkflowObject({
|
||||
nodes,
|
||||
connections,
|
||||
});
|
||||
|
||||
const workflowHelpersMock: MockInstance = vi.spyOn(workflowHelpers, 'useWorkflowHelpers');
|
||||
workflowHelpersMock.mockReturnValue({
|
||||
getCurrentWorkflow: vi.fn(() => workflowObject),
|
||||
});
|
||||
const ndvStoreMock: MockInstance = vi.spyOn(ndvStore, 'useNDVStore');
|
||||
ndvStoreMock.mockReturnValue({ activeNode: nodes[2] });
|
||||
|
||||
expect(autocompletableNodeNames()).toEqual(['Normal Node']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -208,15 +208,29 @@ export const isSplitInBatchesAbsent = () =>
|
|||
!useWorkflowsStore().workflow.nodes.some((node) => node.type === SPLIT_IN_BATCHES_NODE_TYPE);
|
||||
|
||||
export function autocompletableNodeNames() {
|
||||
const activeNodeName = useNDVStore().activeNode?.name;
|
||||
const activeNode = useNDVStore().activeNode;
|
||||
|
||||
if (!activeNodeName) return [];
|
||||
if (!activeNode) return [];
|
||||
|
||||
return useWorkflowHelpers({ router: useRouter() })
|
||||
.getCurrentWorkflow()
|
||||
.getParentNodesByDepth(activeNodeName)
|
||||
const activeNodeName = activeNode.name;
|
||||
|
||||
const workflow = useWorkflowHelpers({ router: useRouter() }).getCurrentWorkflow();
|
||||
const nonMainChildren = workflow.getChildNodes(activeNodeName, 'ALL_NON_MAIN');
|
||||
|
||||
// This is a tool node, look for the nearest node with main connections
|
||||
if (nonMainChildren.length > 0) {
|
||||
return nonMainChildren.map(getPreviousNodes).flat();
|
||||
}
|
||||
|
||||
return getPreviousNodes(activeNodeName);
|
||||
}
|
||||
|
||||
export function getPreviousNodes(nodeName: string) {
|
||||
const workflow = useWorkflowHelpers({ router: useRouter() }).getCurrentWorkflow();
|
||||
return workflow
|
||||
.getParentNodesByDepth(nodeName)
|
||||
.map((node) => node.name)
|
||||
.filter((name) => name !== activeNodeName);
|
||||
.filter((name) => name !== nodeName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue