From 7d92574e02bdfb65b79f3f9624cfdb8fd357fa91 Mon Sep 17 00:00:00 2001 From: zxhlyh Date: Fri, 23 May 2025 11:50:36 +0800 Subject: [PATCH] datasource panel --- .../workflow/block-selector/hooks.ts | 9 ++ .../workflow/block-selector/index.tsx | 6 +- .../workflow/hooks/use-nodes-interactions.ts | 91 ++++++++------ .../workflow/hooks/use-tool-icon.ts | 7 +- .../nodes/data-source/hooks/use-config.ts | 31 ++++- .../workflow/nodes/data-source/panel.tsx | 118 +++++++++++------- .../workflow/nodes/data-source/types.ts | 4 + 7 files changed, 174 insertions(+), 92 deletions(-) diff --git a/web/app/components/workflow/block-selector/hooks.ts b/web/app/components/workflow/block-selector/hooks.ts index 208a44dff6..5bfd7fe62b 100644 --- a/web/app/components/workflow/block-selector/hooks.ts +++ b/web/app/components/workflow/block-selector/hooks.ts @@ -3,6 +3,8 @@ import { useState, } from 'react' import { useTranslation } from 'react-i18next' +import { useDataSourceList } from '@/service/use-pipeline' +import { useStore } from '../store' import { TabsEnum, ToolTypeEnum, @@ -75,3 +77,10 @@ export const useToolTabs = () => { }, ] } + +export const useDataSources = () => { + const pipelineId = useStore(s => s.pipelineId) + const { data: dataSourceList } = useDataSourceList(!!pipelineId) + + return dataSourceList || [] +} diff --git a/web/app/components/workflow/block-selector/index.tsx b/web/app/components/workflow/block-selector/index.tsx index fc4c437a33..a9f3059770 100644 --- a/web/app/components/workflow/block-selector/index.tsx +++ b/web/app/components/workflow/block-selector/index.tsx @@ -5,8 +5,7 @@ import type { NodeSelectorProps } from './main' import NodeSelector from './main' import { useHooksStore } from '@/app/components/workflow/hooks-store/store' import { BlockEnum } from '@/app/components/workflow/types' -import { useStore } from '@/app/components/workflow/store' -import { useDataSourceList } from '@/service/use-pipeline' +import { useDataSources } from './hooks' const NodeSelectorWrapper = (props: NodeSelectorProps) => { const availableNodesMetaData = useHooksStore(s => s.availableNodesMetaData) @@ -34,8 +33,7 @@ const NodeSelectorWrapper = (props: NodeSelectorProps) => { }) }, [availableNodesMetaData?.nodes]) - const pipelineId = useStore(s => s.pipelineId) - const { data: dataSourceList } = useDataSourceList(!!pipelineId) + const dataSourceList = useDataSources() return ( { const outgoers = getOutgoers(prevNode, nodes, edges).sort((a, b) => a.position.y - b.position.y) const lastOutgoer = outgoers[outgoers.length - 1] - newNode.data._connectedTargetHandleIds = [targetHandle] + newNode.data._connectedTargetHandleIds = nodeType === BlockEnum.DataSource ? [] : [targetHandle] newNode.data._connectedSourceHandleIds = [] newNode.position = { x: lastOutgoer ? lastOutgoer.position.x : prevNode.position.x + prevNode.width! + X_OFFSET, @@ -745,27 +745,31 @@ export const useNodesInteractions = () => { } } - const newEdge: Edge = { - id: `${prevNodeId}-${prevNodeSourceHandle}-${newNode.id}-${targetHandle}`, - type: CUSTOM_EDGE, - source: prevNodeId, - sourceHandle: prevNodeSourceHandle, - target: newNode.id, - targetHandle, - data: { - sourceType: prevNode.data.type, - targetType: newNode.data.type, - isInIteration, - isInLoop, - iteration_id: isInIteration ? prevNode.parentId : undefined, - loop_id: isInLoop ? prevNode.parentId : undefined, - _connectedNodeIsSelected: true, - }, - zIndex: prevNode.parentId ? (isInIteration ? ITERATION_CHILDREN_Z_INDEX : LOOP_CHILDREN_Z_INDEX) : 0, + let newEdge = null + if (nodeType !== BlockEnum.DataSource) { + newEdge = { + id: `${prevNodeId}-${prevNodeSourceHandle}-${newNode.id}-${targetHandle}`, + type: CUSTOM_EDGE, + source: prevNodeId, + sourceHandle: prevNodeSourceHandle, + target: newNode.id, + targetHandle, + data: { + sourceType: prevNode.data.type, + targetType: newNode.data.type, + isInIteration, + isInLoop, + iteration_id: isInIteration ? prevNode.parentId : undefined, + loop_id: isInLoop ? prevNode.parentId : undefined, + _connectedNodeIsSelected: true, + }, + zIndex: prevNode.parentId ? (isInIteration ? ITERATION_CHILDREN_Z_INDEX : LOOP_CHILDREN_Z_INDEX) : 0, + } } + const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap( [ - { type: 'add', edge: newEdge }, + ...(newEdge ? [{ type: 'add', edge: newEdge }] : []), ], nodes, ) @@ -816,7 +820,8 @@ export const useNodesInteractions = () => { _connectedNodeIsSelected: false, } }) - draft.push(newEdge) + if (newEdge) + draft.push(newEdge) }) if (checkNestedParallelLimit(newNodes, newEdges, prevNode)) { @@ -959,7 +964,7 @@ export const useNodesInteractions = () => { const prevNode = nodes.find(node => node.id === prevNodeId)! const nextNode = nodes.find(node => node.id === nextNodeId)! - newNode.data._connectedTargetHandleIds = [targetHandle] + newNode.data._connectedTargetHandleIds = nodeType === BlockEnum.DataSource ? [] : [targetHandle] newNode.data._connectedSourceHandleIds = [sourceHandle] newNode.position = { x: nextNode.position.x, @@ -986,24 +991,29 @@ export const useNodesInteractions = () => { } const currentEdgeIndex = edges.findIndex(edge => edge.source === prevNodeId && edge.target === nextNodeId) - const newPrevEdge = { - id: `${prevNodeId}-${prevNodeSourceHandle}-${newNode.id}-${targetHandle}`, - type: CUSTOM_EDGE, - source: prevNodeId, - sourceHandle: prevNodeSourceHandle, - target: newNode.id, - targetHandle, - data: { - sourceType: prevNode.data.type, - targetType: newNode.data.type, - isInIteration, - isInLoop, - iteration_id: isInIteration ? prevNode.parentId : undefined, - loop_id: isInLoop ? prevNode.parentId : undefined, - _connectedNodeIsSelected: true, - }, - zIndex: prevNode.parentId ? (isInIteration ? ITERATION_CHILDREN_Z_INDEX : LOOP_CHILDREN_Z_INDEX) : 0, + let newPrevEdge = null + + if (nodeType !== BlockEnum.DataSource) { + newPrevEdge = { + id: `${prevNodeId}-${prevNodeSourceHandle}-${newNode.id}-${targetHandle}`, + type: CUSTOM_EDGE, + source: prevNodeId, + sourceHandle: prevNodeSourceHandle, + target: newNode.id, + targetHandle, + data: { + sourceType: prevNode.data.type, + targetType: newNode.data.type, + isInIteration, + isInLoop, + iteration_id: isInIteration ? prevNode.parentId : undefined, + loop_id: isInLoop ? prevNode.parentId : undefined, + _connectedNodeIsSelected: true, + }, + zIndex: prevNode.parentId ? (isInIteration ? ITERATION_CHILDREN_Z_INDEX : LOOP_CHILDREN_Z_INDEX) : 0, + } } + let newNextEdge: Edge | null = null const nextNodeParentNode = nodes.find(node => node.id === nextNode.parentId) || null @@ -1033,7 +1043,7 @@ export const useNodesInteractions = () => { const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap( [ { type: 'remove', edge: edges[currentEdgeIndex] }, - { type: 'add', edge: newPrevEdge }, + ...(newPrevEdge ? [{ type: 'add', edge: newPrevEdge }] : []), ...(newNextEdge ? [{ type: 'add', edge: newNextEdge }] : []), ], [...nodes, newNode], @@ -1088,7 +1098,8 @@ export const useNodesInteractions = () => { _connectedNodeIsSelected: false, } }) - draft.push(newPrevEdge) + if (newPrevEdge) + draft.push(newPrevEdge) if (newNextEdge) draft.push(newNextEdge) diff --git a/web/app/components/workflow/hooks/use-tool-icon.ts b/web/app/components/workflow/hooks/use-tool-icon.ts index 9d72815554..8b0f504716 100644 --- a/web/app/components/workflow/hooks/use-tool-icon.ts +++ b/web/app/components/workflow/hooks/use-tool-icon.ts @@ -10,6 +10,7 @@ import { import { useStore, } from '../store' +import { useDataSources } from '../block-selector/hooks' import { CollectionType } from '@/app/components/tools/types' import { canFindTool } from '@/utils' @@ -17,6 +18,8 @@ export const useToolIcon = (data: Node['data']) => { const buildInTools = useStore(s => s.buildInTools) const customTools = useStore(s => s.customTools) const workflowTools = useStore(s => s.workflowTools) + const dataSourceList = useDataSources() + // const a = useStore(s => s.data) const toolIcon = useMemo(() => { if (data.type === BlockEnum.Tool) { let targetTools = buildInTools @@ -28,7 +31,9 @@ export const useToolIcon = (data: Node['data']) => { targetTools = workflowTools return targetTools.find(toolWithProvider => canFindTool(toolWithProvider.id, data.provider_id))?.icon } - }, [data, buildInTools, customTools, workflowTools]) + if (data.type === BlockEnum.DataSource) + return dataSourceList.find(toolWithProvider => canFindTool(toolWithProvider.id, data.provider_id))?.icon + }, [data, buildInTools, customTools, workflowTools, dataSourceList]) return toolIcon } diff --git a/web/app/components/workflow/nodes/data-source/hooks/use-config.ts b/web/app/components/workflow/nodes/data-source/hooks/use-config.ts index e3aee2d19c..66d27dda8c 100644 --- a/web/app/components/workflow/nodes/data-source/hooks/use-config.ts +++ b/web/app/components/workflow/nodes/data-source/hooks/use-config.ts @@ -1,5 +1,34 @@ +import { useCallback } from 'react' +import { useStoreApi } from 'reactflow' +import { useNodeDataUpdate } from '@/app/components/workflow/hooks' +import type { DataSourceNodeType } from '../types' + export const useConfig = (id: string) => { + const store = useStoreApi() + const { handleNodeDataUpdateWithSyncDraft } = useNodeDataUpdate() + + const getNodeData = useCallback(() => { + const { getNodes } = store.getState() + const nodes = getNodes() + + return nodes.find(node => node.id === id) + }, [store, id]) + + const handleNodeDataUpdate = useCallback((data: Partial) => { + handleNodeDataUpdateWithSyncDraft({ + id, + data, + }) + }, [id, handleNodeDataUpdateWithSyncDraft]) + const handleFileExtensionsChange = useCallback((fileExtensions: string[]) => { + const nodeData = getNodeData() + handleNodeDataUpdate({ + ...nodeData?.data, + fileExtensions, + }) + }, [handleNodeDataUpdate, getNodeData]) + return { - id, + handleFileExtensionsChange, } } diff --git a/web/app/components/workflow/nodes/data-source/panel.tsx b/web/app/components/workflow/nodes/data-source/panel.tsx index 1497ea747a..329b47ef6b 100644 --- a/web/app/components/workflow/nodes/data-source/panel.tsx +++ b/web/app/components/workflow/nodes/data-source/panel.tsx @@ -5,15 +5,27 @@ import { import { useTranslation } from 'react-i18next' import { memo } from 'react' import type { DataSourceNodeType } from './types' +import { CollectionType } from '@/app/components/tools/types' import type { NodePanelProps } from '@/app/components/workflow/types' -import { GroupWithBox } from '@/app/components/workflow/nodes/_base/components/layout' +import { + Field, + GroupWithBox, +} from '@/app/components/workflow/nodes/_base/components/layout' import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars' import StructureOutputItem from '@/app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/show' +import TagInput from '@/app/components/base/tag-input' import { Type } from '../llm/types' +import { useConfig } from './hooks/use-config' -const Panel: FC> = ({ data }) => { +const Panel: FC> = ({ id, data }) => { const { t } = useTranslation() - const { output_schema = {} } = data + const { + output_schema = {}, + provider_id, + provider_type, + fileExtensions = [], + } = data + const { handleFileExtensionsChange } = useConfig(id) const outputSchema = useMemo(() => { const res: any[] = [] if (!output_schema) @@ -48,52 +60,66 @@ const Panel: FC> = ({ data }) => { return (
- - - + { + provider_id === 'langgenius/file/file' && provider_type === CollectionType.datasource && ( + + + + + + ) + } - - - {outputSchema.map((outputItem: any) => ( -
- {outputItem.value?.type === 'object' ? ( - + + + {outputSchema.map((outputItem: any) => ( +
+ {outputItem.value?.type === 'object' ? ( + - ) : ( - - )} -
- ))} + additionalProperties: false, + }, + }} /> + ) : ( + + )} +
+ ))}
) diff --git a/web/app/components/workflow/nodes/data-source/types.ts b/web/app/components/workflow/nodes/data-source/types.ts index f7729502e7..ea42094c0e 100644 --- a/web/app/components/workflow/nodes/data-source/types.ts +++ b/web/app/components/workflow/nodes/data-source/types.ts @@ -1,7 +1,11 @@ import type { CommonNodeType } from '@/app/components/workflow/types' import type { RAGPipelineVariables } from '@/models/pipeline' +import type { CollectionType } from '@/app/components/tools/types' export type DataSourceNodeType = CommonNodeType & { variables: RAGPipelineVariables output_schema: Record + provider_id: string + provider_type: CollectionType + fileExtensions?: string[] }