From 671654da71d7e65860f11c8133e3cdeb3fd63491 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Wed, 21 Feb 2024 12:27:50 +0800 Subject: [PATCH] add node --- .../workflow/block-selector/context.tsx | 18 ++- .../nodes/_base/components/add-node/hooks.ts | 40 ++++++ .../nodes/_base/components/add-node/index.tsx | 116 ++++++++++++++++++ .../nodes/_base/components/next-step.tsx | 79 ++++++------ .../components/workflow/nodes/_base/node.tsx | 52 ++++---- 5 files changed, 233 insertions(+), 72 deletions(-) create mode 100644 web/app/components/workflow/nodes/_base/components/add-node/hooks.ts create mode 100644 web/app/components/workflow/nodes/_base/components/add-node/index.tsx diff --git a/web/app/components/workflow/block-selector/context.tsx b/web/app/components/workflow/block-selector/context.tsx index e8261ff9f6..f16aa5bb8a 100644 --- a/web/app/components/workflow/block-selector/context.tsx +++ b/web/app/components/workflow/block-selector/context.tsx @@ -22,6 +22,7 @@ type UpdateParams = { from?: string placement?: Placement offset?: OffsetOptions + open?: boolean className?: string callback?: OnSelect } @@ -30,6 +31,9 @@ export type BlockSelectorContextValue = { open: boolean setOpen: (open: boolean) => void referenceRef: any + floatingRef: any + floatingStyles: React.CSSProperties + getFloatingProps: any handleToggle: (v: UpdateParams) => void } @@ -38,6 +42,9 @@ export const BlockSelectorContext = createContext({ open: false, setOpen: () => {}, referenceRef: null, + floatingRef: null, + floatingStyles: {}, + getFloatingProps: () => {}, handleToggle: () => {}, }) export const useBlockSelectorContext = () => useContext(BlockSelectorContext) @@ -73,13 +80,17 @@ export const BlockSelectorContextProvider = ({ const handleToggle = useCallback(({ from, + open, placement, offset, className, callback, }: UpdateParams) => { setFrom(from || 'node') - setOpen(v => !v) + if (open !== undefined) + setOpen(open) + else + setOpen(v => !v) setPlacement(placement || 'top') setOffsetValue(offset || 0) setClassName(className || '') @@ -99,10 +110,13 @@ export const BlockSelectorContextProvider = ({ setOpen, handleToggle, referenceRef: refs.setReference, + floatingRef: refs.setFloating, + floatingStyles, + getFloatingProps, }}> {children} { - open && ( + open && (from === 'node' || from === 'panel') && (
{ + const [isOpen, setIsOpen] = useState(false) + const [dismissEnable, setDismissEnable] = useState(true) + const { refs, floatingStyles, context } = useFloating({ + placement: 'bottom', + strategy: 'fixed', + open: isOpen, + onOpenChange: setIsOpen, + middleware: [ + flip(), + shift(), + offset(4), + ], + }) + const dismiss = useDismiss(context, { + enabled: dismissEnable, + }) + const { getFloatingProps } = useInteractions([ + dismiss, + ]) + + return { + refs, + floatingStyles, + getFloatingProps, + isOpen, + setIsOpen, + setDismissEnable, + } +} diff --git a/web/app/components/workflow/nodes/_base/components/add-node/index.tsx b/web/app/components/workflow/nodes/_base/components/add-node/index.tsx new file mode 100644 index 0000000000..8e91423173 --- /dev/null +++ b/web/app/components/workflow/nodes/_base/components/add-node/index.tsx @@ -0,0 +1,116 @@ +import type { FC, MouseEvent } from 'react' +import { + memo, + useMemo, +} from 'react' +import { FloatingPortal } from '@floating-ui/react' +import { useBlockSelectorContext } from '../../../../block-selector/context' +import type { + BlockEnum, + Node, +} from '../../../../types' +import { useAddBranch } from './hooks' +import { Plus02 } from '@/app/components/base/icons/src/vender/line/general' + +type AddNodeProps = { + outgoers: Node[] + onAddNextNode: (type: BlockEnum) => void + branches?: { id: string; name: string }[] +} +const AddNode: FC = ({ + onAddNextNode, + branches, +}) => { + const { + refs, + isOpen, + setIsOpen, + setDismissEnable, + floatingStyles, + getFloatingProps, + } = useAddBranch() + const { + from, + open, + referenceRef, + handleToggle, + } = useBlockSelectorContext() + const hasBranches = branches && !!branches.length + const handleAdd = (e: MouseEvent) => { + e.stopPropagation() + + if (hasBranches) + return setIsOpen(v => !v) + + handleToggle({ + placement: 'right', + offset: 6, + callback: onAddNextNode, + }) + } + const buttonRef = useMemo(() => { + if (hasBranches) + return refs.setReference + + if (from === 'node') + return referenceRef + + return null + }, [from, hasBranches, referenceRef, refs.setReference]) + const buttonShouldShow = useMemo(() => { + if (hasBranches && isOpen) + return true + + return open && from === 'node' + }, [from, hasBranches, isOpen, open]) + + return ( + <> + + { + isOpen && hasBranches && ( + +
+ { + branches.map(branch => ( +
{ + setDismissEnable(false) + handleToggle({ + open: true, + placement: 'right', + offset: 6, + callback: onAddNextNode, + }) + }} + > + {branch.name} +
+ )) + } +
+
+ ) + } + + ) +} + +export default memo(AddNode) diff --git a/web/app/components/workflow/nodes/_base/components/next-step.tsx b/web/app/components/workflow/nodes/_base/components/next-step.tsx index 20f7539698..9e757c764c 100644 --- a/web/app/components/workflow/nodes/_base/components/next-step.tsx +++ b/web/app/components/workflow/nodes/_base/components/next-step.tsx @@ -6,10 +6,8 @@ import { } from 'react' import { getOutgoers } from 'reactflow' import BlockIcon from '../../../block-icon' -import type { - BlockEnum, - Node, -} from '../../../types' +import type { Node } from '../../../types' +import { BlockEnum } from '../../../types' import { useWorkflowContext } from '../../../context' import { useBlockSelectorContext } from '../../../block-selector/context' import { Plus } from '@/app/components/base/icons/src/vender/line/general' @@ -47,7 +45,44 @@ const NextStep: FC = ({
{ - !outgoers.length && ( + !!outgoers.length && outgoers.map(outgoer => ( +
+ +
{outgoer.data.name}
+
{ + handleToggle({ + from: 'panel', + className: 'w-[328px]', + placement: 'top-end', + offset: { + mainAxis: 6, + crossAxis: 8, + }, + }) + }} + > + +
+
+ )) + } + { + (!outgoers.length || selectedNode.data.type === BlockEnum.IfElse) && (
{ handleToggle({ @@ -70,40 +105,6 @@ const NextStep: FC = ({
) } - { - !!outgoers.length && outgoers.map(outgoer => ( -
- -
{outgoer.data.name}
-
{ - handleToggle({ - from: 'panel', - className: 'w-[328px]', - placement: 'top-end', - offset: 6, - }) - }} - > - -
-
- )) - }
) diff --git a/web/app/components/workflow/nodes/_base/node.tsx b/web/app/components/workflow/nodes/_base/node.tsx index 95c8d81baa..69e471f4a0 100644 --- a/web/app/components/workflow/nodes/_base/node.tsx +++ b/web/app/components/workflow/nodes/_base/node.tsx @@ -11,11 +11,10 @@ import { import type { NodeProps } from 'reactflow' import { getOutgoers } from 'reactflow' import { useWorkflowContext } from '../../context' -import type { BlockEnum } from '../../types' -import { useBlockSelectorContext } from '../../block-selector/context' +import { BlockEnum } from '../../types' import NodeControl from '../../node-control' import BlockIcon from '../../block-icon' -import { Plus02 } from '@/app/components/base/icons/src/vender/line/general' +import AddNode from './components/add-node/index' type BaseNodeProps = { children: ReactElement @@ -33,12 +32,6 @@ const BaseNode: FC = ({ handleSelectedNodeIdChange, handleAddNextNode, } = useWorkflowContext() - const { - from, - open, - referenceRef, - handleToggle, - } = useBlockSelectorContext() const currentNode = useMemo(() => { return nodes.find(node => node.id === nodeId) }, [nodeId, nodes]) @@ -48,6 +41,20 @@ const BaseNode: FC = ({ const handleSelectBlock = useCallback((type: BlockEnum) => { handleAddNextNode(currentNode!, type) }, [currentNode, handleAddNextNode]) + const branches = useMemo(() => { + if (data.type === BlockEnum.IfElse) { + return [ + { + id: '1', + name: 'Is True', + }, + { + id: '2', + name: 'Is False', + }, + ] + } + }, [data]) return (
= ({
Define the initial parameters for launching a workflow
- { - !outgoers.length && ( -
{ - e.stopPropagation() - handleToggle({ - placement: 'right', - offset: 6, - callback: handleSelectBlock, - }) - }} - className={` - hidden absolute -bottom-2 left-1/2 -translate-x-1/2 items-center justify-center - w-4 h-4 rounded-full bg-primary-600 cursor-pointer z-10 group-hover:flex - ${open && from === 'node' && '!flex'} - `} - > - -
- ) - } +
) }