From 760ada399f69606214f5ace4069bce507711cf72 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Fri, 29 Mar 2024 18:07:54 +0800 Subject: [PATCH] checklist --- ...kflow-variable-block-replacement-block.tsx | 2 +- .../components/workflow/header/checklist.tsx | 124 ++++++++++++++- web/app/components/workflow/header/index.tsx | 10 +- web/app/components/workflow/panel/index.tsx | 8 - .../workflow/panel/workflow-info.tsx | 143 ------------------ 5 files changed, 130 insertions(+), 157 deletions(-) delete mode 100644 web/app/components/workflow/panel/workflow-info.tsx diff --git a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx index d0589a9485..a07d3cd98a 100644 --- a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx +++ b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/workflow-variable-block-replacement-block.tsx @@ -13,7 +13,7 @@ import { CustomTextNode } from '../custom-text/node' import { $createWorkflowVariableBlockNode } from './node' import { WorkflowVariableBlockNode } from './index' -const REGEX = /\{\{#(\d+|sys)(\.[a-zA-Z_][a-zA-Z0-9_]{0,29})+#\}\}/gi +const REGEX = /\{\{(#[a-zA-Z0-9_]{1,50}(\.[a-zA-Z_][a-zA-Z0-9_]{0,29}){1,10}#)\}\}/gi const WorkflowVariableBlockReplacementBlock = ({ getWorkflowNode = () => undefined, diff --git a/web/app/components/workflow/header/checklist.tsx b/web/app/components/workflow/header/checklist.tsx index 02ae026c31..8fe99180f6 100644 --- a/web/app/components/workflow/header/checklist.tsx +++ b/web/app/components/workflow/header/checklist.tsx @@ -1,16 +1,76 @@ import { memo, + useMemo, useState, } from 'react' +import { useTranslation } from 'react-i18next' +import { + getIncomers, + getOutgoers, + useEdges, + useNodes, +} from 'reactflow' +import BlockIcon from '../block-icon' +import { + useNodesExtraData, + useNodesInteractions, +} from '../hooks' +import type { CommonNodeType } from '../types' +import { BlockEnum } from '../types' +import { useStore } from '../store' import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, } from '@/app/components/base/portal-to-follow-elem' -import { Checklist } from '@/app/components/base/icons/src/vender/line/general' +import { + Checklist, + XClose, +} from '@/app/components/base/icons/src/vender/line/general' +import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback' const WorkflowChecklist = () => { + const { t } = useTranslation() const [open, setOpen] = useState(false) + const nodes = useNodes() + const edges = useEdges() + const nodesExtraData = useNodesExtraData() + const { handleNodeSelect } = useNodesInteractions() + const buildInTools = useStore(s => s.buildInTools) + const customTools = useStore(s => s.customTools) + + const needWarningNodes = useMemo(() => { + const list = [] + + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i] + const incomers = getIncomers(node, nodes, edges) + const outgoers = getOutgoers(node, nodes, edges) + const { errorMessage } = nodesExtraData[node.data.type].checkValid(node.data, t) + let toolIcon + + if (node.data.type === BlockEnum.Tool) { + if (node.data.provider_type === 'builtin') + toolIcon = buildInTools.find(tool => tool.id === node.data.provider_id)?.icon + + if (node.data.provider_type === 'custom') + toolIcon = customTools.find(tool => tool.id === node.data.provider_id)?.icon + } + + if (errorMessage || ((!incomers.length && !outgoers.length))) { + list.push({ + id: node.id, + type: node.data.type, + title: node.data.title, + toolIcon, + unConnected: !incomers.length && !outgoers.length, + errorMessage, + }) + } + } + + return list + }, [t, nodes, edges, nodesExtraData, buildInTools, customTools]) return ( { onOpenChange={setOpen} > setOpen(v => !v)}> -
+
{ } />
+
+ {needWarningNodes.length} +
- + +
+
+
{t('workflow.panel.checklist')}({needWarningNodes.length})
+
setOpen(false)} + > + +
+
+
+
{t('workflow.panel.checklistTip')}
+
+ { + needWarningNodes.map(node => ( +
handleNodeSelect(node.id)} + > +
+ + {node.title} +
+ { + node.unConnected && ( +
+
+ + {t('workflow.common.needConnecttip')} +
+
+ ) + } + { + node.errorMessage && ( +
+
+ + {node.errorMessage} +
+
+ ) + } +
+ )) + } +
+
+
+
) } diff --git a/web/app/components/workflow/header/index.tsx b/web/app/components/workflow/header/index.tsx index 4cd829fe67..27c54f71c0 100644 --- a/web/app/components/workflow/header/index.tsx +++ b/web/app/components/workflow/header/index.tsx @@ -119,7 +119,14 @@ const Header: FC = () => { {t('workflow.common.features')} - + { + !nodesReadOnly && ( + <> +
+ + + ) + }
) } @@ -150,7 +157,6 @@ const Header: FC = () => { > {t('workflow.common.restore')} - ) } diff --git a/web/app/components/workflow/panel/index.tsx b/web/app/components/workflow/panel/index.tsx index 618feddace..88426a3a0b 100644 --- a/web/app/components/workflow/panel/index.tsx +++ b/web/app/components/workflow/panel/index.tsx @@ -8,7 +8,6 @@ import type { CommonNodeType } from '../types' import { Panel as NodePanel } from '../nodes' import { useStore } from '../store' import { useIsChatMode } from '../hooks' -import WorkflowInfo from './workflow-info' import DebugAndPreview from './debug-and-preview' import RunHistory from './run-history' import Record from './record' @@ -28,13 +27,11 @@ const Panel: FC = () => { const historyWorkflowData = useStore(s => s.historyWorkflowData) const { currentLogItem, setCurrentLogItem, showMessageLogModal, setShowMessageLogModal } = useAppStore() const { - showWorkflowInfoPanel, showNodePanel, showDebugAndPreviewPanel, showWorkflowPreview, } = useMemo(() => { return { - showWorkflowInfoPanel: !selectedNode && !workflowRunningData && !historyWorkflowData, showNodePanel: !!selectedNode && !workflowRunningData && !historyWorkflowData, showDebugAndPreviewPanel: isChatMode && workflowRunningData && !historyWorkflowData, showWorkflowPreview: !isChatMode && workflowRunningData && !historyWorkflowData, @@ -91,11 +88,6 @@ const Panel: FC = () => { ) } - { - showWorkflowInfoPanel && ( - - ) - } { showRunHistory && ( diff --git a/web/app/components/workflow/panel/workflow-info.tsx b/web/app/components/workflow/panel/workflow-info.tsx deleted file mode 100644 index a4e720a631..0000000000 --- a/web/app/components/workflow/panel/workflow-info.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { - memo, - useMemo, -} from 'react' -import { useTranslation } from 'react-i18next' -import { - getIncomers, - getOutgoers, - useEdges, - useNodes, -} from 'reactflow' -import BlockIcon from '../block-icon' -import { useNodesExtraData } from '../hooks' -import type { CommonNodeType } from '../types' -import { BlockEnum } from '../types' -import { useStore } from '../store' -import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback' -import { FileCheck02 } from '@/app/components/base/icons/src/vender/line/files' -import { useStore as useAppStore } from '@/app/components/app/store' -import AppIcon from '@/app/components/base/app-icon' - -const WorkflowInfo = () => { - const { t } = useTranslation() - const appDetail = useAppStore(state => state.appDetail) - const nodes = useNodes() - const edges = useEdges() - const nodesExtraData = useNodesExtraData() - const buildInTools = useStore(s => s.buildInTools) - const customTools = useStore(s => s.customTools) - const needConnectNodes = nodes.filter((node) => { - const incomers = getIncomers(node, nodes, edges) - const outgoers = getOutgoers(node, nodes, edges) - - return !incomers.length && !outgoers.length - }) - - const needWarningNodes = useMemo(() => { - const list = [] - - for (let i = 0; i < nodes.length; i++) { - const node = nodes[i] - const incomers = getIncomers(node, nodes, edges) - const outgoers = getOutgoers(node, nodes, edges) - const { errorMessage } = nodesExtraData[node.data.type].checkValid(node.data, t) - let toolIcon - - if (node.data.type === BlockEnum.Tool) { - if (node.data.provider_type === 'builtin') - toolIcon = buildInTools.find(tool => tool.id === node.data.provider_id)?.icon - - if (node.data.provider_type === 'custom') - toolIcon = customTools.find(tool => tool.id === node.data.provider_id)?.icon - } - - if (errorMessage || ((!incomers.length && !outgoers.length))) { - list.push({ - id: node.id, - type: node.data.type, - title: node.data.title, - toolIcon, - unConnected: !incomers.length && !outgoers.length, - errorMessage, - }) - } - } - - return list - }, [t, nodes, edges, nodesExtraData, buildInTools, customTools]) - - if (!appDetail) - return null - - return ( -
-
-
- -
- {appDetail.name} -
-
-
- {appDetail.description} -
-
- - {t('workflow.panel.checklist')}({needConnectNodes.length}) -
-
-
-
- {t('workflow.panel.checklistTip')} -
-
- { - needWarningNodes.map(node => ( -
-
- - {node.title} -
- { - node.unConnected && ( -
-
- - {t('workflow.common.needConnecttip')} -
-
- ) - } - { - node.errorMessage && ( -
-
- - {node.errorMessage} -
-
- ) - } -
- )) - } -
-
-
- ) -} - -export default memo(WorkflowInfo)