Commit e307947d authored by StyleZhang's avatar StyleZhang

node control

parent 04ad1eef
...@@ -19,7 +19,8 @@ const Tools = ({ ...@@ -19,7 +19,8 @@ const Tools = ({
isCustom, isCustom,
onSelect, onSelect,
}: ToolsProps) => { }: ToolsProps) => {
const toolsets = useStore(state => state.toolsets).filter(toolset => toolset.type === (isCustom ? 'api' : 'builtin')) const totalToolsets = useStore(state => state.toolsets)
const toolsets = totalToolsets.filter(toolset => toolset.type === (isCustom ? 'api' : 'builtin'))
const setToolsets = useStore(state => state.setToolsets) const setToolsets = useStore(state => state.setToolsets)
const toolsMap = useStore(state => state.toolsMap) const toolsMap = useStore(state => state.toolsMap)
const setToolsMap = useStore(state => state.setToolsMap) const setToolsMap = useStore(state => state.setToolsMap)
......
import type { FC } from 'react' import type { FC } from 'react'
import { memo } from 'react'
import { useWorkflow } from '../../../hooks'
import { import {
DotsHorizontal, memo,
Loading02, useCallback,
} from '@/app/components/base/icons/src/vender/line/general' useState,
} from 'react'
import { useWorkflow } from '../../../hooks'
import type { Node } from '../../../types'
import { canRunBySingle } from '../../../utils'
import PanelOperator from './panel-operator'
import { Loading02 } from '@/app/components/base/icons/src/vender/line/general'
import { import {
Play, Play,
Stop, Stop,
} from '@/app/components/base/icons/src/vender/line/mediaAndDevices' } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
type NodeControlProps = { type NodeControlProps = Pick<Node, 'id' | 'data'>
isRunning?: boolean
nodeId: string
}
const NodeControl: FC<NodeControlProps> = ({ const NodeControl: FC<NodeControlProps> = ({
isRunning, id,
nodeId, data,
}) => { }) => {
const [open, setOpen] = useState(false)
const { handleNodeDataUpdate } = useWorkflow() const { handleNodeDataUpdate } = useWorkflow()
const handleOpenChange = useCallback((newOpen: boolean) => {
setOpen(newOpen)
}, [])
return ( return (
<div className='flex items-center px-0.5 h-6 bg-white rounded-lg border-[0.5px] border-gray-100 shadow-xs text-gray-500'> <div
{ className={`
isRunning && ( hidden group-hover:flex pb-1 absolute right-0 -top-7 h-7
<div className='flex items-center px-1 h-5 rounded-md bg-primary-50 text-xs font-medium text-primary-600'> ${data.selected && '!flex'}
<Loading02 className='mr-1 w-3 h-3 animate-spin' /> ${open && '!flex'}
RUNNING `}
</div> >
)
}
<div <div
className='flex items-center justify-center w-5 h-5 rounded-md cursor-pointer hover:bg-black/5' className='flex items-center px-0.5 h-6 bg-white rounded-lg border-[0.5px] border-gray-100 shadow-xs text-gray-500'
onClick={() => { onClick={e => e.stopPropagation()}
handleNodeDataUpdate({
id: nodeId,
data: { _isSingleRun: !isRunning },
})
}}
> >
{ {
isRunning data._isSingleRun && (
? <Stop className='w-3 h-3' /> <div className='flex items-center mr-1 px-1 h-5 rounded-md bg-primary-50 text-xs font-medium text-primary-600'>
: <Play className='w-3 h-3' /> <Loading02 className='mr-1 w-3 h-3 animate-spin' />
RUNNING
</div>
)
} }
</div> {
<div className='flex items-center justify-center w-5 h-5 rounded-md cursor-pointer hover:bg-black/5'> canRunBySingle(data.type) && (
<DotsHorizontal className='w-3 h-3' /> <div
className='flex items-center justify-center w-5 h-5 rounded-md cursor-pointer hover:bg-black/5'
onClick={() => {
handleNodeDataUpdate({
id,
data: { _isSingleRun: !data._isSingleRun },
})
}}
>
{
data._isSingleRun
? <Stop className='w-3 h-3' />
: <Play className='w-3 h-3' />
}
</div>
)
}
<PanelOperator
id={id}
data={data}
offset={0}
onOpenChange={handleOpenChange}
triggerClassName='!w-5 !h-5'
/>
</div> </div>
</div> </div>
) )
......
...@@ -9,6 +9,7 @@ import produce from 'immer' ...@@ -9,6 +9,7 @@ import produce from 'immer'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useEdges } from 'reactflow' import { useEdges } from 'reactflow'
import type { OffsetOptions } from '@floating-ui/react'
import ChangeBlock from './change-block' import ChangeBlock from './change-block'
import { useStore } from '@/app/components/workflow/store' import { useStore } from '@/app/components/workflow/store'
import { import {
...@@ -33,10 +34,19 @@ import { ...@@ -33,10 +34,19 @@ import {
type PanelOperatorProps = { type PanelOperatorProps = {
id: string id: string
data: Node['data'] data: Node['data']
triggerClassName?: string
offset?: OffsetOptions
onOpenChange?: (open: boolean) => void
} }
const PanelOperator = ({ const PanelOperator = ({
id, id,
data, data,
triggerClassName,
offset = {
mainAxis: 4,
crossAxis: 53,
},
onOpenChange,
}: PanelOperatorProps) => { }: PanelOperatorProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { locale } = useContext(I18n) const { locale } = useContext(I18n)
...@@ -86,22 +96,27 @@ const PanelOperator = ({ ...@@ -86,22 +96,27 @@ const PanelOperator = ({
return tool?.description[language] || '' return tool?.description[language] || ''
}, [data, nodesExtraData, toolsMap, language]) }, [data, nodesExtraData, toolsMap, language])
const handleOpenChange = useCallback((newOpen: boolean) => {
setOpen(newOpen)
if (onOpenChange)
onOpenChange(newOpen)
}, [onOpenChange])
return ( return (
<PortalToFollowElem <PortalToFollowElem
placement='bottom-end' placement='bottom-end'
offset={{ offset={offset}
mainAxis: 4,
crossAxis: 53,
}}
open={open} open={open}
onOpenChange={setOpen} onOpenChange={handleOpenChange}
> >
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}> <PortalToFollowElemTrigger onClick={() => handleOpenChange(!open)}>
<div <div
className={` className={`
flex items-center justify-center w-6 h-6 rounded-md cursor-pointer flex items-center justify-center w-6 h-6 rounded-md cursor-pointer
hover:bg-black/5 hover:bg-black/5
${open && 'bg-black/5'} ${open && 'bg-black/5'}
${triggerClassName}
`} `}
> >
<DotsHorizontal className='w-4 h-4 text-gray-700' /> <DotsHorizontal className='w-4 h-4 text-gray-700' />
...@@ -110,10 +125,14 @@ const PanelOperator = ({ ...@@ -110,10 +125,14 @@ const PanelOperator = ({
<PortalToFollowElemContent className='z-[11]'> <PortalToFollowElemContent className='z-[11]'>
<div className='w-[240px] border-[0.5px] border-gray-200 rounded-2xl shadow-xl bg-white'> <div className='w-[240px] border-[0.5px] border-gray-200 rounded-2xl shadow-xl bg-white'>
<div className='p-1'> <div className='p-1'>
<ChangeBlock {
nodeId={id} data.type !== BlockEnum.Start && (
sourceHandle={edge?.sourceHandle || 'source'} <ChangeBlock
/> nodeId={id}
sourceHandle={edge?.sourceHandle || 'source'}
/>
)
}
<div className='flex items-center px-3 h-8 text-sm text-gray-700 rounded-lg cursor-pointer hover:bg-gray-50'> <div className='flex items-center px-3 h-8 text-sm text-gray-700 rounded-lg cursor-pointer hover:bg-gray-50'>
{t('workflow.panel.helpLink')} {t('workflow.panel.helpLink')}
</div> </div>
...@@ -124,7 +143,10 @@ const PanelOperator = ({ ...@@ -124,7 +143,10 @@ const PanelOperator = ({
<div className='h-[1px] bg-gray-100'></div> <div className='h-[1px] bg-gray-100'></div>
<div className='p-1'> <div className='p-1'>
<div <div
className='flex items-center px-3 h-8 text-sm text-gray-700 rounded-lg cursor-pointer hover:bg-gray-50' className={`
flex items-center px-3 h-8 text-sm text-gray-700 rounded-lg cursor-pointer
hover:bg-rose-50 hover:text-red-500
`}
onClick={() => handleNodeDelete(id)} onClick={() => handleNodeDelete(id)}
> >
{t('common.operation.delete')} {t('common.operation.delete')}
......
...@@ -8,7 +8,6 @@ import { ...@@ -8,7 +8,6 @@ import {
} from 'react' } from 'react'
import type { NodeProps } from '../../types' import type { NodeProps } from '../../types'
import { BlockEnum } from '../../types' import { BlockEnum } from '../../types'
import { canRunBySingle } from '../../utils'
import { import {
NodeSourceHandle, NodeSourceHandle,
NodeTargetHandle, NodeTargetHandle,
...@@ -59,17 +58,10 @@ const BaseNode: FC<BaseNodeProps> = ({ ...@@ -59,17 +58,10 @@ const BaseNode: FC<BaseNodeProps> = ({
/> />
) )
} }
{ <NodeControl
canRunBySingle(data.type) id={id}
&& ( data={data}
<div className='hidden group-hover:flex pb-1 absolute right-0 -top-7 h-7'> />
<NodeControl
nodeId={id}
isRunning={data._isSingleRun}
/>
</div>
)
}
<div className='flex items-center px-3 pt-3 pb-2'> <div className='flex items-center px-3 pt-3 pb-2'>
<BlockIcon <BlockIcon
className='shrink-0 mr-2' className='shrink-0 mr-2'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment