feat: workflow continue on error (#11474)
This commit is contained in:
@@ -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' && (
|
||||
|
@@ -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>
|
||||
)}
|
||||
|
@@ -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>
|
||||
)}
|
||||
|
@@ -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>
|
||||
|
@@ -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',
|
||||
)}
|
||||
>
|
||||
|
@@ -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>
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user