mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 18:08:07 +08:00
Merge remote-tracking branch 'origin/main' into feat/trigger
This commit is contained in:
@ -1,10 +1,12 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiCloseLine } from '@remixicon/react'
|
||||
import { RiCloseLine, RiPlayLargeLine } from '@remixicon/react'
|
||||
import Run from '@/app/components/workflow/run'
|
||||
import { WorkflowContextProvider } from '@/app/components/workflow/context'
|
||||
import { useStore } from '@/app/components/app/store'
|
||||
import TooltipPlus from '@/app/components/base/tooltip'
|
||||
import { useRouter } from 'next/navigation'
|
||||
|
||||
type ILogDetail = {
|
||||
runID: string
|
||||
@ -14,13 +16,34 @@ type ILogDetail = {
|
||||
const DetailPanel: FC<ILogDetail> = ({ runID, onClose }) => {
|
||||
const { t } = useTranslation()
|
||||
const appDetail = useStore(state => state.appDetail)
|
||||
const router = useRouter()
|
||||
|
||||
const handleReplay = () => {
|
||||
if (!appDetail?.id) return
|
||||
router.push(`/app/${appDetail.id}/workflow?replayRunId=${runID}`)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='relative flex grow flex-col pt-3'>
|
||||
<span className='absolute right-3 top-4 z-20 cursor-pointer p-1' onClick={onClose}>
|
||||
<RiCloseLine className='h-4 w-4 text-text-tertiary' />
|
||||
</span>
|
||||
<h1 className='system-xl-semibold shrink-0 px-4 py-1 text-text-primary'>{t('appLog.runDetail.workflowTitle')}</h1>
|
||||
<div className='flex items-center bg-components-panel-bg'>
|
||||
<h1 className='system-xl-semibold shrink-0 px-4 py-1 text-text-primary'>{t('appLog.runDetail.workflowTitle')}</h1>
|
||||
<TooltipPlus
|
||||
popupContent={t('appLog.runDetail.testWithParams')}
|
||||
popupClassName='rounded-xl'
|
||||
>
|
||||
<button
|
||||
type='button'
|
||||
className='mr-1 flex h-6 w-6 items-center justify-center rounded-md hover:bg-state-base-hover'
|
||||
aria-label={t('appLog.runDetail.testWithParams')}
|
||||
onClick={handleReplay}
|
||||
>
|
||||
<RiPlayLargeLine className='h-4 w-4 text-text-tertiary' />
|
||||
</button>
|
||||
</TooltipPlus>
|
||||
</div>
|
||||
<WorkflowContextProvider>
|
||||
<Run
|
||||
runDetailUrl={runID ? `/apps/${appDetail?.id}/workflow-runs/${runID}` : ''}
|
||||
|
||||
@ -14,16 +14,6 @@ import Divider from '@/app/components/base/divider'
|
||||
import { searchEmoji } from '@/utils/emoji'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line ts/no-namespace
|
||||
namespace JSX {
|
||||
// eslint-disable-next-line ts/consistent-type-definitions
|
||||
interface IntrinsicElements {
|
||||
'em-emoji': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init({ data })
|
||||
|
||||
const backgroundColors = [
|
||||
|
||||
@ -30,6 +30,10 @@ import {
|
||||
import type { InjectWorkflowStoreSliceFn } from '@/app/components/workflow/store'
|
||||
import { createWorkflowSlice } from './store/workflow/workflow-slice'
|
||||
import WorkflowAppMain from './components/workflow-main'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
|
||||
import { fetchRunDetail } from '@/service/log'
|
||||
import { useGetRunAndTraceUrl } from './hooks/use-get-run-and-trace-url'
|
||||
|
||||
const WorkflowAppWithAdditionalContext = () => {
|
||||
const {
|
||||
@ -90,6 +94,70 @@ const WorkflowAppWithAdditionalContext = () => {
|
||||
return []
|
||||
}, [data])
|
||||
|
||||
const searchParams = useSearchParams()
|
||||
const { getWorkflowRunAndTraceUrl } = useGetRunAndTraceUrl()
|
||||
const replayRunId = searchParams.get('replayRunId')
|
||||
|
||||
useEffect(() => {
|
||||
if (!replayRunId)
|
||||
return
|
||||
const { runUrl } = getWorkflowRunAndTraceUrl(replayRunId)
|
||||
if (!runUrl)
|
||||
return
|
||||
fetchRunDetail(runUrl).then((res) => {
|
||||
const { setInputs, setShowInputsPanel, setShowDebugAndPreviewPanel } = workflowStore.getState()
|
||||
const rawInputs = res.inputs
|
||||
let parsedInputs: Record<string, unknown> | null = null
|
||||
|
||||
if (typeof rawInputs === 'string') {
|
||||
try {
|
||||
const maybeParsed = JSON.parse(rawInputs) as unknown
|
||||
if (maybeParsed && typeof maybeParsed === 'object' && !Array.isArray(maybeParsed))
|
||||
parsedInputs = maybeParsed as Record<string, unknown>
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Failed to parse workflow run inputs', error)
|
||||
}
|
||||
}
|
||||
else if (rawInputs && typeof rawInputs === 'object' && !Array.isArray(rawInputs)) {
|
||||
parsedInputs = rawInputs as Record<string, unknown>
|
||||
}
|
||||
|
||||
if (!parsedInputs)
|
||||
return
|
||||
|
||||
const userInputs: Record<string, string> = {}
|
||||
Object.entries(parsedInputs).forEach(([key, value]) => {
|
||||
if (key.startsWith('sys.'))
|
||||
return
|
||||
|
||||
if (value == null) {
|
||||
userInputs[key] = ''
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
||||
userInputs[key] = value
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
userInputs[key] = JSON.stringify(value)
|
||||
}
|
||||
catch {
|
||||
userInputs[key] = String(value)
|
||||
}
|
||||
})
|
||||
|
||||
if (!Object.keys(userInputs).length)
|
||||
return
|
||||
|
||||
setInputs(userInputs)
|
||||
setShowInputsPanel(true)
|
||||
setShowDebugAndPreviewPanel(true)
|
||||
})
|
||||
}, [replayRunId, workflowStore, getWorkflowRunAndTraceUrl])
|
||||
|
||||
if (!data || isLoading || isLoadingCurrentWorkspace || !currentWorkspace.id) {
|
||||
return (
|
||||
<div className='relative flex h-full w-full items-center justify-center'>
|
||||
|
||||
@ -4,8 +4,8 @@ import type {
|
||||
} from '@/app/components/workflow/types'
|
||||
|
||||
export type FormSliceShape = {
|
||||
inputs: Record<string, string>
|
||||
setInputs: (inputs: Record<string, string>) => void
|
||||
inputs: Record<string, string | number | boolean>
|
||||
setInputs: (inputs: Record<string, string | number | boolean>) => void
|
||||
files: RunFile[]
|
||||
setFiles: (files: RunFile[]) => void
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user