diff --git a/web/app/components/workflow/run/index.tsx b/web/app/components/workflow/run/index.tsx index b379a804a7..fda74873ed 100644 --- a/web/app/components/workflow/run/index.tsx +++ b/web/app/components/workflow/run/index.tsx @@ -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 = ({ activeTab = 'RESULT', runID }) => { const { t } = useTranslation() + const { notify } = useContext(ToastContext) const [currentTab, setCurrentTab] = useState(activeTab) + const { appDetail } = useAppStore() + const [loading, setLoading] = useState(true) + const [runDetail, setRunDetail] = useState() + const [list, setList] = useState([]) + const [collapseState, setCollapseState] = useState([]) + + 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 (
@@ -24,20 +106,46 @@ const RunPanel: FC = ({ 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')}
setCurrentTab('TRACING')} + onClick={() => switchTab('TRACING')} >{t('runLog.tracing')}
+
+ +
{/* panel detal */}
- {currentTab === 'RESULT' && } - {currentTab === 'TRACING' && } + {loading && ( +
+ +
+ )} + {!loading && currentTab === 'RESULT' && runDetail && ( + + )} + {!loading && currentTab === 'TRACING' && ( + + )}
) diff --git a/web/app/components/workflow/run/result.tsx b/web/app/components/workflow/run/result.tsx deleted file mode 100644 index ab2dfd53fc..0000000000 --- a/web/app/components/workflow/run/result.tsx +++ /dev/null @@ -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 = ({ runID }) => { - const { appDetail } = useAppStore() - const [loading, setLoading] = useState(true) - const [runDetail, setRunDetail] = useState() - - 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 ( -
- -
- ) - } - - return ( - - ) -} - -export default Result diff --git a/web/app/components/workflow/run/tracing.tsx b/web/app/components/workflow/run/tracing.tsx deleted file mode 100644 index 75a183efa8..0000000000 --- a/web/app/components/workflow/run/tracing.tsx +++ /dev/null @@ -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 = ({ runID }) => { - const { notify } = useContext(ToastContext) - const { appDetail } = useAppStore() - const [loading, setLoading] = useState(true) - const [list, setList] = useState([]) - const [collapseState, setCollapseState] = useState([]) - - 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 ( -
- -
- ) - } - - return ( - - ) -} - -export default Tracing