diff --git a/web/app/components/base/features/types.ts b/web/app/components/base/features/types.ts index 1912eb6609..74dfecd0cd 100644 --- a/web/app/components/base/features/types.ts +++ b/web/app/components/base/features/types.ts @@ -1,3 +1,5 @@ +import type { TransferMethod } from '@/types/app' + export type EnabledOrDisabled = { enabled: boolean } @@ -26,7 +28,7 @@ export type SensitiveWordAvoidance = EnabledOrDisabled & { export type FileUpload = { image: EnabledOrDisabled & { number_limits: number - transfer_methods: string[] + transfer_methods: TransferMethod[] } } diff --git a/web/app/components/workflow/block-icon.tsx b/web/app/components/workflow/block-icon.tsx index 6a5c664858..6d353f6219 100644 --- a/web/app/components/workflow/block-icon.tsx +++ b/web/app/components/workflow/block-icon.tsx @@ -1,7 +1,6 @@ import type { FC } from 'react' import { memo } from 'react' import { BlockEnum } from './types' -import { useStore } from './store' import { Answer, Code, @@ -21,7 +20,7 @@ type BlockIconProps = { type: BlockEnum size?: string className?: string - toolProviderId?: string + toolIcon?: string | { content: string; background: string } } const ICON_CONTAINER_CLASSNAME_SIZE_MAP: Record = { sm: 'w-5 h-5 rounded-md shadow-xs', @@ -60,17 +59,14 @@ const BlockIcon: FC = ({ type, size = 'sm', className, - toolProviderId, + toolIcon, }) => { - const toolsets = useStore(s => s.toolsets) - const icon = toolsets.find(toolset => toolset.id === toolProviderId)?.icon - return (
@@ -80,15 +76,15 @@ const BlockIcon: FC = ({ ) } { - type === BlockEnum.Tool && icon && ( + type === BlockEnum.Tool && toolIcon && ( <> { - typeof icon === 'string' + typeof toolIcon === 'string' ? (
) @@ -96,8 +92,8 @@ const BlockIcon: FC = ({ ) } diff --git a/web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx b/web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx index d306f9eb02..4fe571652f 100644 --- a/web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx +++ b/web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx @@ -8,8 +8,9 @@ import CodeEditor from '../editor/code-editor' import { CodeLanguage } from '../../../code/types' import Select from '@/app/components/base/select' import TextGenerationImageUploader from '@/app/components/base/image-uploader/text-generation-image-uploader' -import { Resolution, TransferMethod } from '@/types/app' +import { Resolution } from '@/types/app' import { Trash03 } from '@/app/components/base/icons/src/vender/line/general' +import { useFeatures } from '@/app/components/base/features/hooks' type Props = { payload: InputVar @@ -25,6 +26,7 @@ const FormItem: FC = ({ className, }) => { const { type } = payload + const fileSettings = useFeatures(s => s.features.file) const handleContextItemChange = useCallback((index: number) => { return (newValue: any) => { const newValues = produce(value, (draft: any) => { @@ -105,10 +107,8 @@ const FormItem: FC = ({ type === InputVarType.files && ( onChange(files.filter(file => file.progress !== -1).map(fileItem => ({ type: 'image', diff --git a/web/app/components/workflow/nodes/_base/components/next-step/index.tsx b/web/app/components/workflow/nodes/_base/components/next-step/index.tsx index de2ea1c824..d90269548f 100644 --- a/web/app/components/workflow/nodes/_base/components/next-step/index.tsx +++ b/web/app/components/workflow/nodes/_base/components/next-step/index.tsx @@ -1,4 +1,7 @@ -import { memo } from 'react' +import { + memo, + useMemo, +} from 'react' import { getConnectedEdges, getOutgoers, @@ -6,6 +9,7 @@ import { useStoreApi, } from 'reactflow' import BlockIcon from '../../../../block-icon' +import { useStore } from '../../../../store' import type { Branch, Node, @@ -21,9 +25,15 @@ type NextStepProps = { const NextStep = ({ selectedNode, }: NextStepProps) => { + const data = selectedNode.data + const toolsets = useStore(s => s.toolsets) + const toolIcon = useMemo(() => { + if (data.type === BlockEnum.Tool) + return toolsets.find(toolset => toolset.id === data.provider_id)?.icon + }, [data, toolsets]) const store = useStoreApi() - const branches = selectedNode.data._targetBranches || [] - const nodeWithBranches = selectedNode.data.type === BlockEnum.IfElse || selectedNode.data.type === BlockEnum.QuestionClassifier + const branches = data._targetBranches || [] + const nodeWithBranches = data.type === BlockEnum.IfElse || data.type === BlockEnum.QuestionClassifier const edges = useEdges() const outgoers = getOutgoers(selectedNode as Node, store.getState().getNodes(), edges) const connectedEdges = getConnectedEdges([selectedNode] as Node[], edges).filter(edge => edge.source === selectedNode!.id) @@ -33,7 +43,7 @@ const NextStep = ({
diff --git a/web/app/components/workflow/nodes/_base/components/next-step/item.tsx b/web/app/components/workflow/nodes/_base/components/next-step/item.tsx index 837cac1bbb..8cd206e734 100644 --- a/web/app/components/workflow/nodes/_base/components/next-step/item.tsx +++ b/web/app/components/workflow/nodes/_base/components/next-step/item.tsx @@ -1,6 +1,7 @@ import { memo, useCallback, + useMemo, } from 'react' import { useTranslation } from 'react-i18next' import { union } from 'lodash-es' @@ -15,6 +16,8 @@ import { useNodesInteractions, } from '@/app/components/workflow/hooks' import Button from '@/app/components/base/button' +import { useStore } from '@/app/components/workflow/store' +import { BlockEnum } from '@/app/components/workflow/types' type ItemProps = { nodeId: string @@ -31,6 +34,11 @@ const Item = ({ const { t } = useTranslation() const { handleNodeChange } = useNodesInteractions() const nodesExtraData = useNodesExtraData() + const toolsets = useStore(s => s.toolsets) + const toolIcon = useMemo(() => { + if (data.type === BlockEnum.Tool) + return toolsets.find(toolset => toolset.id === data.provider_id)?.icon + }, [data, toolsets]) const availablePrevNodes = nodesExtraData[data.type].availablePrevNodes const availableNextNodes = nodesExtraData[data.type].availableNextNodes const handleSelect = useCallback((type, toolDefaultValue) => { @@ -65,7 +73,7 @@ const Item = ({ }
{data.title}
diff --git a/web/app/components/workflow/nodes/_base/node.tsx b/web/app/components/workflow/nodes/_base/node.tsx index 2fbc82fc39..cbd1e5a85d 100644 --- a/web/app/components/workflow/nodes/_base/node.tsx +++ b/web/app/components/workflow/nodes/_base/node.tsx @@ -5,12 +5,14 @@ import type { import { cloneElement, memo, + useMemo, } from 'react' import type { NodeProps } from '../../types' import { BlockEnum, NodeRunningStatus, } from '../../types' +import { useStore } from '../../store' import { NodeSourceHandle, NodeTargetHandle, @@ -32,6 +34,12 @@ const BaseNode: FC = ({ data, children, }) => { + const toolsets = useStore(s => s.toolsets) + const toolIcon = useMemo(() => { + if (data.type === BlockEnum.Tool) + return toolsets.find(toolset => toolset.id === data.provider_id)?.icon + }, [data, toolsets]) + return (
= ({ className='shrink-0 mr-2' type={data.type} size='md' - toolProviderId={data.provider_id} + toolIcon={toolIcon} />
= ({ const nodesExtraData = useNodesExtraData() const availableNextNodes = nodesExtraData[data.type].availableNextNodes + const toolsets = useStore(s => s.toolsets) + const toolIcon = useMemo(() => { + if (data.type === BlockEnum.Tool) + return toolsets.find(toolset => toolset.id === data.provider_id)?.icon + }, [data, toolsets]) + const { handleNodeDataUpdate, handleNodeDataUpdateWithSyncDraft, @@ -62,7 +71,7 @@ const BasePanel: FC = ({ { const { t } = useTranslation() const workflowStore = useWorkflowStore() + const fileSettings = useFeatures(s => s.features.file) const nodes = useNodes() const inputs = useStore(s => s.inputs) + const files = useStore(s => s.files) const { handleRun, handleRunSetting, } = useWorkflowRun() const startNode = nodes.find(node => node.data.type === BlockEnum.Start) - const variables = startNode?.data.variables || [] + const startVariables = startNode?.data.variables - const handleValueChange = (variable: string, v: string) => { - workflowStore.getState().setInputs({ - ...inputs, - [variable]: v, - }) + const variables = useMemo(() => { + const data = startVariables || [] + if (fileSettings.image.enabled) { + return [ + ...data, + { + type: InputVarType.files, + variable: '__image', + required: true, + label: 'files', + }, + ] + } + + return data + }, [fileSettings.image.enabled, startVariables]) + + const handleValueChange = (variable: string, v: any) => { + if (variable === '__image') { + workflowStore.setState({ + files: v, + }) + } + else { + workflowStore.getState().setInputs({ + ...inputs, + [variable]: v, + }) + } } const handleCancel = useCallback(() => { @@ -40,7 +71,7 @@ const InputsPanel = () => { const doRun = () => { handleCancel() handleRunSetting() - handleRun({ inputs }) + handleRun({ inputs, files }) } return ( diff --git a/web/app/components/workflow/store.ts b/web/app/components/workflow/store.ts index df97791691..89a4f44f2d 100644 --- a/web/app/components/workflow/store.ts +++ b/web/app/components/workflow/store.ts @@ -16,6 +16,7 @@ import type { import type { Edge, Node, + RunFile, WorkflowRunningStatus, } from './types' import { WorkflowContext } from './context' @@ -36,6 +37,7 @@ type State = { runningStatus?: WorkflowRunningStatus showInputsPanel: boolean inputs: Record + files: RunFile[] backupDraft?: { nodes: Node[] edges: Edge[] @@ -63,6 +65,7 @@ type Action = { setRunningStatus: (runningStatus?: WorkflowRunningStatus) => void setShowInputsPanel: (showInputsPanel: boolean) => void setInputs: (inputs: Record) => void + setFiles: (files: RunFile[]) => void setBackupDraft: (backupDraft?: State['backupDraft']) => void setNotInitialWorkflow: (notInitialWorkflow: boolean) => void setNodesDefaultConfigs: (nodesDefaultConfigs: Record) => void @@ -102,6 +105,8 @@ export const createWorkflowStore = () => { setShowInputsPanel: showInputsPanel => set(() => ({ showInputsPanel })), inputs: {}, setInputs: inputs => set(() => ({ inputs })), + files: [], + setFiles: files => set(() => ({ files })), backupDraft: undefined, setBackupDraft: backupDraft => set(() => ({ backupDraft })), notInitialWorkflow: false, diff --git a/web/app/components/workflow/types.ts b/web/app/components/workflow/types.ts index 67e20139b7..eb48766993 100644 --- a/web/app/components/workflow/types.ts +++ b/web/app/components/workflow/types.ts @@ -2,6 +2,7 @@ import type { Edge as ReactFlowEdge, Node as ReactFlowNode, } from 'reactflow' +import type { TransferMethod } from '@/types/app' import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types' import type { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types' @@ -211,3 +212,10 @@ export type CheckValidRes = { isValid: boolean errorMessage?: string } + +export type RunFile = { + type: string + transfer_method: TransferMethod[] + url?: string + upload_file_id?: string +}