diff --git a/web/src/pages/data-flow/canvas/edge/index.tsx b/web/src/pages/data-flow/canvas/edge/index.tsx index 3e1b57e85..40c8bb14d 100644 --- a/web/src/pages/data-flow/canvas/edge/index.tsx +++ b/web/src/pages/data-flow/canvas/edge/index.tsx @@ -11,7 +11,7 @@ import useGraphStore from '../../store'; import { useFetchAgent } from '@/hooks/use-agent-request'; import { cn } from '@/lib/utils'; import { useMemo } from 'react'; -import { NodeHandleId, Operator } from '../../constant'; +import { Operator } from '../../constant'; function InnerButtonEdge({ id, @@ -27,7 +27,6 @@ function InnerButtonEdge({ markerEnd, selected, data, - sourceHandleId, }: EdgeProps>) { const deleteEdgeById = useGraphStore((state) => state.deleteEdgeById); const [edgePath, labelX, labelY] = getBezierPath({ @@ -49,47 +48,32 @@ function InnerButtonEdge({ // highlight the nodes that the workflow passes through const { data: flowDetail } = useFetchAgent(); - const graphPath = useMemo(() => { - // TODO: this will be called multiple times + const showHighlight = useMemo(() => { const path = flowDetail?.dsl?.path ?? []; - // The second to last - const previousGraphPath: string[] = path.at(-2) ?? []; - let graphPath: string[] = path.at(-1) ?? []; - // The last of the second to last article - const previousLatestElement = previousGraphPath.at(-1); - if (previousGraphPath.length > 0 && previousLatestElement) { - graphPath = [previousLatestElement, ...graphPath]; - } - return Array.isArray(graphPath) ? graphPath : []; - }, [flowDetail.dsl?.path]); - - const highlightStyle = useMemo(() => { - const idx = graphPath.findIndex((x) => x === source); + const idx = path.findIndex((x) => x === target); if (idx !== -1) { - // The set of elements following source - const slicedGraphPath = graphPath.slice(idx + 1); - if (slicedGraphPath.some((x) => x === target)) { - return { strokeWidth: 1, stroke: 'red' }; + let index = idx - 1; + while (index >= 0) { + if (path[index] === source) { + return { strokeWidth: 1, stroke: 'var(--accent-primary)' }; + } + index--; } + return {}; } return {}; - }, [source, target, graphPath]); + }, [flowDetail?.dsl?.path, source, target]); const visible = useMemo(() => { - return ( - data?.isHovered && - sourceHandleId !== NodeHandleId.Tool && - sourceHandleId !== NodeHandleId.AgentBottom && // The connection between the agent node and the tool node does not need to display the delete button - !target.startsWith(Operator.Tool) - ); - }, [data?.isHovered, sourceHandleId, target]); + return data?.isHovered && source !== Operator.Begin; + }, [data?.isHovered, source]); return ( <> diff --git a/web/src/pages/data-flow/canvas/index.tsx b/web/src/pages/data-flow/canvas/index.tsx index e57087377..edc998a69 100644 --- a/web/src/pages/data-flow/canvas/index.tsx +++ b/web/src/pages/data-flow/canvas/index.tsx @@ -42,8 +42,8 @@ import { ButtonEdge } from './edge'; import styles from './index.less'; import { RagNode } from './node'; import { BeginNode } from './node/begin-node'; -import { ContextNode } from './node/context-node'; import { NextStepDropdown } from './node/dropdown/next-step-dropdown'; +import { ExtractorNode } from './node/extractor-node'; import { HierarchicalMergerNode } from './node/hierarchical-merger-node'; import NoteNode from './node/note-node'; import ParserNode from './node/parser-node'; @@ -58,7 +58,7 @@ export const nodeTypes: NodeTypes = { tokenizerNode: TokenizerNode, splitterNode: SplitterNode, hierarchicalMergerNode: HierarchicalMergerNode, - contextNode: ContextNode, + contextNode: ExtractorNode, }; const edgeTypes = { @@ -316,7 +316,6 @@ function DataFlowCanvas({ drawerVisible, hideDrawer, showLogSheet }: IProps) { loading={running} > )} - {/* {logSheetVisible && } */} ); } diff --git a/web/src/pages/data-flow/canvas/node/context-node.tsx b/web/src/pages/data-flow/canvas/node/context-node.tsx deleted file mode 100644 index ebeec332e..000000000 --- a/web/src/pages/data-flow/canvas/node/context-node.tsx +++ /dev/null @@ -1 +0,0 @@ -export { RagNode as ContextNode } from './index'; diff --git a/web/src/pages/data-flow/canvas/node/dropdown/next-step-dropdown.tsx b/web/src/pages/data-flow/canvas/node/dropdown/next-step-dropdown.tsx index 403980b13..2e9c95f26 100644 --- a/web/src/pages/data-flow/canvas/node/dropdown/next-step-dropdown.tsx +++ b/web/src/pages/data-flow/canvas/node/dropdown/next-step-dropdown.tsx @@ -24,7 +24,7 @@ import { useMemo, useRef, } from 'react'; -import { Operator } from '../../../constant'; +import { Operator, SingleOperators } from '../../../constant'; import { AgentInstanceContext, HandleContext } from '../../../context'; import OperatorIcon from '../../../operator-icon'; @@ -112,18 +112,12 @@ function OperatorItemList({ return ; } -const singleOperators = [ - Operator.Tokenizer, - Operator.Splitter, - Operator.HierarchicalMerger, - Operator.Parser, -]; // Limit the number of operators of a certain type on the canvas to only one function useRestrictSingleOperatorOnCanvas() { const list: Operator[] = []; const { findNodeByName } = useGraphStore((state) => state); - singleOperators.forEach((operator) => { + SingleOperators.forEach((operator) => { if (!findNodeByName(operator)) { list.push(operator); } diff --git a/web/src/pages/data-flow/canvas/node/extractor-node.tsx b/web/src/pages/data-flow/canvas/node/extractor-node.tsx new file mode 100644 index 000000000..b8746a163 --- /dev/null +++ b/web/src/pages/data-flow/canvas/node/extractor-node.tsx @@ -0,0 +1 @@ +export { RagNode as ExtractorNode } from './index'; diff --git a/web/src/pages/data-flow/canvas/node/index.tsx b/web/src/pages/data-flow/canvas/node/index.tsx index c7f2b2933..7a26d4ecc 100644 --- a/web/src/pages/data-flow/canvas/node/index.tsx +++ b/web/src/pages/data-flow/canvas/node/index.tsx @@ -1,7 +1,8 @@ import { IRagNode } from '@/interfaces/database/flow'; import { NodeProps, Position } from '@xyflow/react'; -import { memo } from 'react'; -import { NodeHandleId } from '../../constant'; +import { memo, useMemo } from 'react'; +import { NodeHandleId, SingleOperators } from '../../constant'; +import useGraphStore from '../../store'; import { CommonHandle } from './handle'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import NodeHeader from './node-header'; @@ -14,8 +15,17 @@ function InnerRagNode({ isConnectable = true, selected, }: NodeProps) { + const getOperatorTypeFromId = useGraphStore( + (state) => state.getOperatorTypeFromId, + ); + + const showCopy = useMemo(() => { + const operatorName = getOperatorTypeFromId(id); + return SingleOperators.every((x) => x !== operatorName); + }, [getOperatorTypeFromId, id]); + return ( - + ) { - return ( - - - - - - - - ); -} - -export const LogicNode = memo(InnerLogicNode); diff --git a/web/src/pages/data-flow/canvas/node/parser-node.tsx b/web/src/pages/data-flow/canvas/node/parser-node.tsx index 4dceabce9..512632db6 100644 --- a/web/src/pages/data-flow/canvas/node/parser-node.tsx +++ b/web/src/pages/data-flow/canvas/node/parser-node.tsx @@ -2,12 +2,10 @@ import { IRagNode } from '@/interfaces/database/flow'; import { NodeProps, Position } from '@xyflow/react'; import { memo } from 'react'; import { NodeHandleId } from '../../constant'; -import { needsSingleStepDebugging } from '../../utils'; import { CommonHandle } from './handle'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import NodeHeader from './node-header'; import { NodeWrapper } from './node-wrapper'; -import { ToolBar } from './toolbar'; function ParserNode({ id, @@ -16,33 +14,26 @@ function ParserNode({ selected, }: NodeProps) { return ( - - - - - - - + + + + + ); } diff --git a/web/src/pages/data-flow/canvas/node/tokenizer-node.tsx b/web/src/pages/data-flow/canvas/node/tokenizer-node.tsx index f6481b86a..710ddef1f 100644 --- a/web/src/pages/data-flow/canvas/node/tokenizer-node.tsx +++ b/web/src/pages/data-flow/canvas/node/tokenizer-node.tsx @@ -2,7 +2,6 @@ import { IRagNode } from '@/interfaces/database/flow'; import { NodeProps, Position } from '@xyflow/react'; import { memo } from 'react'; import { NodeHandleId } from '../../constant'; -import { needsSingleStepDebugging } from '../../utils'; import { CommonHandle } from './handle'; import { LeftHandleStyle } from './handle-icon'; import NodeHeader from './node-header'; @@ -20,7 +19,8 @@ function TokenizerNode({ selected={selected} id={id} label={data.label} - showRun={needsSingleStepDebugging(data.label)} + showRun={false} + showCopy={false} > store.deleteNodeById); @@ -66,10 +68,13 @@ export function ToolBar({ - )}{' '} - - - + )} + {showCopy && ( + + + + )} + diff --git a/web/src/pages/data-flow/constant.tsx b/web/src/pages/data-flow/constant.tsx index e0096b609..950227e60 100644 --- a/web/src/pages/data-flow/constant.tsx +++ b/web/src/pages/data-flow/constant.tsx @@ -325,13 +325,14 @@ export const CategorizeAnchorPointPositions = [ // key is the source of the edge, value is the target of the edge // no connection lines are allowed between key and value -export const RestrictedUpstreamMap = { - [Operator.Begin]: [], +export const RestrictedUpstreamMap: Record = { + [Operator.Begin]: [] as Operator[], [Operator.Parser]: [Operator.Begin], [Operator.Splitter]: [Operator.Begin], [Operator.HierarchicalMerger]: [Operator.Begin], [Operator.Tokenizer]: [Operator.Begin], [Operator.Extractor]: [Operator.Begin], + [Operator.Note]: [Operator.Begin], }; export const NodeMap = { @@ -411,3 +412,10 @@ export const FileTypeSuffixMap = { 'ape', ], }; + +export const SingleOperators = [ + Operator.Tokenizer, + Operator.Splitter, + Operator.HierarchicalMerger, + Operator.Parser, +];