From e19adbbbc541e4023379f5bd24c05213ccc280a8 Mon Sep 17 00:00:00 2001 From: zxhlyh Date: Fri, 23 May 2025 16:27:19 +0800 Subject: [PATCH] datasource --- .../workflow/block-selector/data-sources.tsx | 13 +- .../workflow/block-selector/tabs.tsx | 4 +- .../workflow/block-selector/types.ts | 8 + .../_base/components/input-field/add.tsx | 12 ++ .../_base/components/input-field/index.tsx | 24 +++ .../components/layout/box-group-field.tsx | 29 +++ .../{group-with-box.tsx => box-group.tsx} | 6 +- .../_base/components/layout/field-title.tsx | 39 ++++- .../nodes/_base/components/layout/field.tsx | 26 ++- .../_base/components/layout/group-field.tsx | 29 +++ .../nodes/_base/components/layout/index.tsx | 4 +- .../workflow/nodes/data-source/panel.tsx | 165 ++++++++---------- .../workflow/nodes/data-source/types.ts | 21 ++- .../components/input-variable.tsx | 37 ---- .../workflow/nodes/knowledge-base/panel.tsx | 31 +++- web/app/components/workflow/types.ts | 10 +- 16 files changed, 293 insertions(+), 165 deletions(-) create mode 100644 web/app/components/workflow/nodes/_base/components/input-field/add.tsx create mode 100644 web/app/components/workflow/nodes/_base/components/input-field/index.tsx create mode 100644 web/app/components/workflow/nodes/_base/components/layout/box-group-field.tsx rename web/app/components/workflow/nodes/_base/components/layout/{group-with-box.tsx => box-group.tsx} (82%) create mode 100644 web/app/components/workflow/nodes/_base/components/layout/group-field.tsx delete mode 100644 web/app/components/workflow/nodes/knowledge-base/components/input-variable.tsx diff --git a/web/app/components/workflow/block-selector/data-sources.tsx b/web/app/components/workflow/block-selector/data-sources.tsx index 16a08e01ef..467ddaa9e7 100644 --- a/web/app/components/workflow/block-selector/data-sources.tsx +++ b/web/app/components/workflow/block-selector/data-sources.tsx @@ -7,6 +7,7 @@ import type { OnSelectBlock, ToolWithProvider, } from '../types' +import type { ToolDefaultValue } from './types' import Tools from './tools' import { ViewType } from './view-type-select' import cn from '@/utils/classnames' @@ -30,8 +31,14 @@ const DataSources = ({ const pluginRef = useRef(null) const wrapElemRef = useRef(null) const formatedDataSources = dataSources.map(item => ({ ...item, tools: item.datasources || [] })) - const handleSelect = useCallback((_, toolDefaultValue) => { - onSelect(BlockEnum.DataSource, toolDefaultValue) + const handleSelect = useCallback((_: any, toolDefaultValue: ToolDefaultValue) => { + onSelect(BlockEnum.DataSource, toolDefaultValue && { + provider_id: toolDefaultValue?.provider_id, + provider_type: toolDefaultValue?.provider_type, + provider_name: toolDefaultValue?.provider_name, + datasource_name: toolDefaultValue?.tool_name, + datasource_label: toolDefaultValue?.tool_label, + }) }, [onSelect]) return ( @@ -45,7 +52,7 @@ const DataSources = ({ className={toolContentClassName} showWorkflowEmpty={false} tools={formatedDataSources} - onSelect={handleSelect} + onSelect={handleSelect as OnSelectBlock} viewType={ViewType.flat} hasSearchText={!!searchText} /> diff --git a/web/app/components/workflow/block-selector/tabs.tsx b/web/app/components/workflow/block-selector/tabs.tsx index c4dc4532cf..ad6e8b4176 100644 --- a/web/app/components/workflow/block-selector/tabs.tsx +++ b/web/app/components/workflow/block-selector/tabs.tsx @@ -4,9 +4,9 @@ import { useAllBuiltInTools, useAllCustomTools, useAllWorkflowTools } from '@/se import type { BlockEnum, NodeDefault, + OnSelectBlock, ToolWithProvider, } from '../types' -import type { ToolDefaultValue } from './types' import { TabsEnum } from './types' import Blocks from './blocks' import AllTools from './all-tools' @@ -16,7 +16,7 @@ export type TabsProps = { activeTab: TabsEnum searchText: string tags: string[] - onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void + onSelect: OnSelectBlock availableBlocksTypes?: BlockEnum[] blocks: NodeDefault[] dataSources?: ToolWithProvider[] diff --git a/web/app/components/workflow/block-selector/types.ts b/web/app/components/workflow/block-selector/types.ts index 1be4f224e3..1558fd4be6 100644 --- a/web/app/components/workflow/block-selector/types.ts +++ b/web/app/components/workflow/block-selector/types.ts @@ -33,6 +33,14 @@ export type ToolDefaultValue = { output_schema: Record } +export type DataSourceDefaultValue = { + provider_id: string + provider_type: string + provider_name: string + datasource_name: string + datasource_label: string +} + export type ToolValue = { provider_name: string tool_name: string diff --git a/web/app/components/workflow/nodes/_base/components/input-field/add.tsx b/web/app/components/workflow/nodes/_base/components/input-field/add.tsx new file mode 100644 index 0000000000..a104973399 --- /dev/null +++ b/web/app/components/workflow/nodes/_base/components/input-field/add.tsx @@ -0,0 +1,12 @@ +import { RiAddLine } from '@remixicon/react' +import ActionButton from '@/app/components/base/action-button' + +const Add = () => { + return ( + + + + ) +} + +export default Add diff --git a/web/app/components/workflow/nodes/_base/components/input-field/index.tsx b/web/app/components/workflow/nodes/_base/components/input-field/index.tsx new file mode 100644 index 0000000000..829133e52a --- /dev/null +++ b/web/app/components/workflow/nodes/_base/components/input-field/index.tsx @@ -0,0 +1,24 @@ +import { BoxGroupField } from '@/app/components/workflow/nodes/_base/components/layout' +import Add from './add' + +const InputField = () => { + return ( + , + }, + }} + boxGroupProps={{ + boxProps: { + withBorderBottom: true, + }, + }} + > + input field + + ) +} +export default InputField diff --git a/web/app/components/workflow/nodes/_base/components/layout/box-group-field.tsx b/web/app/components/workflow/nodes/_base/components/layout/box-group-field.tsx new file mode 100644 index 0000000000..f89f13e1c5 --- /dev/null +++ b/web/app/components/workflow/nodes/_base/components/layout/box-group-field.tsx @@ -0,0 +1,29 @@ +import type { ReactNode } from 'react' +import { memo } from 'react' +import type { + BoxGroupProps, + FieldProps, +} from '.' +import { + BoxGroup, + Field, +} from '.' + +type BoxGroupFieldProps = { + children?: ReactNode + boxGroupProps?: Omit + fieldProps?: Omit +} +export const BoxGroupField = memo(({ + children, + fieldProps, + boxGroupProps, +}: BoxGroupFieldProps) => { + return ( + + + {children} + + + ) +}) diff --git a/web/app/components/workflow/nodes/_base/components/layout/group-with-box.tsx b/web/app/components/workflow/nodes/_base/components/layout/box-group.tsx similarity index 82% rename from web/app/components/workflow/nodes/_base/components/layout/group-with-box.tsx rename to web/app/components/workflow/nodes/_base/components/layout/box-group.tsx index d2cea636f3..7d2d4b0dcb 100644 --- a/web/app/components/workflow/nodes/_base/components/layout/group-with-box.tsx +++ b/web/app/components/workflow/nodes/_base/components/layout/box-group.tsx @@ -9,16 +9,16 @@ import type { GroupProps, } from '.' -type GroupWithBoxProps = { +export type BoxGroupProps = { children?: ReactNode boxProps?: Omit groupProps?: Omit } -export const GroupWithBox = memo(({ +export const BoxGroup = memo(({ children, boxProps, groupProps, -}: GroupWithBoxProps) => { +}: BoxGroupProps) => { return ( diff --git a/web/app/components/workflow/nodes/_base/components/layout/field-title.tsx b/web/app/components/workflow/nodes/_base/components/layout/field-title.tsx index 84d2ec33cb..8ab2d8de27 100644 --- a/web/app/components/workflow/nodes/_base/components/layout/field-title.tsx +++ b/web/app/components/workflow/nodes/_base/components/layout/field-title.tsx @@ -1,25 +1,58 @@ import type { ReactNode } from 'react' -import { memo } from 'react' +import { + memo, + useState, +} from 'react' +import { ArrowDownRoundFill } from '@/app/components/base/icons/src/vender/solid/general' import Tooltip from '@/app/components/base/tooltip' import cn from '@/utils/classnames' export type FieldTitleProps = { - title: string + title?: string operation?: ReactNode subTitle?: string | ReactNode tooltip?: string + showArrow?: boolean + disabled?: boolean + collapsed?: boolean + onCollapse?: (collapsed: boolean) => void } export const FieldTitle = memo(({ title, operation, subTitle, tooltip, + showArrow, + disabled, + collapsed, + onCollapse, }: FieldTitleProps) => { + const [collapsedLocal, setCollapsedLocal] = useState(true) + const collapsedMerged = collapsed !== undefined ? collapsed : collapsedLocal + return (
-
+
{ + if (!disabled) { + setCollapsedLocal(!collapsedMerged) + onCollapse?.(!collapsedMerged) + } + }} + >
{title} + { + showArrow && ( + + ) + } { tooltip && ( { + const [collapsed, setCollapsed] = useState(false) + return (
- - {children} + + {supportCollapse && !collapsed && children} + {!supportCollapse && children}
) }) diff --git a/web/app/components/workflow/nodes/_base/components/layout/group-field.tsx b/web/app/components/workflow/nodes/_base/components/layout/group-field.tsx new file mode 100644 index 0000000000..b7238f0c0c --- /dev/null +++ b/web/app/components/workflow/nodes/_base/components/layout/group-field.tsx @@ -0,0 +1,29 @@ +import type { ReactNode } from 'react' +import { memo } from 'react' +import type { + FieldProps, + GroupProps, +} from '.' +import { + Field, + Group, +} from '.' + +type GroupFieldProps = { + children?: ReactNode + groupProps?: Omit + fieldProps?: Omit +} +export const GroupField = memo(({ + children, + fieldProps, + groupProps, +}: GroupFieldProps) => { + return ( + + + {children} + + + ) +}) diff --git a/web/app/components/workflow/nodes/_base/components/layout/index.tsx b/web/app/components/workflow/nodes/_base/components/layout/index.tsx index 3323405d19..fc5b211bdc 100644 --- a/web/app/components/workflow/nodes/_base/components/layout/index.tsx +++ b/web/app/components/workflow/nodes/_base/components/layout/index.tsx @@ -1,5 +1,7 @@ export * from './box' export * from './group' -export * from './group-with-box' +export * from './box-group' export * from './field-title' export * from './field' +export * from './group-field' +export * from './box-group-field' diff --git a/web/app/components/workflow/nodes/data-source/panel.tsx b/web/app/components/workflow/nodes/data-source/panel.tsx index 854e9235c9..a9a303e616 100644 --- a/web/app/components/workflow/nodes/data-source/panel.tsx +++ b/web/app/components/workflow/nodes/data-source/panel.tsx @@ -1,128 +1,101 @@ import type { FC } from 'react' -import { - useMemo, -} from 'react' 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 { - Field, - GroupWithBox, -} from '@/app/components/workflow/nodes/_base/components/layout' +import { BoxGroupField } 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> = ({ id, data }) => { const { t } = useTranslation() const { - output_schema = {}, provider_id, provider_type, fileExtensions = [], } = data const { handleFileExtensionsChange } = useConfig(id) - const outputSchema = useMemo(() => { - const res: any[] = [] - if (!output_schema) - return [] - Object.keys(output_schema.properties).forEach((outputKey) => { - const output = output_schema.properties[outputKey] - const type = output.type - if (type === 'object') { - res.push({ - name: outputKey, - value: output, - }) - } - else { - res.push({ - name: outputKey, - type: output.type === 'array' - ? `Array[${output.items?.type.slice(0, 1).toLocaleUpperCase()}${output.items?.type.slice(1)}]` - : `${output.type.slice(0, 1).toLocaleUpperCase()}${output.type.slice(1)}`, - description: output.description, - }) - } - }) - return res - }, [output_schema]) - const hasObjectOutput = useMemo(() => { - if (!output_schema) - return false - const properties = output_schema.properties - return Object.keys(properties).some(key => properties[key].type === 'object') - }, [output_schema]) + const isLocalFile = provider_id === 'langgenius/file/file' && provider_type === CollectionType.datasource return (
{ - provider_id === 'langgenius/file/file' && provider_type === CollectionType.datasource && ( - - -
- -
-
-
+ }, + }} + > +
+ +
+ ) } - - - {outputSchema.map((outputItem: any) => ( -
- {outputItem.value?.type === 'object' ? ( - - ) : ( - - )} -
- ))} + { + isLocalFile && ( + + ) + }
) diff --git a/web/app/components/workflow/nodes/data-source/types.ts b/web/app/components/workflow/nodes/data-source/types.ts index ea42094c0e..9ac0538b65 100644 --- a/web/app/components/workflow/nodes/data-source/types.ts +++ b/web/app/components/workflow/nodes/data-source/types.ts @@ -1,11 +1,26 @@ -import type { CommonNodeType } from '@/app/components/workflow/types' +import type { CommonNodeType, ValueSelector } from '@/app/components/workflow/types' import type { RAGPipelineVariables } from '@/models/pipeline' import type { CollectionType } from '@/app/components/tools/types' +export enum VarType { + variable = 'variable', + constant = 'constant', + mixed = 'mixed', +} + +export type ToolVarInputs = Record + export type DataSourceNodeType = CommonNodeType & { variables: RAGPipelineVariables - output_schema: Record + fileExtensions?: string[] provider_id: string provider_type: CollectionType - fileExtensions?: string[] + provider_name: string + datasource_name: string + datasource_label: string + datasource_parameters: ToolVarInputs + datasource_configurations: Record } diff --git a/web/app/components/workflow/nodes/knowledge-base/components/input-variable.tsx b/web/app/components/workflow/nodes/knowledge-base/components/input-variable.tsx deleted file mode 100644 index ae91041903..0000000000 --- a/web/app/components/workflow/nodes/knowledge-base/components/input-variable.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { memo } from 'react' -import { useTranslation } from 'react-i18next' -import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker' -import { Field } from '@/app/components/workflow/nodes/_base/components/layout' -import type { ValueSelector } from '@/app/components/workflow/types' - -type InputVariableProps = { - nodeId: string - inputVariable?: string[] - onInputVariableChange: (inputVariable: string | ValueSelector) => void - readonly?: boolean -} -const InputVariable = ({ - nodeId, - inputVariable = [], - onInputVariableChange, - readonly = false, -}: InputVariableProps) => { - const { t } = useTranslation() - - return ( - - - - ) -} -export default memo(InputVariable) diff --git a/web/app/components/workflow/nodes/knowledge-base/panel.tsx b/web/app/components/workflow/nodes/knowledge-base/panel.tsx index e47f6d3ebb..245c63fd3d 100644 --- a/web/app/components/workflow/nodes/knowledge-base/panel.tsx +++ b/web/app/components/workflow/nodes/knowledge-base/panel.tsx @@ -2,11 +2,11 @@ import type { FC } from 'react' import { memo, } from 'react' +import { useTranslation } from 'react-i18next' import type { KnowledgeBaseNodeType } from './types' import { IndexMethodEnum, } from './types' -import InputVariable from './components/input-variable' import ChunkStructure from './components/chunk-structure' import IndexMethod from './components/index-method' import RetrievalSetting from './components/retrieval-setting' @@ -14,16 +14,19 @@ import EmbeddingModel from './components/embedding-model' import { useConfig } from './hooks/use-config' import type { NodePanelProps } from '@/app/components/workflow/types' import { + BoxGroup, + BoxGroupField, Group, - GroupWithBox, } from '@/app/components/workflow/nodes/_base/components/layout' import Split from '../_base/components/split' import { useNodesReadOnly } from '@/app/components/workflow/hooks' +import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker' const Panel: FC> = ({ id, data, }) => { + const { t } = useTranslation() const { nodesReadOnly } = useNodesReadOnly() const { handleChunkStructureChange, @@ -42,14 +45,24 @@ const Panel: FC> = ({ return (
- - + - + > = ({ readonly={nodesReadOnly} /> - +
> = ({ readonly={nodesReadOnly} />
-
+
) } diff --git a/web/app/components/workflow/types.ts b/web/app/components/workflow/types.ts index 15e438b0c0..0519a6dddb 100644 --- a/web/app/components/workflow/types.ts +++ b/web/app/components/workflow/types.ts @@ -5,7 +5,10 @@ import type { XYPosition, } from 'reactflow' import type { Resolution, TransferMethod } from '@/types/app' -import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types' +import type { + DataSourceDefaultValue, + ToolDefaultValue, +} from '@/app/components/workflow/block-selector/types' import type { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types' import type { FileResponse, NodeTracing } from '@/types/workflow' import type { Collection, Tool } from '@/app/components/tools/types' @@ -96,6 +99,7 @@ export type CommonNodeType = { retry_config?: WorkflowRetryConfig default_value?: DefaultValueForm[] } & T & Partial> +& Partial> export type CommonEdgeType = { _hovering?: boolean @@ -311,7 +315,7 @@ export type NodeDefault = { checkValid: (payload: T, t: any, moreDataForCheckValid?: any) => { isValid: boolean; errorMessage?: string } } -export type OnSelectBlock = (type: BlockEnum, toolDefaultValue?: ToolDefaultValue) => void +export type OnSelectBlock = (type: BlockEnum, toolDefaultValue?: ToolDefaultValue | DataSourceDefaultValue) => void export enum WorkflowRunningStatus { Waiting = 'waiting', @@ -341,7 +345,7 @@ export type OnNodeAdd = ( nodeType: BlockEnum sourceHandle?: string targetHandle?: string - toolDefaultValue?: ToolDefaultValue + toolDefaultValue?: ToolDefaultValue | DataSourceDefaultValue }, oldNodesPayload: { prevNodeId?: string