mirror of https://github.com/langgenius/dify.git
Merge remote-tracking branch 'origin/feat/workflow' into feat/workflow
This commit is contained in:
commit
a647698c32
|
|
@ -78,7 +78,7 @@ const WorkflowChecklist = () => {
|
|||
placement='bottom-end'
|
||||
offset={{
|
||||
mainAxis: 12,
|
||||
crossAxis: -4,
|
||||
crossAxis: 4,
|
||||
}}
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
|
|
@ -174,7 +174,7 @@ const WorkflowChecklist = () => {
|
|||
}
|
||||
{
|
||||
!needWarningNodes.length && (
|
||||
<div className='mx-4 mb-3 py-4 rounded-lg bg-gray-50 text-gray-400 text-center'>
|
||||
<div className='mx-4 mb-3 py-4 rounded-lg bg-gray-50 text-gray-400 text-xs text-center'>
|
||||
<ChecklistSquare className='mx-auto mb-[5px] w-8 h-8 text-gray-300' />
|
||||
{t('workflow.panel.checklistResolved')}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,14 +16,12 @@ import {
|
|||
BlockEnum,
|
||||
WorkflowRunningStatus,
|
||||
} from '../types'
|
||||
import ViewHistory from './view-history'
|
||||
import {
|
||||
Play,
|
||||
StopCircle,
|
||||
} from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||
import { ClockPlay } from '@/app/components/base/icons/src/vender/line/time'
|
||||
import TooltipPlus from '@/app/components/base/tooltip-plus'
|
||||
import { Loading02 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import { useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
|
||||
const RunMode = memo(() => {
|
||||
|
|
@ -160,11 +158,7 @@ const PreviewMode = memo(() => {
|
|||
PreviewMode.displayName = 'PreviewMode'
|
||||
|
||||
const RunAndHistory: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const { setCurrentLogItem, setShowMessageLogModal } = useAppStore()
|
||||
const workflowStore = useWorkflowStore()
|
||||
const isChatMode = useIsChatMode()
|
||||
const showRunHistory = useStore(state => state.showRunHistory)
|
||||
|
||||
return (
|
||||
<div className='flex items-center px-0.5 h-8 rounded-lg border-[0.5px] border-gray-200 bg-white shadow-xs'>
|
||||
|
|
@ -175,23 +169,7 @@ const RunAndHistory: FC = () => {
|
|||
isChatMode && <PreviewMode />
|
||||
}
|
||||
<div className='mx-0.5 w-[0.5px] h-8 bg-gray-200'></div>
|
||||
<TooltipPlus
|
||||
popupContent={t('workflow.common.viewRunHistory')}
|
||||
>
|
||||
<div
|
||||
className={`
|
||||
flex items-center justify-center w-7 h-7 rounded-md hover:bg-black/5 cursor-pointer
|
||||
${showRunHistory && 'bg-primary-50'}
|
||||
`}
|
||||
onClick={() => {
|
||||
workflowStore.setState({ showRunHistory: !showRunHistory })
|
||||
setCurrentLogItem()
|
||||
setShowMessageLogModal(false)
|
||||
}}
|
||||
>
|
||||
<ClockPlay className={`w-4 h-4 ${showRunHistory ? 'text-primary-600' : 'text-gray-500'}`} />
|
||||
</div>
|
||||
</TooltipPlus>
|
||||
<ViewHistory />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,174 @@
|
|||
import {
|
||||
memo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import cn from 'classnames'
|
||||
import useSWR from 'swr'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
useIsChatMode,
|
||||
useWorkflow,
|
||||
useWorkflowRun,
|
||||
} from '../hooks'
|
||||
import { WorkflowRunningStatus } from '../types'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import TooltipPlus from '@/app/components/base/tooltip-plus'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import {
|
||||
ClockPlay,
|
||||
ClockPlaySlim,
|
||||
} from '@/app/components/base/icons/src/vender/line/time'
|
||||
import { CheckCircle, XClose } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { AlertCircle, AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
|
||||
import {
|
||||
fetcChatRunHistory,
|
||||
fetchWorkflowRunHistory,
|
||||
} from '@/service/workflow'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import {
|
||||
useStore,
|
||||
useWorkflowStore,
|
||||
} from '@/app/components/workflow/store'
|
||||
|
||||
const ViewHistory = () => {
|
||||
const { t } = useTranslation()
|
||||
const isChatMode = useIsChatMode()
|
||||
const [open, setOpen] = useState(false)
|
||||
const { formatTimeFromNow } = useWorkflow()
|
||||
const workflowStore = useWorkflowStore()
|
||||
const { appDetail, setCurrentLogItem, setShowMessageLogModal } = useAppStore()
|
||||
const historyWorkflowData = useStore(s => s.historyWorkflowData)
|
||||
const { handleBackupDraft } = useWorkflowRun()
|
||||
const { data: runList, isLoading: runListLoading } = useSWR((appDetail && !isChatMode) ? `/apps/${appDetail.id}/workflow-runs` : null, fetchWorkflowRunHistory)
|
||||
const { data: chatList, isLoading: chatListLoading } = useSWR((appDetail && isChatMode) ? `/apps/${appDetail.id}/advanced-chat/workflow-runs` : null, fetcChatRunHistory)
|
||||
|
||||
const data = isChatMode ? chatList : runList
|
||||
const isLoading = isChatMode ? chatListLoading : runListLoading
|
||||
|
||||
return (
|
||||
(
|
||||
<PortalToFollowElem
|
||||
placement='bottom-end'
|
||||
offset={{
|
||||
mainAxis: 4,
|
||||
crossAxis: 131,
|
||||
}}
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
|
||||
<TooltipPlus
|
||||
popupContent={t('workflow.common.viewRunHistory')}
|
||||
>
|
||||
<div
|
||||
className={`
|
||||
flex items-center justify-center w-7 h-7 rounded-md hover:bg-black/5 cursor-pointer
|
||||
${open && 'bg-primary-50'}
|
||||
`}
|
||||
onClick={() => {
|
||||
setCurrentLogItem()
|
||||
setShowMessageLogModal(false)
|
||||
}}
|
||||
>
|
||||
<ClockPlay className={`w-4 h-4 ${open ? 'text-primary-600' : 'text-gray-500'}`} />
|
||||
</div>
|
||||
</TooltipPlus>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[12]'>
|
||||
<div
|
||||
className='flex flex-col ml-2 w-[240px] bg-white border-[0.5px] border-gray-200 shadow-xl rounded-xl overflow-y-auto'
|
||||
style={{
|
||||
maxHeight: 'calc(2 / 3 * 100vh)',
|
||||
}}
|
||||
>
|
||||
<div className='sticky top-0 bg-white flex items-center justify-between px-4 pt-3 text-base font-semibold text-gray-900'>
|
||||
<div className='grow'>{t('workflow.common.runHistory')}</div>
|
||||
<div
|
||||
className='shrink-0 flex items-center justify-center w-6 h-6 cursor-pointer'
|
||||
onClick={() => {
|
||||
setCurrentLogItem()
|
||||
setShowMessageLogModal(false)
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<XClose className='w-4 h-4 text-gray-500' />
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
isLoading && (
|
||||
<div className='grow flex items-center justify-center h-full'>
|
||||
<Loading />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className='p-2'>
|
||||
{
|
||||
!data?.data.length && (
|
||||
<div className='py-12'>
|
||||
<ClockPlaySlim className='mx-auto mb-2 w-8 h-8 text-gray-300' />
|
||||
<div className='text-center text-[13px] text-gray-400'>
|
||||
{t('workflow.common.notRunning')}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
data?.data.map(item => (
|
||||
<div
|
||||
key={item.id}
|
||||
className={cn(
|
||||
'flex mb-0.5 px-2 py-[7px] rounded-lg hover:bg-primary-50 cursor-pointer',
|
||||
item.id === historyWorkflowData?.id && 'bg-primary-50',
|
||||
)}
|
||||
onClick={() => {
|
||||
workflowStore.setState({
|
||||
historyWorkflowData: item,
|
||||
})
|
||||
handleBackupDraft()
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
{
|
||||
!isChatMode && item.status === WorkflowRunningStatus.Stopped && (
|
||||
<AlertTriangle className='mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#F79009]' />
|
||||
)
|
||||
}
|
||||
{
|
||||
!isChatMode && item.status === WorkflowRunningStatus.Failed && (
|
||||
<AlertCircle className='mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#F04438]' />
|
||||
)
|
||||
}
|
||||
{
|
||||
!isChatMode && item.status === WorkflowRunningStatus.Succeeded && (
|
||||
<CheckCircle className='mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#12B76A]' />
|
||||
)
|
||||
}
|
||||
<div>
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center text-[13px] font-medium leading-[18px]',
|
||||
item.id === historyWorkflowData?.id && 'text-primary-600',
|
||||
)}
|
||||
>
|
||||
{`Test ${isChatMode ? 'Chat' : 'Run'}#${item.sequence_number}`}
|
||||
</div>
|
||||
<div className='flex items-center text-xs text-gray-500 leading-[18px]'>
|
||||
{item.created_by_account.name} · {formatTimeFromNow((item.finished_at || item.created_at) * 1000)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(ViewHistory)
|
||||
|
|
@ -78,21 +78,23 @@ const ChatRecord = () => {
|
|||
background: 'linear-gradient(156deg, rgba(242, 244, 247, 0.80) 0%, rgba(242, 244, 247, 0.00) 99.43%), var(--white, #FFF)',
|
||||
}}
|
||||
>
|
||||
<div className='flex items-center justify-between p-4 pb-1 text-base font-semibold text-gray-900'>
|
||||
<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>
|
||||
<Chat
|
||||
config={{} as any}
|
||||
chatList={chatMessageList}
|
||||
chatContainerclassName='px-4'
|
||||
chatContainerInnerClassName='pt-6'
|
||||
chatFooterClassName='px-4 rounded-b-2xl'
|
||||
chatFooterInnerClassName='pb-4'
|
||||
chatNode={<UserInput />}
|
||||
noChatInput
|
||||
allToolIcons={{}}
|
||||
showPromptLog
|
||||
/>
|
||||
<div className='grow h-0'>
|
||||
<Chat
|
||||
config={{} as any}
|
||||
chatList={chatMessageList}
|
||||
chatContainerclassName='px-4'
|
||||
chatContainerInnerClassName='pt-6'
|
||||
chatFooterClassName='px-4 rounded-b-2xl'
|
||||
chatFooterInnerClassName='pb-4'
|
||||
chatNode={<UserInput />}
|
||||
noChatInput
|
||||
allToolIcons={{}}
|
||||
showPromptLog
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import { Panel as NodePanel } from '../nodes'
|
|||
import { useStore } from '../store'
|
||||
import { useIsChatMode } from '../hooks'
|
||||
import DebugAndPreview from './debug-and-preview'
|
||||
import RunHistory from './run-history'
|
||||
import Record from './record'
|
||||
import InputsPanel from './inputs-panel'
|
||||
import WorkflowPreview from './workflow-preview'
|
||||
|
|
@ -21,7 +20,6 @@ const Panel: FC = () => {
|
|||
const nodes = useNodes<CommonNodeType>()
|
||||
const isChatMode = useIsChatMode()
|
||||
const selectedNode = nodes.find(node => node.data.selected)
|
||||
const showRunHistory = useStore(state => state.showRunHistory)
|
||||
const showInputsPanel = useStore(s => s.showInputsPanel)
|
||||
const workflowRunningData = useStore(s => s.workflowRunningData)
|
||||
const historyWorkflowData = useStore(s => s.historyWorkflowData)
|
||||
|
|
@ -88,11 +86,6 @@ const Panel: FC = () => {
|
|||
<NodePanel {...selectedNode!} />
|
||||
)
|
||||
}
|
||||
{
|
||||
showRunHistory && (
|
||||
<RunHistory />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,12 @@
|
|||
import { memo } from 'react'
|
||||
import { useIsChatMode } from '../hooks'
|
||||
import Run from '../run'
|
||||
import { useStore } from '../store'
|
||||
|
||||
const Record = () => {
|
||||
const isChatMode = useIsChatMode()
|
||||
const historyWorkflowData = useStore(s => s.historyWorkflowData)
|
||||
|
||||
return (
|
||||
<div className={`
|
||||
flex flex-col h-full rounded-2xl border-[0.5px] border-gray-200 shadow-xl bg-white
|
||||
${isChatMode ? 'w-[320px]' : 'w-[400px]'}
|
||||
`}>
|
||||
<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#${historyWorkflowData?.sequence_number}`}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,130 +0,0 @@
|
|||
import { memo } from 'react'
|
||||
import cn from 'classnames'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import useSWR from 'swr'
|
||||
import { WorkflowRunningStatus } from '../types'
|
||||
import {
|
||||
useIsChatMode,
|
||||
useWorkflow,
|
||||
useWorkflowRun,
|
||||
} from '../hooks'
|
||||
import { CheckCircle, XClose } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { AlertCircle, AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
|
||||
import {
|
||||
useStore,
|
||||
useWorkflowStore,
|
||||
} from '@/app/components/workflow/store'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import { fetcChatRunHistory, fetchWorkflowRunHistory } from '@/service/workflow'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { ClockPlaySlim } from '@/app/components/base/icons/src/vender/line/time'
|
||||
|
||||
const RunHistory = () => {
|
||||
const { t } = useTranslation()
|
||||
const isChatMode = useIsChatMode()
|
||||
const { appDetail, setCurrentLogItem, setShowMessageLogModal } = useAppStore()
|
||||
const { formatTimeFromNow } = useWorkflow()
|
||||
const { handleBackupDraft } = useWorkflowRun()
|
||||
const workflowStore = useWorkflowStore()
|
||||
const historyWorkflowData = useStore(s => s.historyWorkflowData)
|
||||
const { data: runList, isLoading: runListLoading } = useSWR((appDetail && !isChatMode) ? `/apps/${appDetail.id}/workflow-runs` : null, fetchWorkflowRunHistory)
|
||||
|
||||
const { data: chatList, isLoading: chatListLoading } = useSWR((appDetail && isChatMode) ? `/apps/${appDetail.id}/advanced-chat/workflow-runs` : null, fetcChatRunHistory)
|
||||
|
||||
const data = isChatMode ? chatList : runList
|
||||
const isLoading = isChatMode ? chatListLoading : runListLoading
|
||||
|
||||
if (!appDetail)
|
||||
return null
|
||||
|
||||
return (
|
||||
<div className='absolute -top-2 right-2 flex flex-col ml-2 w-[240px] min-h-[214px] bg-white border-[0.5px] border-gray-200 shadow-xl rounded-xl overflow-y-auto z-[11]'>
|
||||
<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'
|
||||
onClick={() => {
|
||||
workflowStore.setState({
|
||||
showRunHistory: false,
|
||||
})
|
||||
setCurrentLogItem()
|
||||
setShowMessageLogModal(false)
|
||||
}}
|
||||
>
|
||||
<XClose className='w-4 h-4 text-gray-500' />
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
isLoading && (
|
||||
<div className='grow flex items-center justify-center h-full'>
|
||||
<Loading />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className='grow p-2 overflow-y-auto'>
|
||||
{
|
||||
!data?.data.length && (
|
||||
<div className='flex justify-center items-center h-full'>
|
||||
<div>
|
||||
<div className='flex justify-center mb-2'>
|
||||
<ClockPlaySlim className='w-8 h-8 text-gray-300' />
|
||||
</div>
|
||||
<div className='text-center text-[13px] text-gray-400'>
|
||||
{t('workflow.common.notRunning')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
data?.data.map(item => (
|
||||
<div
|
||||
key={item.id}
|
||||
className={cn(
|
||||
'flex mb-0.5 px-2 py-[7px] rounded-lg hover:bg-primary-50 cursor-pointer',
|
||||
item.id === historyWorkflowData?.id && 'bg-primary-50',
|
||||
)}
|
||||
onClick={() => {
|
||||
workflowStore.setState({
|
||||
historyWorkflowData: item,
|
||||
})
|
||||
handleBackupDraft()
|
||||
}}
|
||||
>
|
||||
{
|
||||
!isChatMode && item.status === WorkflowRunningStatus.Stopped && (
|
||||
<AlertTriangle className='mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#F79009]' />
|
||||
)
|
||||
}
|
||||
{
|
||||
!isChatMode && item.status === WorkflowRunningStatus.Failed && (
|
||||
<AlertCircle className='mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#F04438]' />
|
||||
)
|
||||
}
|
||||
{
|
||||
!isChatMode && item.status === WorkflowRunningStatus.Succeeded && (
|
||||
<CheckCircle className='mt-0.5 mr-1.5 w-3.5 h-3.5 text-[#12B76A]' />
|
||||
)
|
||||
}
|
||||
<div>
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center text-[13px] font-medium leading-[18px]',
|
||||
item.id === historyWorkflowData?.id && 'text-primary-600',
|
||||
)}
|
||||
>
|
||||
{`Test ${isChatMode ? 'Chat' : 'Run'}#${item.sequence_number}`}
|
||||
</div>
|
||||
<div className='flex items-center text-xs text-gray-500 leading-[18px]'>
|
||||
{item.created_by_account.name} · {formatTimeFromNow((item.finished_at || item.created_at) * 1000)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(RunHistory)
|
||||
Loading…
Reference in New Issue