Commit 1f41521c authored by StyleZhang's avatar StyleZhang

workflow run

parent e686d422
......@@ -5,7 +5,9 @@ import Workflow from '@/app/components/workflow'
const Page = () => {
return (
<div className='w-full h-full overflow-x-auto'>
<Workflow />
</div>
)
}
export default memo(Page)
......@@ -36,7 +36,7 @@ const CustomEdge = ({
id={id}
path={edgePath}
style={{
stroke: (selected || data?._connectedNodeIsHovering) ? '#2970FF' : '#D0D5DD',
stroke: (selected || data?._connectedNodeIsHovering || data?._runned) ? '#2970FF' : '#D0D5DD',
strokeWidth: 2,
}}
/>
......
......@@ -27,8 +27,11 @@ const Header: FC = () => {
const { handleRunSetting } = useWorkflowRun()
const handleShowFeatures = useCallback(() => {
if (runningStatus)
return
useStore.setState({ showFeaturesPanel: true })
}, [])
}, [runningStatus])
const handleGoBackToEdit = useCallback(() => {
handleRunSetting(true)
......@@ -77,6 +80,7 @@ const Header: FC = () => {
className={`
mr-2 px-3 py-0 h-8 bg-white text-[13px] font-medium text-gray-700
border-[0.5px] border-gray-200 shadow-xs
${runningStatus && '!cursor-not-allowed opacity-50'}
`}
onClick={handleShowFeatures}
>
......
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useStore } from '../store'
import Button from '@/app/components/base/button'
import {
PortalToFollowElem,
......@@ -9,6 +10,7 @@ import {
const Publish = () => {
const { t } = useTranslation()
const runningStatus = useStore(s => s.runningStatus)
const [open, setOpen] = useState(false)
return (
......@@ -21,10 +23,18 @@ const Publish = () => {
crossAxis: -5,
}}
>
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
<PortalToFollowElemTrigger onClick={() => {
if (runningStatus)
return
setOpen(v => !v)
}}>
<Button
type='primary'
className='px-3 py-0 h-8 text-[13px] font-medium'
className={`
px-3 py-0 h-8 text-[13px] font-medium
${runningStatus && 'cursor-not-allowed opacity-50'}
`}
>
{t('workflow.common.publish')}
</Button>
......
import { useCallback } from 'react'
import {
useCallback,
useRef,
} from 'react'
import {
useReactFlow,
useStoreApi,
......@@ -9,6 +12,7 @@ import {
NodeRunningStatus,
WorkflowRunningStatus,
} from '../types'
import { NODE_WIDTH } from '../constants'
import { useStore as useAppStore } from '@/app/components/app/store'
import type { IOtherOptions } from '@/service/base'
import { ssePost } from '@/service/base'
......@@ -16,24 +20,78 @@ import { ssePost } from '@/service/base'
export const useWorkflowRun = () => {
const store = useStoreApi()
const reactflow = useReactFlow()
const workflowContainerRef = useRef<HTMLDivElement>(null)
const handleLoadBackupDraft = useCallback(() => {
const {
setNodes,
setEdges,
} = store.getState()
const { setViewport } = reactflow
const { backupDraft } = useStore.getState()
if (backupDraft) {
const {
nodes,
edges,
viewport,
} = backupDraft
setNodes(nodes)
setEdges(edges)
setViewport(viewport)
}
}, [store, reactflow])
const handleRunSetting = useCallback((shouldClear?: boolean) => {
useStore.setState({ runningStatus: shouldClear ? undefined : WorkflowRunningStatus.Waiting })
const { setNodes, getNodes } = store.getState()
const {
setNodes,
getNodes,
edges,
setEdges,
} = store.getState()
if (shouldClear) {
handleLoadBackupDraft()
}
else {
const newNodes = produce(getNodes(), (draft) => {
draft.forEach((node) => {
node.data._runningStatus = shouldClear ? undefined : NodeRunningStatus.Waiting
})
})
setNodes(newNodes)
}, [store])
const newEdges = produce(edges, (draft) => {
draft.forEach((edge) => {
edge.data = { ...edge.data, _runned: false }
})
})
setEdges(newEdges)
}
}, [store, handleLoadBackupDraft])
const handleRun = useCallback((params: any, callback?: IOtherOptions) => {
const {
getNodes,
setNodes,
edges,
setEdges,
} = store.getState()
const { getViewport } = reactflow
const { setBackupDraft } = useStore.getState()
const appDetail = useAppStore.getState().appDetail
const workflowContainer = document.getElementById('workflow-container')
const {
clientWidth,
clientHeight,
} = workflowContainer!
setBackupDraft({
nodes: getNodes(),
edges,
viewport: getViewport(),
})
let url = ''
if (appDetail?.mode === 'advanced-chat')
......@@ -69,19 +127,28 @@ export const useWorkflowRun = () => {
getViewport,
setViewport,
} = reactflow
const viewport = getViewport()
const currentNodeIndex = nodes.findIndex(node => node.id === data.node_id)
const position = nodes[currentNodeIndex].position
const zoom = 1
const currentNode = nodes[currentNodeIndex]
const position = currentNode.position
const zoom = 0.5
setViewport({
zoom,
x: 200 / viewport.zoom - position.x,
y: 200 / viewport.zoom - position.y,
x: (((clientWidth - 400) / 2 - NODE_WIDTH / 2) / viewport.zoom - position.x) * zoom,
y: ((clientHeight / 2 - currentNode.height! / 2) / viewport.zoom - position.y) * zoom,
})
const newNodes = produce(nodes, (draft) => {
draft[currentNodeIndex].data._runningStatus = NodeRunningStatus.Running
})
setNodes(newNodes)
const newEdges = produce(edges, (draft) => {
const edge = draft.find(edge => edge.target === data.node_id)
if (edge)
edge.data = { ...edge.data, _runned: true }
})
setEdges(newEdges)
},
onNodeFinished: ({ data }) => {
const newNodes = produce(getNodes(), (draft) => {
......@@ -99,5 +166,6 @@ export const useWorkflowRun = () => {
return {
handleRunSetting,
handleRun,
workflowContainerRef,
}
}
......@@ -100,7 +100,10 @@ const Workflow: FC<WorkflowProps> = memo(({
useKeyPress('Backspace', handleEdgeDelete)
return (
<div className='relative w-full h-full bg-[#F0F2F7]'>
<div
id='workflow-container'
className='relative w-full min-w-[960px] h-full bg-[#F0F2F7]'
>
<Header />
<Panel />
<Operator />
......
......@@ -35,7 +35,7 @@ const Operator = () => {
<div
className={`
ml-[1px] flex items-center justify-center w-8 h-8 cursor-pointer hover:bg-black/5 rounded-lg
${runningStatus && '!cursor-not-allowed'}
${runningStatus && '!cursor-not-allowed opacity-50'}
`}
onClick={goLayout}
>
......
......@@ -100,7 +100,7 @@ const ZoomInOut: FC = () => {
<div className={`
flex items-center px-2 h-8 cursor-pointer text-[13px] hover:bg-gray-50 rounded-lg
${open && 'bg-gray-50'}
${runningStatus && '!cursor-not-allowed'}
${runningStatus && '!cursor-not-allowed opacity-50'}
`}>
<SearchLg className='mr-1 w-4 h-4' />
<div className='w-[34px]'>{parseFloat(`${zoom * 100}`).toFixed(0)}%</div>
......
import { memo } from 'react'
import Run from '../run'
import { useStore } from '../store'
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
const Record = () => {
const { currentSequenceNumber, setCurrentSequenceNumber, workflowRunId, setWorkflowRunId } = useStore()
const { currentSequenceNumber, workflowRunId } = useStore()
return (
<div className='flex flex-col w-[400px] h-full rounded-2xl border-[0.5px] border-gray-200 shadow-xl bg-white'>
<div className='flex items-center justify-between p-4 pb-1 text-base font-semibold text-gray-900'>
{`Test Run#${currentSequenceNumber}`}
<div
className='flex items-center justify-center w-6 h-6 cursor-pointer'
onClick={() => {
setWorkflowRunId('')
setCurrentSequenceNumber(0)
}}
>
<XClose className='w-4 h-4 text-gray-500' />
</div>
</div>
<Run runID={workflowRunId} />
</div>
......
import { create } from 'zustand'
import type { Viewport } from 'reactflow'
import type {
HelpLineHorizontalPosition,
HelpLineVerticalPosition,
......@@ -9,7 +10,11 @@ import type {
ToolsMap,
} from './block-selector/types'
import { Mode } from './types'
import type { WorkflowRunningStatus } from './types'
import type {
Edge,
Node,
WorkflowRunningStatus,
} from './types'
type State = {
mode: Mode
......@@ -27,6 +32,11 @@ type State = {
runningStatus?: WorkflowRunningStatus
showInputsPanel: boolean
inputs: Record<string, string>
backupDraft?: {
nodes: Node[]
edges: Edge[]
viewport: Viewport
}
}
type Action = {
......@@ -45,6 +55,7 @@ type Action = {
setRunningStatus: (runningStatus?: WorkflowRunningStatus) => void
setShowInputsPanel: (showInputsPanel: boolean) => void
setInputs: (inputs: Record<string, string>) => void
setBackupDraft: (backupDraft?: State['backupDraft']) => void
}
export const useStore = create<State & Action>(set => ({
......@@ -78,4 +89,6 @@ export const useStore = create<State & Action>(set => ({
setShowInputsPanel: showInputsPanel => set(() => ({ showInputsPanel })),
inputs: {},
setInputs: inputs => set(() => ({ inputs })),
backupDraft: undefined,
setBackupDraft: backupDraft => set(() => ({ backupDraft })),
}))
......@@ -38,6 +38,7 @@ export type CommonNodeType<T = {}> = {
export type CommonEdgeType = {
_hovering: boolean
_connectedNodeIsHovering: boolean
_runned?: boolean
}
export type Node<T = {}> = ReactFlowNode<CommonNodeType<T>>
......
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