feat: workflow continue on error (#11474)

This commit is contained in:
zxhlyh
2024-12-11 14:21:38 +08:00
committed by GitHub
parent 86dfdcb8ec
commit bec5451f12
60 changed files with 1481 additions and 282 deletions

View File

@@ -258,6 +258,7 @@ const RunPanel: FC<RunProps> = ({ hideResult, activeTab = 'RESULT', runID, getRe
created_at={runDetail.created_at}
created_by={executor}
steps={runDetail.total_steps}
exceptionCounts={runDetail.exceptions_count}
/>
)}
{!loading && currentTab === 'TRACING' && (

View File

@@ -38,6 +38,12 @@ const MetaData: FC<Props> = ({
{status === 'succeeded' && (
<span>SUCCESS</span>
)}
{status === 'partial-succeeded' && (
<span>PARTIAL SUCCESS</span>
)}
{status === 'exception' && (
<span>EXCEPTION</span>
)}
{status === 'failed' && (
<span>FAIL</span>
)}

View File

@@ -19,6 +19,7 @@ import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/
import Button from '@/app/components/base/button'
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
import type { IterationDurationMap, NodeTracing } from '@/types/workflow'
import ErrorHandleTip from '@/app/components/workflow/nodes/_base/components/error-handle/error-handle-tip'
type Props = {
className?: string
@@ -128,6 +129,9 @@ const NodePanel: FC<Props> = ({
{nodeInfo.status === 'stopped' && (
<RiAlertFill className={cn('shrink-0 ml-2 w-4 h-4 text-text-warning-secondary', inMessage && 'w-3.5 h-3.5')} />
)}
{nodeInfo.status === 'exception' && (
<RiAlertFill className={cn('shrink-0 ml-2 w-4 h-4 text-text-warning-secondary', inMessage && 'w-3.5 h-3.5')} />
)}
{nodeInfo.status === 'running' && (
<div className='shrink-0 flex items-center text-text-accent text-[13px] leading-[16px] font-medium'>
<span className='mr-2 text-xs font-normal'>Running</span>
@@ -165,12 +169,24 @@ const NodePanel: FC<Props> = ({
<Split className='mt-2' />
</div>
)}
<div className={cn('px-[10px]', hideInfo && '!px-2 !py-0.5')}>
{nodeInfo.status === 'stopped' && (
<div className={cn('mb-1', hideInfo && '!px-2 !py-0.5')}>
{(nodeInfo.status === 'stopped') && (
<StatusContainer status='stopped'>
{t('workflow.tracing.stopBy', { user: nodeInfo.created_by ? nodeInfo.created_by.name : 'N/A' })}
</StatusContainer>
)}
{(nodeInfo.status === 'exception') && (
<StatusContainer status='stopped'>
{nodeInfo.error}
<a
href='https://docs.dify.ai/guides/workflow/error-handling/predefined-nodes-failure-logic'
target='_blank'
className='text-text-accent'
>
{t('workflow.common.learnMore')}
</a>
</StatusContainer>
)}
{nodeInfo.status === 'failed' && (
<StatusContainer status='failed'>
{nodeInfo.error}
@@ -207,6 +223,7 @@ const NodePanel: FC<Props> = ({
language={CodeLanguage.json}
value={nodeInfo.outputs}
isJSONStringifyBeauty
tip={<ErrorHandleTip type={nodeInfo.execution_metadata?.error_strategy} />}
/>
</div>
)}

View File

@@ -5,6 +5,7 @@ import StatusPanel from './status'
import MetaData from './meta'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
import ErrorHandleTip from '@/app/components/workflow/nodes/_base/components/error-handle/error-handle-tip'
type ResultPanelProps = {
inputs?: string
@@ -19,6 +20,8 @@ type ResultPanelProps = {
finished_at?: number
steps?: number
showSteps?: boolean
exceptionCounts?: number
execution_metadata?: any
}
const ResultPanel: FC<ResultPanelProps> = ({
@@ -33,6 +36,8 @@ const ResultPanel: FC<ResultPanelProps> = ({
created_by,
steps,
showSteps,
exceptionCounts,
execution_metadata,
}) => {
const { t } = useTranslation()
return (
@@ -43,6 +48,7 @@ const ResultPanel: FC<ResultPanelProps> = ({
time={elapsed_time}
tokens={total_tokens}
error={error}
exceptionCounts={exceptionCounts}
/>
</div>
<div className='px-4 py-2 flex flex-col gap-2'>
@@ -69,6 +75,7 @@ const ResultPanel: FC<ResultPanelProps> = ({
language={CodeLanguage.json}
value={outputs}
isJSONStringifyBeauty
tip={<ErrorHandleTip type={execution_metadata?.error_strategy} />}
/>
)}
</div>

View File

@@ -14,10 +14,12 @@ const StatusContainer: FC<Props> = ({
return (
<div
className={cn(
'relative px-3 py-2.5 rounded-lg border system-xs-regular',
'relative px-3 py-2.5 rounded-lg border system-xs-regular break-all',
status === 'succeeded' && 'border-[rgba(23,178,106,0.8)] bg-workflow-display-success-bg bg-[url(~@/app/components/workflow/run/assets/bg-line-success.svg)] shadow-[inset_2px_2px_0_0_rgba(255,255,255,0.5),inset_0_1px_3px_0_rgba(0,0,0,0.12),inset_0_2px_24px_0_rgba(23,178,106,0.2),0_1px_2px_0_rgba(9,9,11,0.05),0_0_0_1px_rgba(0,0,0,0.05)] text-text-success',
status === 'partial-succeeded' && 'border-[rgba(23,178,106,0.8)] bg-workflow-display-success-bg bg-[url(~@/app/components/workflow/run/assets/bg-line-success.svg)] shadow-[inset_2px_2px_0_0_rgba(255,255,255,0.5),inset_0_1px_3px_0_rgba(0,0,0,0.12),inset_0_2px_24px_0_rgba(23,178,106,0.2),0_1px_2px_0_rgba(9,9,11,0.05),0_0_0_1px_rgba(0,0,0,0.05)] text-text-success',
status === 'failed' && 'border-[rgba(240,68,56,0.8)] bg-workflow-display-error-bg bg-[url(~@/app/components/workflow/run/assets/bg-line-error.svg)] shadow-[inset_2px_2px_0_0_rgba(255,255,255,0.5),inset_0_1px_3px_0_rgba(0,0,0,0.12),inset_0_2px_24px_0_rgba(240,68,56,0.2),0_1px_2px_0_rgba(9,9,11,0.05),0_0_0_1px_rgba(0,0,0,0.05)] text-text-warning',
status === 'stopped' && 'border-[rgba(247,144,9,0.8)] bg-workflow-display-warning-bg bg-[url(~@/app/components/workflow/run/assets/bg-line-warning.svg)] shadow-[inset_2px_2px_0_0_rgba(255,255,255,0.5),inset_0_1px_3px_0_rgba(0,0,0,0.12),inset_0_2px_24px_0_rgba(247,144,9,0.2),0_1px_2px_0_rgba(9,9,11,0.05),0_0_0_1px_rgba(0,0,0,0.05)] text-text-destructive',
status === 'exception' && 'border-[rgba(247,144,9,0.8)] bg-workflow-display-warning-bg bg-[url(~@/app/components/workflow/run/assets/bg-line-warning.svg)] shadow-[inset_2px_2px_0_0_rgba(255,255,255,0.5),inset_0_1px_3px_0_rgba(0,0,0,0.12),inset_0_2px_24px_0_rgba(247,144,9,0.2),0_1px_2px_0_rgba(9,9,11,0.05),0_0_0_1px_rgba(0,0,0,0.05)] text-text-destructive',
status === 'running' && 'border-[rgba(11,165,236,0.8)] bg-workflow-display-normal-bg bg-[url(~@/app/components/workflow/run/assets/bg-line-running.svg)] shadow-[inset_2px_2px_0_0_rgba(255,255,255,0.5),inset_0_1px_3px_0_rgba(0,0,0,0.12),inset_0_2px_24px_0_rgba(11,165,236,0.2),0_1px_2px_0_rgba(9,9,11,0.05),0_0_0_1px_rgba(0,0,0,0.05)] text-util-colors-blue-light-blue-light-600',
)}
>

View File

@@ -10,6 +10,7 @@ type ResultProps = {
time?: number
tokens?: number
error?: string
exceptionCounts?: number
}
const StatusPanel: FC<ResultProps> = ({
@@ -17,18 +18,23 @@ const StatusPanel: FC<ResultProps> = ({
time,
tokens,
error,
exceptionCounts,
}) => {
const { t } = useTranslation()
return (
<StatusContainer status={status}>
<div className='flex'>
<div className='flex-[33%] max-w-[120px]'>
<div className={cn(
'flex-[33%] max-w-[120px]',
status === 'partial-succeeded' && 'min-w-[140px]',
)}>
<div className='mb-1 text-text-tertiary system-2xs-medium-uppercase'>{t('runLog.resultPanel.status')}</div>
<div
className={cn(
'flex items-center gap-1 system-xs-semibold-uppercase',
status === 'succeeded' && 'text-util-colors-green-green-600',
status === 'partial-succeeded' && 'text-util-colors-green-green-600',
status === 'failed' && 'text-util-colors-red-red-600',
status === 'stopped' && 'text-util-colors-warning-warning-600',
status === 'running' && 'text-util-colors-blue-light-blue-light-600',
@@ -46,6 +52,18 @@ const StatusPanel: FC<ResultProps> = ({
<span>SUCCESS</span>
</>
)}
{status === 'partial-succeeded' && (
<>
<Indicator color={'green'} />
<span>PARTIAL SUCCESS</span>
</>
)}
{status === 'exception' && (
<>
<Indicator color={'yellow'} />
<span>EXCEPTION</span>
</>
)}
{status === 'failed' && (
<>
<Indicator color={'red'} />
@@ -87,8 +105,45 @@ const StatusPanel: FC<ResultProps> = ({
<>
<div className='my-2 h-[0.5px] bg-divider-subtle'/>
<div className='system-xs-regular text-text-destructive'>{error}</div>
{
!!exceptionCounts && (
<>
<div className='my-2 h-[0.5px] bg-divider-subtle'/>
<div className='system-xs-regular text-text-destructive'>
{t('workflow.nodes.common.errorHandle.partialSucceeded.tip', { num: exceptionCounts })}
</div>
</>
)
}
</>
)}
{
status === 'partial-succeeded' && !!exceptionCounts && (
<>
<div className='my-2 h-[0.5px] bg-divider-deep'/>
<div className='system-xs-medium text-text-warning'>
{t('workflow.nodes.common.errorHandle.partialSucceeded.tip', { num: exceptionCounts })}
</div>
</>
)
}
{
status === 'exception' && (
<>
<div className='my-2 h-[0.5px] bg-divider-deep'/>
<div className='system-xs-medium text-text-warning'>
{error}
<a
href='https://docs.dify.ai/guides/workflow/error-handling/predefined-nodes-failure-logic'
target='_blank'
className='text-text-accent'
>
{t('workflow.common.learnMore')}
</a>
</div>
</>
)
}
</StatusContainer>
)
}