feat: workflow remove preview mode (#3941)

This commit is contained in:
zxhlyh
2024-04-28 17:09:56 +08:00
committed by GitHub
parent 0940f01634
commit 8e4989ed03
33 changed files with 549 additions and 309 deletions

View File

@@ -5,18 +5,25 @@ import {
useMemo,
useState,
} from 'react'
import { useStore } from '../../store'
import {
useStore,
useWorkflowStore,
} from '../../store'
import { useWorkflowRun } from '../../hooks'
import UserInput from './user-input'
import Chat from '@/app/components/base/chat/chat'
import type { ChatItem } from '@/app/components/base/chat/types'
import { fetchConvesationMessages } from '@/service/debug'
import { useStore as useAppStore } from '@/app/components/app/store'
import Loading from '@/app/components/base/loading'
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
const ChatRecord = () => {
const [fetched, setFetched] = useState(false)
const [chatList, setChatList] = useState([])
const appDetail = useAppStore(s => s.appDetail)
const workflowStore = useWorkflowStore()
const { handleLoadBackupDraft } = useWorkflowRun()
const historyWorkflowData = useStore(s => s.historyWorkflowData)
const currentConversationID = historyWorkflowData?.conversation_id
@@ -79,6 +86,15 @@ const ChatRecord = () => {
<>
<div className='shrink-0 flex items-center justify-between p-4 pb-1 text-base font-semibold text-gray-900'>
{`TEST CHAT#${historyWorkflowData?.sequence_number}`}
<div
className='flex justify-center items-center w-6 h-6 cursor-pointer'
onClick={() => {
handleLoadBackupDraft()
workflowStore.setState({ historyWorkflowData: undefined })
}}
>
<XClose className='w-4 h-4 text-gray-500' />
</div>
</div>
<div className='grow h-0'>
<Chat

View File

@@ -3,10 +3,17 @@ import {
useRef,
} from 'react'
import { useKeyPress } from 'ahooks'
import cn from 'classnames'
import { useTranslation } from 'react-i18next'
import {
useEdgesInteractions,
useNodesInteractions,
useWorkflowInteractions,
} from '../../hooks'
import ChatWrapper from './chat-wrapper'
import Button from '@/app/components/base/button'
import { RefreshCcw01 } from '@/app/components/base/icons/src/vender/line/arrows'
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
export type ChatWrapperRefType = {
handleRestart: () => void
@@ -14,33 +21,56 @@ export type ChatWrapperRefType = {
const DebugAndPreview = () => {
const { t } = useTranslation()
const chatRef = useRef({ handleRestart: () => {} })
const { handleCancelDebugAndPreviewPanel } = useWorkflowInteractions()
const { handleNodeCancelRunningStatus } = useNodesInteractions()
const { handleEdgeCancelRunningStatus } = useEdgesInteractions()
const handleRestartChat = () => {
handleNodeCancelRunningStatus()
handleEdgeCancelRunningStatus()
chatRef.current.handleRestart()
}
useKeyPress('shift.r', () => {
chatRef.current.handleRestart()
handleRestartChat()
}, {
exactMatch: true,
})
return (
<div
className={`
flex flex-col w-[400px] rounded-l-2xl h-full border border-black/[0.02] shadow-xl
`}
className={cn(
'flex flex-col w-[400px] rounded-l-2xl h-full border border-black/[0.02]',
)}
style={{
background: 'linear-gradient(156deg, rgba(242, 244, 247, 0.80) 0%, rgba(242, 244, 247, 0.00) 99.43%), var(--white, #FFF)',
}}
>
<div className='shrink-0 flex items-center justify-between px-4 pt-3 pb-2 font-semibold text-gray-900'>
<div className='shrink-0 flex items-center justify-between pl-4 pr-3 pt-3 pb-2 font-semibold text-gray-900'>
{t('workflow.common.debugAndPreview').toLocaleUpperCase()}
<Button
className='pl-2.5 pr-[7px] h-8 bg-white border-[0.5px] border-gray-200 shadow-xs rounded-lg text-[13px] text-primary-600 font-semibold'
onClick={() => chatRef.current.handleRestart()}
>
<RefreshCcw01 className='mr-1 w-3.5 h-3.5' />
{t('common.operation.refresh')}
<div className='ml-2 px-1 leading-[18px] rounded-md border border-gray-200 bg-gray-50 text-[11px] text-gray-500 font-medium'>Shift</div>
<div className='ml-0.5 px-1 leading-[18px] rounded-md border border-gray-200 bg-gray-50 text-[11px] text-gray-500 font-medium'>R</div>
</Button>
<div className='flex items-center'>
<Button
className='px-2 h-8 bg-white border-[0.5px] border-gray-200 shadow-xs rounded-lg text-xs text-gray-700 font-medium'
onClick={() => handleRestartChat()}
>
<RefreshCcw01 className='shrink-0 mr-1 w-3 h-3 text-gray-500' />
<div
className='grow truncate uppercase'
title={t('common.operation.refresh') || ''}
>
{t('common.operation.refresh')}
</div>
<div className='shrink-0 ml-1 px-1 leading-[18px] rounded-md border border-gray-200 bg-gray-50 text-[11px] text-gray-500 font-medium'>Shift</div>
<div className='shrink-0 ml-0.5 px-1 leading-[18px] rounded-md border border-gray-200 bg-gray-50 text-[11px] text-gray-500 font-medium'>R</div>
</Button>
<div className='mx-3 w-[1px] h-3.5 bg-gray-200'></div>
<div
className='flex items-center justify-center w-6 h-6 cursor-pointer'
onClick={handleCancelDebugAndPreviewPanel}
>
<XClose className='w-4 h-4 text-gray-500' />
</div>
</div>
</div>
<div className='grow rounded-b-2xl overflow-y-auto'>
<ChatWrapper ref={chatRef} />

View File

@@ -56,12 +56,13 @@ const UserInput = () => {
expanded && (
<div className='py-2 text-[13px] text-gray-900'>
{
variables.map(variable => (
variables.map((variable, index) => (
<div
key={variable.variable}
className='mb-2 last-of-type:mb-0'
>
<FormItem
autoFocus={index === 0}
payload={variable}
value={inputs[variable.variable]}
onChange={v => handleValueChange(variable.variable, v)}

View File

@@ -1,9 +1,7 @@
import type { FC } from 'react'
import {
memo,
useMemo,
} from 'react'
import { memo } from 'react'
import { useNodes } from 'reactflow'
import cn from 'classnames'
import { useShallow } from 'zustand/react/shallow'
import type { CommonNodeType } from '../types'
import { Panel as NodePanel } from '../nodes'
@@ -23,9 +21,8 @@ const Panel: FC = () => {
const nodes = useNodes<CommonNodeType>()
const isChatMode = useIsChatMode()
const selectedNode = nodes.find(node => node.data.selected)
const showInputsPanel = useStore(s => s.showInputsPanel)
const workflowRunningData = useStore(s => s.workflowRunningData)
const historyWorkflowData = useStore(s => s.historyWorkflowData)
const showDebugAndPreviewPanel = useStore(s => s.showDebugAndPreviewPanel)
const isRestoring = useStore(s => s.isRestoring)
const {
enableShortcuts,
@@ -37,28 +34,13 @@ const Panel: FC = () => {
showMessageLogModal: state.showMessageLogModal,
setShowMessageLogModal: state.setShowMessageLogModal,
})))
const {
showNodePanel,
showDebugAndPreviewPanel,
showWorkflowPreview,
} = useMemo(() => {
return {
showNodePanel: !!selectedNode && !workflowRunningData && !historyWorkflowData && !showInputsPanel,
showDebugAndPreviewPanel: isChatMode && workflowRunningData && !historyWorkflowData,
showWorkflowPreview: !isChatMode && !historyWorkflowData && (workflowRunningData || showInputsPanel),
}
}, [
showInputsPanel,
selectedNode,
isChatMode,
workflowRunningData,
historyWorkflowData,
])
return (
<div
tabIndex={-1}
className='absolute top-14 right-0 bottom-2 flex z-10 outline-none'
className={cn(
'absolute top-14 right-0 bottom-2 flex z-10 outline-none',
)}
onFocus={disableShortcuts}
onBlur={enableShortcuts}
key={`${isRestoring}`}
@@ -76,6 +58,11 @@ const Panel: FC = () => {
/>
)
}
{
!!selectedNode && (
<NodePanel {...selectedNode!} />
)
}
{
historyWorkflowData && !isChatMode && (
<Record />
@@ -87,20 +74,15 @@ const Panel: FC = () => {
)
}
{
showDebugAndPreviewPanel && (
showDebugAndPreviewPanel && isChatMode && (
<DebugAndPreview />
)
}
{
showWorkflowPreview && (
showDebugAndPreviewPanel && !isChatMode && (
<WorkflowPreview />
)
}
{
showNodePanel && (
<NodePanel {...selectedNode!} />
)
}
</div>
)
}

View File

@@ -34,7 +34,6 @@ const InputsPanel = ({ onRun }: Props) => {
const workflowRunningData = useStore(s => s.workflowRunningData)
const {
handleRun,
handleRunSetting,
} = useWorkflowRun()
const startNode = nodes.find(node => node.data.type === BlockEnum.Start)
const startVariables = startNode?.data.variables
@@ -72,7 +71,6 @@ const InputsPanel = ({ onRun }: Props) => {
const doRun = () => {
onRun()
handleRunSetting()
handleRun({ inputs, files })
}
@@ -87,12 +85,13 @@ const InputsPanel = ({ onRun }: Props) => {
<>
<div className='px-4 pb-2'>
{
variables.map(variable => (
variables.map((variable, index) => (
<div
key={variable.variable}
className='mb-2 last-of-type:mb-0'
>
<FormItem
autoFocus={index === 0}
className='!block'
payload={variable}
value={inputs[variable.variable]}

View File

@@ -1,16 +1,31 @@
import { memo } from 'react'
import { memo, useCallback } from 'react'
import type { WorkflowDataUpdator } from '../types'
import Run from '../run'
import { useStore } from '../store'
import { useWorkflowInteractions } from '../hooks'
const Record = () => {
const historyWorkflowData = useStore(s => s.historyWorkflowData)
const { handleUpdateWorkflowCanvas } = useWorkflowInteractions()
const handleResultCallback = useCallback((res: any) => {
const graph: WorkflowDataUpdator = res.graph
handleUpdateWorkflowCanvas({
nodes: graph.nodes,
edges: graph.edges,
viewport: graph.viewport,
})
}, [handleUpdateWorkflowCanvas])
return (
<div className='flex flex-col w-[400px] h-full rounded-l-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#${historyWorkflowData?.sequence_number}`}
</div>
<Run runID={historyWorkflowData?.id || ''} />
<Run
runID={historyWorkflowData?.id || ''}
getResultCallback={handleResultCallback}
/>
</div>
)
}

View File

@@ -10,7 +10,7 @@ import OutputPanel from '../run/output-panel'
import ResultPanel from '../run/result-panel'
import TracingPanel from '../run/tracing-panel'
import {
useWorkflowRun,
useWorkflowInteractions,
} from '../hooks'
import { useStore } from '../store'
import {
@@ -22,9 +22,10 @@ import { XClose } from '@/app/components/base/icons/src/vender/line/general'
const WorkflowPreview = () => {
const { t } = useTranslation()
const { handleRunSetting } = useWorkflowRun()
const showInputsPanel = useStore(s => s.showInputsPanel)
const { handleCancelDebugAndPreviewPanel } = useWorkflowInteractions()
const workflowRunningData = useStore(s => s.workflowRunningData)
const showInputsPanel = useStore(s => s.showInputsPanel)
const showDebugAndPreviewPanel = useStore(s => s.showDebugAndPreviewPanel)
const [currentTab, setCurrentTab] = useState<string>(showInputsPanel ? 'INPUT' : 'TRACING')
const switchTab = async (tab: string) => {
@@ -34,6 +35,11 @@ const WorkflowPreview = () => {
const [height, setHieght] = useState(0)
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
if (showDebugAndPreviewPanel && showInputsPanel)
setCurrentTab('INPUT')
}, [showDebugAndPreviewPanel, showInputsPanel])
const adjustResultHeight = () => {
if (ref.current)
setHieght(ref.current?.clientHeight - 16 - 16 - 2 - 1)
@@ -49,11 +55,9 @@ const WorkflowPreview = () => {
`}>
<div className='flex items-center justify-between p-4 pb-1 text-base font-semibold text-gray-900'>
{`Test Run${!workflowRunningData?.result.sequence_number ? '' : `#${workflowRunningData?.result.sequence_number}`}`}
{showInputsPanel && workflowRunningData?.result?.status !== WorkflowRunningStatus.Running && (
<div className='p-1 cursor-pointer' onClick={() => handleRunSetting(true)}>
<XClose className='w-4 h-4 text-gray-500' />
</div>
)}
<div className='p-1 cursor-pointer' onClick={() => handleCancelDebugAndPreviewPanel()}>
<XClose className='w-4 h-4 text-gray-500' />
</div>
</div>
<div className='grow relative flex flex-col'>
<div className='shrink-0 flex items-center px-4 border-b-[0.5px] border-[rgba(0,0,0,0.05)]'>
@@ -107,7 +111,7 @@ const WorkflowPreview = () => {
'grow bg-white h-0 overflow-y-auto rounded-b-2xl',
(currentTab === 'RESULT' || currentTab === 'TRACING') && '!bg-gray-50',
)}>
{currentTab === 'INPUT' && (
{currentTab === 'INPUT' && showInputsPanel && (
<InputsPanel onRun={() => switchTab('RESULT')} />
)}
{currentTab === 'RESULT' && (