Connect vector store tools nodes when adding from connection drag

This commit is contained in:
Oleg Ivaniv 2024-12-20 09:28:03 +01:00
parent 85604cca25
commit 4018dc1f7f
No known key found for this signature in database
6 changed files with 44 additions and 7 deletions

View file

@ -110,12 +110,14 @@ function getOperationModeOptions(args: VectorStoreNodeConstructorArgs): INodePro
value: 'retrieve',
description: 'Retrieve documents from vector store to be used as vector store with AI nodes',
action: 'Retrieve documents for AI processing as Vector Store',
outputConnectionType: NodeConnectionType.AiVectorStore,
},
{
name: 'Retrieve Documents (As Tool for AI Agent)',
value: 'retrieve-as-tool',
description: 'Retrieve documents from vector store to be used as tool with AI nodes',
action: 'Retrieve documents for AI processing as Tool',
outputConnectionType: NodeConnectionType.AiTool,
},
{
name: 'Update Documents',

View file

@ -723,6 +723,7 @@ export interface ActionTypeDescription extends SimplifiedNodeType {
displayOptions?: IDisplayOptions;
values?: IDataObject;
actionKey: string;
outputConnectionType?: NodeConnectionType;
codex: {
label: string;
categories: string[];

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { camelCase } from 'lodash-es';
import { computed } from 'vue';
import type { INodeCreateElement, NodeFilterType } from '@/Interface';
import type { INodeCreateElement, NodeCreateElement, NodeFilterType } from '@/Interface';
import {
TRIGGER_NODE_CREATOR_VIEW,
HTTP_REQUEST_NODE_TYPE,
@ -25,6 +25,8 @@ import NoResults from '../Panel/NoResults.vue';
import { useI18n } from '@/composables/useI18n';
import { getNodeIcon, getNodeIconColor, getNodeIconUrl } from '@/utils/nodeTypesUtils';
import { useUIStore } from '@/stores/ui.store';
import { useActions } from '../composables/useActions';
import { INodeParameters } from 'n8n-workflow';
export interface Props {
rootView: 'trigger' | 'action';
@ -40,12 +42,21 @@ const rootStore = useRootStore();
const { mergedNodes, actions, onSubcategorySelected } = useNodeCreatorStore();
const { pushViewStack, popViewStack } = useViewStacks();
const { setAddedNodeActionParameters } = useActions();
const { registerKeyHook } = useKeyboardNavigation();
const activeViewStack = computed(() => useViewStacks().activeViewStack);
const globalSearchItemsDiff = computed(() => useViewStacks().globalSearchItemsDiff);
function getFilteredActions(node: NodeCreateElement) {
const nodeActions = actions?.[node.key] || [];
if (activeViewStack.value.actionsFilter) {
return activeViewStack.value.actionsFilter(nodeActions);
}
return nodeActions;
}
function selectNodeType(nodeTypes: string[]) {
emit('nodeTypeSelected', nodeTypes);
}
@ -87,9 +98,21 @@ function onSelected(item: INodeCreateElement) {
}
if (item.type === 'node') {
const nodeActions = actions?.[item.key] || [];
const nodeActions = getFilteredActions(item);
// If there is only one action, use it
if (nodeActions.length === 1) {
selectNodeType([item.key]);
setAddedNodeActionParameters({
name: nodeActions[0].defaults.name ?? item.properties.displayName,
key: item.key,
value: nodeActions[0].values as INodeParameters,
});
return;
}
// Only show actions if there are more than one or if the view is not an AI subcategory
if (nodeActions.length <= 1 || activeViewStack.value.hideActions) {
if (nodeActions.length === 0 || activeViewStack.value.hideActions) {
selectNodeType([item.key]);
return;
}
@ -158,7 +181,7 @@ function subcategoriesMapper(item: INodeCreateElement) {
if (item.type !== 'node') return item;
const hasTriggerGroup = item.properties.group.includes('trigger');
const nodeActions = actions?.[item.key] || [];
const nodeActions = getFilteredActions(item);
const hasActions = nodeActions.length > 0;
if (hasTriggerGroup && hasActions) {
@ -179,7 +202,7 @@ function baseSubcategoriesFilter(item: INodeCreateElement): boolean {
if (item.type !== 'node') return false;
const hasTriggerGroup = item.properties.group.includes('trigger');
const nodeActions = actions?.[item.key] || [];
const nodeActions = getFilteredActions(item);
const hasActions = nodeActions.length > 0;
const isTriggerRootView = activeViewStack.value.rootView === TRIGGER_NODE_CREATOR_VIEW;

View file

@ -87,6 +87,7 @@ function operationsCategory(nodeTypeDescription: INodeTypeDescription): ActionTy
displayName: item.action ?? startCase(item.name),
description: item.description ?? '',
displayOptions: matchedProperty.displayOptions,
outputConnectionType: item.outputConnectionType,
values: {
[matchedProperty.name]: matchedProperty.type === 'multiOptions' ? [item.value] : item.value,
},
@ -117,6 +118,7 @@ function modeCategory(nodeTypeDescription: INodeTypeDescription): ActionTypeDesc
displayName: item.action ?? startCase(item.name),
description: item.description ?? '',
displayOptions: matchedProperty.displayOptions,
outputConnectionType: item.outputConnectionType,
values: {
[matchedProperty.name]: item.value,
},
@ -320,7 +322,6 @@ export function useActionsGenerator() {
const visibleNodeTypes = [...nodeTypes];
const actions: ActionsRecord<typeof mergedNodes> = {};
const mergedNodes: SimplifiedNodeType[] = [];
visibleNodeTypes
.filter((node) => !node.group.includes('trigger'))
.forEach((app) => {

View file

@ -1,4 +1,5 @@
import type {
ActionTypeDescription,
INodeCreateElement,
NodeCreateElement,
NodeFilterType,
@ -38,8 +39,8 @@ import { useKeyboardNavigation } from './useKeyboardNavigation';
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
import {
AI_TRANSFORM_NODE_TYPE,
NodeConnectionType,
type INodeInputFilter,
type NodeConnectionType,
type Themed,
} from 'n8n-workflow';
import { useCanvasStore } from '@/stores/canvas.store';
@ -71,6 +72,7 @@ interface ViewStack {
hideActions?: boolean;
baseFilter?: (item: INodeCreateElement) => boolean;
itemsMapper?: (item: INodeCreateElement) => INodeCreateElement;
actionsFilter?: (items: ActionTypeDescription[]) => ActionTypeDescription[];
panelClass?: string;
sections?: string[] | NodeViewItemSection[];
}
@ -346,6 +348,13 @@ export const useViewStacks = defineStore('nodeCreatorViewStacks', () => {
subcategory: connectionType,
};
},
actionsFilter: (items: ActionTypeDescription[]) => {
// Filter out actions that are not compatible with the connection type
if (items.some((item) => item.outputConnectionType)) {
return items.filter((item) => item.outputConnectionType === connectionType);
}
return items;
},
hideActions: true,
preventBack: true,
});

View file

@ -1449,6 +1449,7 @@ export interface INodePropertyOptions {
action?: string;
description?: string;
routing?: INodePropertyRouting;
outputConnectionType?: NodeConnectionType;
}
export interface INodeListSearchItems extends INodePropertyOptions {