Commit 7655d7f6 authored by StyleZhang's avatar StyleZhang

run

parent 84e2071a
......@@ -5,7 +5,10 @@ import {
} from 'react'
import { useTranslation } from 'react-i18next'
import { useStore } from '../store'
import { useIsChatMode } from '../hooks'
import {
useIsChatMode,
useWorkflow,
} from '../hooks'
import RunAndHistory from './run-and-history'
import EditingTitle from './editing-title'
import RunningTitle from './running-title'
......@@ -21,11 +24,16 @@ const Header: FC = () => {
const appSidebarExpand = useAppStore(s => s.appSidebarExpand)
const isChatMode = useIsChatMode()
const runningStatus = useStore(s => s.runningStatus)
const { handleRunInit } = useWorkflow()
const handleShowFeatures = useCallback(() => {
useStore.setState({ showFeaturesPanel: true })
}, [])
const handleGoBackToEdit = useCallback(() => {
handleRunInit(true)
}, [handleRunInit])
return (
<div
className='absolute top-0 left-0 flex items-center justify-between px-3 w-full h-14 z-10'
......@@ -54,7 +62,7 @@ const Header: FC = () => {
mr-2 px-3 py-0 h-8 bg-white text-[13px] font-medium text-primary-600
border-[0.5px] border-gray-200 shadow-xs
`}
onClick={() => useStore.setState({ runningStatus: undefined })}
onClick={handleGoBackToEdit}
>
<ArrowNarrowLeft className='mr-1 w-4 h-4' />
{t('workflow.common.goBackToEdit')}
......
......@@ -2,7 +2,10 @@ import type { FC } from 'react'
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import { useStore } from '../store'
import { useIsChatMode } from '../hooks'
import {
useIsChatMode,
useWorkflow,
} from '../hooks'
import { WorkflowRunningStatus } from '../types'
import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
import { ClockPlay } from '@/app/components/base/icons/src/vender/line/time'
......@@ -51,11 +54,12 @@ RunMode.displayName = 'RunMode'
const PreviewMode = memo(() => {
const { t } = useTranslation()
const { handleRunInit } = useWorkflow()
const runningStatus = useStore(s => s.runningStatus)
const isRunning = runningStatus === WorkflowRunningStatus.Running
const handleClick = () => {
useStore.setState({ runningStatus: WorkflowRunningStatus.Succeeded })
handleRunInit()
}
return (
......
......@@ -79,11 +79,19 @@ export const useWorkflow = () => {
if (appId) {
const features = featuresStore!.getState().features
const nodes = produce(getNodes(), (draft) => {
draft.forEach((node) => {
Object.keys(node.data).forEach((key) => {
if (key.startsWith('_'))
delete node.data[key]
})
})
})
syncWorkflowDraft({
url: `/apps/${appId}/workflows/draft`,
params: {
graph: {
nodes: getNodes(),
nodes,
edges,
viewport: getViewport(),
},
......@@ -622,6 +630,17 @@ export const useWorkflow = () => {
setEdges(newEdges)
}, [store])
const handleRunInit = useCallback((shouldClear?: boolean) => {
useStore.setState({ runningStatus: shouldClear ? undefined : WorkflowRunningStatus.Waiting })
const { setNodes, getNodes } = store.getState()
const newNodes = produce(getNodes(), (draft) => {
draft.forEach((node) => {
node.data._runningStatus = shouldClear ? undefined : NodeRunningStatus.Waiting
})
})
setNodes(newNodes)
}, [store])
return {
handleSyncWorkflowDraft,
handleLayout,
......@@ -644,6 +663,8 @@ export const useWorkflow = () => {
handleEdgeLeave,
handleEdgeDelete,
handleEdgesChange,
handleRunInit,
}
}
......@@ -674,6 +695,12 @@ export const useWorkflowRun = () => {
useStore.setState({ runningStatus: WorkflowRunningStatus.Running })
useStore.setState({ taskId: task_id })
useStore.setState({ workflowRunId: workflow_run_id })
const newNodes = produce(getNodes(), (draft) => {
draft.forEach((node) => {
node.data._runningStatus = NodeRunningStatus.Waiting
})
})
setNodes(newNodes)
},
onWorkflowFinished: ({ data }) => {
useStore.setState({ runningStatus: data.status as WorkflowRunningStatus })
......
......@@ -63,6 +63,7 @@ const Workflow: FC<WorkflowProps> = memo(({
viewport,
}) => {
const showFeaturesPanel = useStore(state => state.showFeaturesPanel)
const runningStatus = useStore(s => s.runningStatus)
const {
handleSyncWorkflowDraft,
......@@ -116,6 +117,11 @@ const Workflow: FC<WorkflowProps> = memo(({
deleteKeyCode={null}
nodeDragThreshold={1}
defaultViewport={viewport}
panOnDrag={!runningStatus}
nodesDraggable={!runningStatus}
nodesConnectable={!runningStatus}
nodesFocusable={!runningStatus}
edgesFocusable={!runningStatus}
>
<Background
gap={[14, 14]}
......
......@@ -18,7 +18,6 @@ const Operator = () => {
height: 80,
}}
className='!static !m-0 !w-[128px] !h-[80px] !border-[0.5px] !border-black/[0.08] !rounded-lg !shadow-lg'
pannable
/>
<div className='flex items-center mt-1 p-0.5 rounded-lg border-[0.5px] border-gray-100 bg-white shadow-lg text-gray-500'>
<ZoomInOut />
......
......@@ -30,12 +30,17 @@ const Panel: FC = () => {
return {
showWorkflowInfoPanel: !isChatMode && !selectedNode && !runningStatus,
showNodePanel: !!selectedNode && !runningStatus,
showDebugAndPreviewPanel: isChatMode && !selectedNode && !runningStatus,
showDebugAndPreviewPanel: isChatMode && runningStatus,
}
}, [selectedNode, isChatMode, runningStatus])
return (
<div className='absolute top-14 right-0 bottom-2 flex z-10'>
<div
className={`
absolute top-14 right-0 bottom-2 flex pr-2 z-10
${showRunHistory && '!pr-0'}
`}
>
{
showInputsPanel && (
<InputsPanel />
......
......@@ -7,7 +7,10 @@ import { useNodes } from 'reactflow'
import FormItem from '../nodes/_base/components/before-run-form/form-item'
import { BlockEnum } from '../types'
import { useStore } from '../store'
import { useWorkflowRun } from '../hooks'
import {
useWorkflow,
useWorkflowRun,
} from '../hooks'
import type { StartNodeType } from '../nodes/start/types'
import Button from '@/app/components/base/button'
......@@ -16,6 +19,7 @@ const InputsPanel = () => {
const nodes = useNodes<StartNodeType>()
const inputs = useStore(s => s.inputs)
const run = useWorkflowRun()
const { handleRunInit } = useWorkflow()
const startNode = nodes.find(node => node.data.type === BlockEnum.Start)
const variables = startNode?.data.variables || []
......@@ -32,6 +36,7 @@ const InputsPanel = () => {
const handleRun = () => {
handleCancel()
handleRunInit()
run({ inputs })
}
......
import { memo } from 'react'
import dayjs from 'dayjs'
import { useTranslation } from 'react-i18next'
import useSWR from 'swr'
import { WorkflowRunningStatus } from '../types'
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
import { AlertCircle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
import { CheckCircle } from '@/app/components/base/icons/src/vender/solid/general'
import { useStore } from '@/app/components/workflow/store'
import { useStore as useAppStore } from '@/app/components/app/store'
import { fetchWorkflowRunHistory } from '@/service/workflow'
import Loading from '@/app/components/base/loading'
const RunHistory = () => {
const { t } = useTranslation()
const appDetail = useAppStore(state => state.appDetail)
const { data, isLoading } = useSWR(appDetail ? `/apps/${appDetail.id}/workflow-runs` : null, fetchWorkflowRunHistory)
if (!appDetail)
return null
return (
<div className='ml-2 w-[200px] h-full bg-white border-[0.5px] border-gray-200 shadow-xl rounded-l-2xl'>
<div className='flex items-center justify-between px-4 pt-3 text-base font-semibold text-gray-900'>
<div className='flex flex-col ml-2 w-[200px] h-full bg-white border-[0.5px] border-gray-200 shadow-xl rounded-l-2xl'>
<div className='shrink-0 flex items-center justify-between px-4 pt-3 text-base font-semibold text-gray-900'>
{t('workflow.common.runHistory')}
<div
className='flex items-center justify-center w-6 h-6 cursor-pointer'
......@@ -20,23 +30,42 @@ const RunHistory = () => {
<XClose className='w-4 h-4 text-gray-500' />
</div>
</div>
<div className='p-2'>
<div
className='flex mb-0.5 px-2 py-[7px] rounded-lg hover:bg-primary-50 cursor-pointer'
onClick={() => useStore.setState({ runTaskId: '1' })}
>
{
appDetail?.mode === 'advanced-chat' && (
<AlertCircle className='mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#F79009]' />
)
}
<div>
<div className='flex items-center text-[13px] font-medium text-primary-600 leading-[18px]'>Test Run#6</div>
<div className='flex items-center text-xs text-gray-500 leading-[18px]'>
Evan · 30 min ago
</div>
{
isLoading && (
<div className='grow flex items-center justify-center h-full'>
<Loading />
</div>
</div>
)
}
<div className='grow p-2 overflow-y-auto'>
{
data?.data.map(item => (
<div
key={item.id}
className='flex mb-0.5 px-2 py-[7px] rounded-lg hover:bg-primary-50 cursor-pointer'
onClick={() => useStore.setState({ workflowRunId: item.id })}
>
{
appDetail?.mode === 'workflow' && item.status === WorkflowRunningStatus.Failed && (
<AlertCircle className='mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#F79009]' />
)
}
{
appDetail?.mode === 'workflow' && item.status === WorkflowRunningStatus.Succeeded && (
<CheckCircle className='mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#12B76A]' />
)
}
<div>
<div className='flex items-center text-[13px] font-medium text-primary-600 leading-[18px]'>
Test Run#{item.sequence_number}
</div>
<div className='flex items-center text-xs text-gray-500 leading-[18px]'>
{item.created_by_account.name} · {dayjs((item.finished_at || item.created_at) * 1000).fromNow()}
</div>
</div>
</div>
))
}
</div>
</div>
)
......
......@@ -150,6 +150,7 @@ export enum Mode {
}
export enum WorkflowRunningStatus {
Waiting = 'waiting',
Running = 'running',
Succeeded = 'succeeded',
Failed = 'failed',
......@@ -157,6 +158,7 @@ export enum WorkflowRunningStatus {
}
export enum NodeRunningStatus {
Waiting = 'waiting',
Running = 'running',
Succeeded = 'succeeded',
Failed = 'failed',
......
......@@ -3,6 +3,7 @@ import { get, post } from './base'
import type { CommonResponse } from '@/models/common'
import type {
FetchWorkflowDraftResponse,
WorkflowRunHistoryResponse,
} from '@/types/workflow'
export const fetchWorkflowDraft: Fetcher<FetchWorkflowDraftResponse, string> = (url) => {
......@@ -16,3 +17,7 @@ export const syncWorkflowDraft = ({ url, params }: { url: string; params: Pick<F
export const fetchNodesDefaultConfigs: Fetcher<any, string> = (url) => {
return get<any>(url)
}
export const fetchWorkflowRunHistory: Fetcher<WorkflowRunHistoryResponse, string> = (url) => {
return get<WorkflowRunHistoryResponse>(url)
}
......@@ -131,3 +131,31 @@ export type TextReplaceResponse = {
text: string
}
}
export type WorkflowRunHistory = {
id: string
sequence_number: number
version: string
graph: {
nodes: Node[]
edges: Edge[]
viewport?: Viewport
}
inputs: Record<string, string>
status: string
outputs: Record<string, any>
error?: string
elapsed_time: number
total_tokens: number
total_steps: number
created_at: number
finished_at: number
created_by_account: {
id: string
name: string
email: string
}
}
export type WorkflowRunHistoryResponse = {
data: WorkflowRunHistory[]
}
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