refactor run data fetching

This commit is contained in:
JzoNg 2024-03-18 14:15:29 +08:00
parent 0439276866
commit d537efe97a
3 changed files with 115 additions and 144 deletions

View File

@ -1,10 +1,18 @@
'use client'
import type { FC } from 'react'
import React, { useState } from 'react'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { useContext } from 'use-context-selector'
import { useTranslation } from 'react-i18next'
import cn from 'classnames'
import Result from './result'
import Tracing from './tracing'
import produce from 'immer'
import ResultPanel from './result-panel'
import TracingPanel from './tracing-panel'
import { ToastContext } from '@/app/components/base/toast'
import Loading from '@/app/components/base/loading'
import { fetchRunDetail, fetchTracingList } from '@/service/log'
import type { NodeTracing } from '@/types/workflow'
import type { WorkflowRunDetailResponse } from '@/models/log'
import { useStore as useAppStore } from '@/app/components/app/store'
type RunProps = {
activeTab?: 'RESULT' | 'TRACING'
@ -13,7 +21,81 @@ type RunProps = {
const RunPanel: FC<RunProps> = ({ activeTab = 'RESULT', runID }) => {
const { t } = useTranslation()
const { notify } = useContext(ToastContext)
const [currentTab, setCurrentTab] = useState<string>(activeTab)
const { appDetail } = useAppStore()
const [loading, setLoading] = useState<boolean>(true)
const [runDetail, setRunDetail] = useState<WorkflowRunDetailResponse>()
const [list, setList] = useState<NodeTracing[]>([])
const [collapseState, setCollapseState] = useState<boolean[]>([])
const executor = useMemo(() => {
if (runDetail?.created_by_role === 'account')
return runDetail.created_by_account?.name || ''
if (runDetail?.created_by_role === 'end_user')
return runDetail.created_by_end_user?.session_id || ''
return 'N/A'
}, [runDetail])
const collapseStateChange = (index: number) => {
const newCollapseState = produce(collapseState, (draft: boolean[]) => {
draft[index] = !draft[index]
})
setCollapseState(newCollapseState)
}
const getResult = useCallback(async (appID: string, runID: string) => {
try {
const res = await fetchRunDetail({
appID,
runID,
})
setRunDetail(res)
}
catch (err) {
notify({
type: 'error',
message: `${err}`,
})
}
}, [notify])
const getTracingList = useCallback(async (appID: string, runID: string) => {
try {
const { data: nodeList } = await fetchTracingList({
url: `/apps/${appID}/workflow-runs/${runID}/node-executions`,
})
const collapseState = nodeList.map(node => node.status === 'succeeded')
setList(nodeList.reverse())
setCollapseState(collapseState)
}
catch (err) {
notify({
type: 'error',
message: `${err}`,
})
}
}, [notify])
const getData = async (appID: string, runID: string) => {
setLoading(true)
await getResult(appID, runID)
await getTracingList(appID, runID)
setLoading(false)
}
const switchTab = async (tab: string) => {
setCurrentTab(tab)
if (tab === 'RESULT')
appDetail?.id && await getResult(appDetail.id, runID)
appDetail?.id && await getTracingList(appDetail.id, runID)
}
useEffect(() => {
// fetch data
if (appDetail && runID)
getData(appDetail.id, runID)
}, [appDetail, runID])
return (
<div className='grow relative flex flex-col'>
@ -24,20 +106,46 @@ const RunPanel: FC<RunProps> = ({ activeTab = 'RESULT', runID }) => {
'mr-6 py-3 border-b-2 border-transparent text-[13px] font-semibold leading-[18px] text-gray-400 cursor-pointer',
currentTab === 'RESULT' && '!border-[rgb(21,94,239)] text-gray-700',
)}
onClick={() => setCurrentTab('RESULT')}
onClick={() => switchTab('RESULT')}
>{t('runLog.result')}</div>
<div
className={cn(
'mr-6 py-3 border-b-2 border-transparent text-[13px] font-semibold leading-[18px] text-gray-400 cursor-pointer',
currentTab === 'TRACING' && '!border-[rgb(21,94,239)] text-gray-700',
)}
onClick={() => setCurrentTab('TRACING')}
onClick={() => switchTab('TRACING')}
>{t('runLog.tracing')}</div>
</div>
<div className='flex h-full items-center justify-center bg-white'>
<Loading />
</div>
{/* panel detal */}
<div className={cn('grow bg-white h-0 overflow-y-auto', currentTab === 'TRACING' && '!bg-gray-50')}>
{currentTab === 'RESULT' && <Result runID={runID} />}
{currentTab === 'TRACING' && <Tracing runID={runID} />}
{loading && (
<div className='flex h-full items-center justify-center bg-white'>
<Loading />
</div>
)}
{!loading && currentTab === 'RESULT' && runDetail && (
<ResultPanel
inputs={runDetail.inputs}
outputs={runDetail.outputs}
status={runDetail.status}
error={runDetail.error}
elapsed_time={runDetail.elapsed_time}
total_tokens={runDetail.total_tokens}
created_at={runDetail.created_at}
created_by={executor}
steps={runDetail.total_steps}
/>
)}
{!loading && currentTab === 'TRACING' && (
<TracingPanel
list={list}
collapseState={collapseState}
collapseHandle={collapseStateChange}
/>
)}
</div>
</div>
)

View File

@ -1,64 +0,0 @@
'use client'
import type { FC } from 'react'
import React, { useEffect, useMemo, useState } from 'react'
import ResultPanel from './result-panel'
import Loading from '@/app/components/base/loading'
import { fetchRunDetail } from '@/service/log'
import type { WorkflowRunDetailResponse } from '@/models/log'
import { useStore as useAppStore } from '@/app/components/app/store'
type ResultProps = {
runID: string
}
const Result: FC<ResultProps> = ({ runID }) => {
const { appDetail } = useAppStore()
const [loading, setLoading] = useState<boolean>(true)
const [runDetail, setRunDetail] = useState<WorkflowRunDetailResponse>()
const executor = useMemo(() => {
if (runDetail?.created_by_role === 'account')
return runDetail.created_by_account?.name || ''
if (runDetail?.created_by_role === 'end_user')
return runDetail.created_by_end_user?.session_id || ''
return 'N/A'
}, [runDetail])
useEffect(() => {
// fetch data
if (appDetail && runID) {
setLoading(true)
fetchRunDetail({
appID: appDetail?.id,
runID,
}).then((res: WorkflowRunDetailResponse) => {
setLoading(false)
setRunDetail(res)
})
}
}, [appDetail, runID])
if (loading || !runDetail) {
return (
<div className='flex h-full items-center justify-center bg-white'>
<Loading />
</div>
)
}
return (
<ResultPanel
inputs={runDetail.inputs}
outputs={runDetail.outputs}
status={runDetail.status}
error={runDetail.error}
elapsed_time={runDetail.elapsed_time}
total_tokens={runDetail.total_tokens}
created_at={runDetail.created_at}
created_by={executor}
steps={runDetail.total_steps}
/>
)
}
export default Result

View File

@ -1,73 +0,0 @@
'use client'
import type { FC } from 'react'
import React, { useCallback, useEffect, useState } from 'react'
import { useContext } from 'use-context-selector'
import produce from 'immer'
import TracingPanel from './tracing-panel'
import Loading from '@/app/components/base/loading'
import { fetchTracingList } from '@/service/log'
import { useStore as useAppStore } from '@/app/components/app/store'
import type { NodeTracing } from '@/types/workflow'
import { ToastContext } from '@/app/components/base/toast'
type TracingProps = {
runID: string
}
const Tracing: FC<TracingProps> = ({ runID }) => {
const { notify } = useContext(ToastContext)
const { appDetail } = useAppStore()
const [loading, setLoading] = useState<boolean>(true)
const [list, setList] = useState<NodeTracing[]>([])
const [collapseState, setCollapseState] = useState<boolean[]>([])
const getTracingList = useCallback(async (appID: string, runID: string) => {
setLoading(true)
try {
const { data: nodeList } = await fetchTracingList({
url: `/apps/${appID}/workflow-runs/${runID}/node-executions`,
})
const collapseState = nodeList.map(node => node.status === 'succeeded')
setList(nodeList.reverse())
setCollapseState(collapseState)
setLoading(false)
}
catch (err) {
notify({
type: 'error',
message: `${err}`,
})
setLoading(false)
}
}, [notify])
useEffect(() => {
if (appDetail && runID)
getTracingList(appDetail.id, runID)
}, [appDetail, getTracingList, runID])
const collapseStateChange = (index: number) => {
const newCollapseState = produce(collapseState, (draft: boolean[]) => {
draft[index] = !draft[index]
})
setCollapseState(newCollapseState)
}
if (loading) {
return (
<div className='flex h-full items-center justify-center bg-white'>
<Loading />
</div>
)
}
return (
<TracingPanel
list={list}
collapseState={collapseState}
collapseHandle={collapseStateChange}
/>
)
}
export default Tracing