Merge remote-tracking branch 'origin/main' into feat/trigger

This commit is contained in:
lyzno1
2025-10-16 18:30:33 +08:00
151 changed files with 858 additions and 857 deletions

View File

@ -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}` : ''}

View File

@ -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 = [

View File

@ -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'>

View File

@ -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
}