| @@ -0,0 +1,35 @@ | |||||
| import { useServerTime } from '@/hooks/useServerTime'; | |||||
| import { elapsedTime } from '@/utils/date'; | |||||
| import React, { useEffect, useState } from 'react'; | |||||
| type RunDurationProps = { | |||||
| createTime?: string; | |||||
| finishTime?: string; | |||||
| className?: string; | |||||
| style?: React.CSSProperties; | |||||
| }; | |||||
| function RunDuration({ createTime, finishTime, className, style }: RunDurationProps) { | |||||
| const [now] = useServerTime(); | |||||
| const [currentTime, setCurrentTime] = useState<Date>(now()); | |||||
| // 定时刷新耗时 | |||||
| useEffect(() => { | |||||
| if (finishTime) { | |||||
| setCurrentTime(new Date(finishTime)); | |||||
| } else { | |||||
| const timer = setInterval(() => { | |||||
| setCurrentTime(now()); | |||||
| }, 1000); | |||||
| return () => { | |||||
| clearInterval(timer); | |||||
| }; | |||||
| } | |||||
| }, [finishTime, now]); | |||||
| return ( | |||||
| <span className={className} style={style}> | |||||
| {elapsedTime(createTime, currentTime)} | |||||
| </span> | |||||
| ); | |||||
| } | |||||
| export default RunDuration; | |||||
| @@ -1,6 +1,5 @@ | |||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import { AutoMLTaskType, ExperimentStatus } from '@/enums'; | import { AutoMLTaskType, ExperimentStatus } from '@/enums'; | ||||
| import { useServerTime } from '@/hooks/useServerTime'; | |||||
| import { getActiveLearnInsReq } from '@/services/activeLearn'; | import { getActiveLearnInsReq } from '@/services/activeLearn'; | ||||
| import { NodeStatus } from '@/types'; | import { NodeStatus } from '@/types'; | ||||
| import { parseJsonText } from '@/utils'; | import { parseJsonText } from '@/utils'; | ||||
| @@ -36,9 +35,6 @@ function ActiveLearnInstance() { | |||||
| const params = useParams(); | const params = useParams(); | ||||
| const instanceId = safeInvoke(Number)(params.id); | const instanceId = safeInvoke(Number)(params.id); | ||||
| const evtSourceRef = useRef<EventSource | null>(null); | const evtSourceRef = useRef<EventSource | null>(null); | ||||
| const [now] = useServerTime(); | |||||
| const [currentTime, setCurrentTime] = useState<Date>(now()); | |||||
| const finish_time = workflowStatus?.finishedAt; | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (instanceId) { | if (instanceId) { | ||||
| @@ -50,20 +46,6 @@ function ActiveLearnInstance() { | |||||
| // eslint-disable-next-line react-hooks/exhaustive-deps | // eslint-disable-next-line react-hooks/exhaustive-deps | ||||
| }, [instanceId]); | }, [instanceId]); | ||||
| // 定时刷新耗时 | |||||
| useEffect(() => { | |||||
| if (finish_time) { | |||||
| setCurrentTime(new Date(finish_time)); | |||||
| } else { | |||||
| const timer = setInterval(() => { | |||||
| setCurrentTime(now()); | |||||
| }, 1000); | |||||
| return () => { | |||||
| clearInterval(timer); | |||||
| }; | |||||
| } | |||||
| }, [finish_time, now]); | |||||
| // 获取实验实例详情 | // 获取实验实例详情 | ||||
| const getExperimentInsInfo = async (isStatusDetermined: boolean) => { | const getExperimentInsInfo = async (isStatusDetermined: boolean) => { | ||||
| const [res] = await to(getActiveLearnInsReq(instanceId)); | const [res] = await to(getActiveLearnInsReq(instanceId)); | ||||
| @@ -171,7 +153,6 @@ function ActiveLearnInstance() { | |||||
| className={styles['active-learn-instance__basic']} | className={styles['active-learn-instance__basic']} | ||||
| info={experimentInfo} | info={experimentInfo} | ||||
| runStatus={workflowStatus} | runStatus={workflowStatus} | ||||
| finishTime={currentTime} | |||||
| isInstance | isInstance | ||||
| /> | /> | ||||
| ), | ), | ||||
| @@ -1,4 +1,5 @@ | |||||
| import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; | import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; | ||||
| import RunDuration from '@/components/RunDuration'; | |||||
| import { AutoMLTaskType, autoMLTaskTypeOptions } from '@/enums'; | import { AutoMLTaskType, autoMLTaskTypeOptions } from '@/enums'; | ||||
| import { useComputingResource } from '@/hooks/useComputingResource'; | import { useComputingResource } from '@/hooks/useComputingResource'; | ||||
| import { | import { | ||||
| @@ -11,7 +12,6 @@ import { | |||||
| import { ActiveLearnData } from '@/pages/ActiveLearn/types'; | import { ActiveLearnData } from '@/pages/ActiveLearn/types'; | ||||
| import { experimentStatusInfo } from '@/pages/Experiment/status'; | import { experimentStatusInfo } from '@/pages/Experiment/status'; | ||||
| import { type NodeStatus } from '@/types'; | import { type NodeStatus } from '@/types'; | ||||
| import { elapsedTime } from '@/utils/date'; | |||||
| import { | import { | ||||
| formatBoolean, | formatBoolean, | ||||
| formatCodeConfig, | formatCodeConfig, | ||||
| @@ -31,10 +31,9 @@ type BasicInfoProps = { | |||||
| className?: string; | className?: string; | ||||
| isInstance?: boolean; | isInstance?: boolean; | ||||
| runStatus?: NodeStatus; | runStatus?: NodeStatus; | ||||
| finishTime?: Date; | |||||
| }; | }; | ||||
| function BasicInfo({ info, className, runStatus, finishTime, isInstance = false }: BasicInfoProps) { | |||||
| function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfoProps) { | |||||
| const getResourceDescription = useComputingResource()[1]; | const getResourceDescription = useComputingResource()[1]; | ||||
| const basicDatas: BasicInfoData[] = useMemo(() => { | const basicDatas: BasicInfoData[] = useMemo(() => { | ||||
| if (!info) { | if (!info) { | ||||
| @@ -215,12 +214,10 @@ function BasicInfo({ info, className, runStatus, finishTime, isInstance = false | |||||
| { | { | ||||
| label: '启动时间', | label: '启动时间', | ||||
| value: formatDate(info.create_time), | value: formatDate(info.create_time), | ||||
| ellipsis: true, | |||||
| }, | }, | ||||
| { | { | ||||
| label: '执行时长', | label: '执行时长', | ||||
| value: elapsedTime(info.create_time, finishTime), | |||||
| ellipsis: true, | |||||
| value: <RunDuration createTime={info.create_time} finishTime={runStatus.finishedAt} />, | |||||
| }, | }, | ||||
| { | { | ||||
| label: '状态', | label: '状态', | ||||
| @@ -243,10 +240,9 @@ function BasicInfo({ info, className, runStatus, finishTime, isInstance = false | |||||
| </div> | </div> | ||||
| </Flex> | </Flex> | ||||
| ), | ), | ||||
| ellipsis: true, | |||||
| }, | }, | ||||
| ]; | ]; | ||||
| }, [runStatus, info, finishTime]); | |||||
| }, [runStatus, info]); | |||||
| return ( | return ( | ||||
| <div className={classNames(styles['active-learn-basic'], className)}> | <div className={classNames(styles['active-learn-basic'], className)}> | ||||
| @@ -1,6 +1,5 @@ | |||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import { AutoMLTaskType, AutoMLType, ExperimentStatus } from '@/enums'; | import { AutoMLTaskType, AutoMLType, ExperimentStatus } from '@/enums'; | ||||
| import { useServerTime } from '@/hooks/useServerTime'; | |||||
| import { getExperimentInsReq } from '@/services/autoML'; | import { getExperimentInsReq } from '@/services/autoML'; | ||||
| import { NodeStatus } from '@/types'; | import { NodeStatus } from '@/types'; | ||||
| import { parseJsonText } from '@/utils'; | import { parseJsonText } from '@/utils'; | ||||
| @@ -36,9 +35,6 @@ function AutoMLInstance() { | |||||
| const params = useParams(); | const params = useParams(); | ||||
| const instanceId = safeInvoke(Number)(params.id); | const instanceId = safeInvoke(Number)(params.id); | ||||
| const evtSourceRef = useRef<EventSource | null>(null); | const evtSourceRef = useRef<EventSource | null>(null); | ||||
| const [now] = useServerTime(); | |||||
| const [currentTime, setCurrentTime] = useState<Date>(now()); | |||||
| const finish_time = workflowStatus?.finishedAt; | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (instanceId) { | if (instanceId) { | ||||
| @@ -50,20 +46,6 @@ function AutoMLInstance() { | |||||
| // eslint-disable-next-line react-hooks/exhaustive-deps | // eslint-disable-next-line react-hooks/exhaustive-deps | ||||
| }, [instanceId]); | }, [instanceId]); | ||||
| // 定时刷新耗时 | |||||
| useEffect(() => { | |||||
| if (finish_time) { | |||||
| setCurrentTime(new Date(finish_time)); | |||||
| } else { | |||||
| const timer = setInterval(() => { | |||||
| setCurrentTime(now()); | |||||
| }, 1000); | |||||
| return () => { | |||||
| clearInterval(timer); | |||||
| }; | |||||
| } | |||||
| }, [finish_time, now]); | |||||
| // 获取实验实例详情 | // 获取实验实例详情 | ||||
| const getExperimentInsInfo = async (isStatusDetermined: boolean) => { | const getExperimentInsInfo = async (isStatusDetermined: boolean) => { | ||||
| const [res] = await to(getExperimentInsReq(instanceId)); | const [res] = await to(getExperimentInsReq(instanceId)); | ||||
| @@ -174,7 +156,6 @@ function AutoMLInstance() { | |||||
| className={styles['auto-ml-instance__basic']} | className={styles['auto-ml-instance__basic']} | ||||
| info={autoMLInfo} | info={autoMLInfo} | ||||
| runStatus={workflowStatus} | runStatus={workflowStatus} | ||||
| finishTime={currentTime} | |||||
| isInstance | isInstance | ||||
| /> | /> | ||||
| ), | ), | ||||
| @@ -1,4 +1,5 @@ | |||||
| import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; | import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; | ||||
| import RunDuration from '@/components/RunDuration'; | |||||
| import { | import { | ||||
| AutoMLTaskType, | AutoMLTaskType, | ||||
| AutoMLType, | AutoMLType, | ||||
| @@ -10,7 +11,6 @@ import { AutoMLData } from '@/pages/AutoML/types'; | |||||
| import { experimentStatusInfo } from '@/pages/Experiment/status'; | import { experimentStatusInfo } from '@/pages/Experiment/status'; | ||||
| import { type NodeStatus } from '@/types'; | import { type NodeStatus } from '@/types'; | ||||
| import { parseJsonText } from '@/utils'; | import { parseJsonText } from '@/utils'; | ||||
| import { elapsedTime } from '@/utils/date'; | |||||
| import { formatBoolean, formatDataset, formatDate, formatEnum } from '@/utils/format'; | import { formatBoolean, formatDataset, formatDate, formatEnum } from '@/utils/format'; | ||||
| import { Flex } from 'antd'; | import { Flex } from 'antd'; | ||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| @@ -40,16 +40,9 @@ type AutoMLBasicProps = { | |||||
| className?: string; | className?: string; | ||||
| isInstance?: boolean; | isInstance?: boolean; | ||||
| runStatus?: NodeStatus; | runStatus?: NodeStatus; | ||||
| finishTime?: Date; | |||||
| }; | }; | ||||
| function AutoMLBasic({ | |||||
| info, | |||||
| className, | |||||
| runStatus, | |||||
| finishTime, | |||||
| isInstance = false, | |||||
| }: AutoMLBasicProps) { | |||||
| function AutoMLBasic({ info, className, runStatus, isInstance = false }: AutoMLBasicProps) { | |||||
| const getResourceDescription = useComputingResource()[1]; | const getResourceDescription = useComputingResource()[1]; | ||||
| const basicDatas: BasicInfoData[] = useMemo(() => { | const basicDatas: BasicInfoData[] = useMemo(() => { | ||||
| if (!info) { | if (!info) { | ||||
| @@ -303,7 +296,7 @@ function AutoMLBasic({ | |||||
| }, | }, | ||||
| { | { | ||||
| label: '执行时长', | label: '执行时长', | ||||
| value: elapsedTime(info.create_time, finishTime), | |||||
| value: <RunDuration createTime={info.create_time} finishTime={runStatus.finishedAt} />, | |||||
| }, | }, | ||||
| { | { | ||||
| label: '状态', | label: '状态', | ||||
| @@ -328,7 +321,7 @@ function AutoMLBasic({ | |||||
| ), | ), | ||||
| }, | }, | ||||
| ]; | ]; | ||||
| }, [runStatus, info, finishTime]); | |||||
| }, [runStatus, info]); | |||||
| return ( | return ( | ||||
| <div className={classNames(styles['auto-ml-basic'], className)}> | <div className={classNames(styles['auto-ml-basic'], className)}> | ||||
| @@ -1,11 +1,11 @@ | |||||
| import RunDuration from '@/components/RunDuration'; | |||||
| import { ExperimentStatus } from '@/enums'; | import { ExperimentStatus } from '@/enums'; | ||||
| import { useServerTime } from '@/hooks/useServerTime'; | |||||
| import { useSSE, type MessageHandler } from '@/hooks/useSSE'; | import { useSSE, type MessageHandler } from '@/hooks/useSSE'; | ||||
| import { experimentStatusInfo } from '@/pages/Experiment/status'; | import { experimentStatusInfo } from '@/pages/Experiment/status'; | ||||
| import { ExperimentCompleted } from '@/utils/constant'; | import { ExperimentCompleted } from '@/utils/constant'; | ||||
| import { elapsedTime, formatDate } from '@/utils/date'; | |||||
| import { formatDate } from '@/utils/date'; | |||||
| import { Typography } from 'antd'; | import { Typography } from 'antd'; | ||||
| import React, { useCallback, useEffect, useState } from 'react'; | |||||
| import React, { useCallback } from 'react'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| type ExperimentInstanceProps = { | type ExperimentInstanceProps = { | ||||
| @@ -25,9 +25,6 @@ function ExperimentInstance({ | |||||
| argo_ins_ns, | argo_ins_ns, | ||||
| experimentInsId, | experimentInsId, | ||||
| }: ExperimentInstanceProps) { | }: ExperimentInstanceProps) { | ||||
| const [now] = useServerTime(); | |||||
| const [currentTime, setCurrentTime] = useState<Date>(now()); | |||||
| const handleSSEMessage: MessageHandler = useCallback( | const handleSSEMessage: MessageHandler = useCallback( | ||||
| (experimentInsId: number, status: string, finish_time: string) => { | (experimentInsId: number, status: string, finish_time: string) => { | ||||
| window.postMessage({ | window.postMessage({ | ||||
| @@ -43,23 +40,11 @@ function ExperimentInstance({ | |||||
| ); | ); | ||||
| useSSE(experimentInsId, status, argo_ins_name, argo_ins_ns, handleSSEMessage); | useSSE(experimentInsId, status, argo_ins_name, argo_ins_ns, handleSSEMessage); | ||||
| // 定时刷新耗时 | |||||
| useEffect(() => { | |||||
| if (finish_time) { | |||||
| setCurrentTime(new Date(finish_time)); | |||||
| } else { | |||||
| const timer = setInterval(() => { | |||||
| setCurrentTime(now()); | |||||
| }, 1000); | |||||
| return () => { | |||||
| clearInterval(timer); | |||||
| }; | |||||
| } | |||||
| }, [finish_time, now]); | |||||
| return ( | return ( | ||||
| <React.Fragment> | <React.Fragment> | ||||
| <div className={styles.description}>{elapsedTime(create_time, currentTime)}</div> | |||||
| <div className={styles.description}> | |||||
| <RunDuration createTime={create_time} finishTime={finish_time} /> | |||||
| </div> | |||||
| <div className={styles.startTime}> | <div className={styles.startTime}> | ||||
| <Typography.Text ellipsis={{ tooltip: formatDate(create_time) }}> | <Typography.Text ellipsis={{ tooltip: formatDate(create_time) }}> | ||||
| {formatDate(create_time)} | {formatDate(create_time)} | ||||
| @@ -29,7 +29,7 @@ import { | |||||
| } from 'antd'; | } from 'antd'; | ||||
| import { type SearchProps } from 'antd/es/input'; | import { type SearchProps } from 'antd/es/input'; | ||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { useCallback, useEffect, useState } from 'react'; | |||||
| import { useCallback, useEffect, useRef, useState } from 'react'; | |||||
| import ExperimentInstanceList from '../ExperimentInstanceList'; | import ExperimentInstanceList from '../ExperimentInstanceList'; | ||||
| import { ExperimentListType, experimentListConfig } from './config'; | import { ExperimentListType, experimentListConfig } from './config'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| @@ -58,6 +58,7 @@ function ExperimentList({ type }: ExperimentListProps) { | |||||
| }, | }, | ||||
| ); | ); | ||||
| const config = experimentListConfig[type]; | const config = experimentListConfig[type]; | ||||
| const timerRef = useRef<ReturnType<typeof window.setTimeout> | undefined>(); | |||||
| // 获取自主机器学习或超参数自动优化列表 | // 获取自主机器学习或超参数自动优化列表 | ||||
| const getAutoMLList = useCallback(async () => { | const getAutoMLList = useCallback(async () => { | ||||
| @@ -140,7 +141,13 @@ function ExperimentList({ type }: ExperimentListProps) { | |||||
| : v, | : v, | ||||
| ), | ), | ||||
| ); | ); | ||||
| setTimeout(() => { | |||||
| if (timerRef.current) { | |||||
| clearTimeout(timerRef.current); | |||||
| timerRef.current = undefined; | |||||
| } | |||||
| timerRef.current = setTimeout(() => { | |||||
| refreshExperimentList(); | refreshExperimentList(); | ||||
| }, 10000); | }, 10000); | ||||
| } | } | ||||
| @@ -149,6 +156,10 @@ function ExperimentList({ type }: ExperimentListProps) { | |||||
| window.addEventListener('message', handleMessage); | window.addEventListener('message', handleMessage); | ||||
| return () => { | return () => { | ||||
| window.removeEventListener('message', handleMessage); | window.removeEventListener('message', handleMessage); | ||||
| if (timerRef.current) { | |||||
| clearTimeout(timerRef.current); | |||||
| timerRef.current = undefined; | |||||
| } | |||||
| }; | }; | ||||
| }, [refreshExperimentList]); | }, [refreshExperimentList]); | ||||
| @@ -16,6 +16,7 @@ import ParamsModal from '../components/ViewParamsModal'; | |||||
| import { experimentStatusInfo } from '../status'; | import { experimentStatusInfo } from '../status'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| import { useServerTime } from '@/hooks/useServerTime'; | import { useServerTime } from '@/hooks/useServerTime'; | ||||
| import RunDuration from '@/components/RunDuration'; | |||||
| let graph = null; | let graph = null; | ||||
| @@ -28,13 +29,10 @@ function ExperimentText() { | |||||
| const [paramsModalOpen, openParamsModal, closeParamsModal] = useVisible(false); | const [paramsModalOpen, openParamsModal, closeParamsModal] = useVisible(false); | ||||
| const [propsDrawerOpen, openPropsDrawer, closePropsDrawer, propsDrawerOpenRef] = | const [propsDrawerOpen, openPropsDrawer, closePropsDrawer, propsDrawerOpenRef] = | ||||
| useVisible(false); | useVisible(false); | ||||
| const [now] = useServerTime(); | |||||
| const [currentTime, setCurrentTime] = useState(now()); | |||||
| const navigate = useNavigate(); | const navigate = useNavigate(); | ||||
| const evtSourceRef = useRef(); | const evtSourceRef = useRef(); | ||||
| const width = 110; | const width = 110; | ||||
| const height = 36; | const height = 36; | ||||
| const finish_time = experimentIns?.finish_time | |||||
| useEffect(() => { | useEffect(() => { | ||||
| initGraph(); | initGraph(); | ||||
| @@ -63,20 +61,6 @@ function ExperimentText() { | |||||
| }; | }; | ||||
| }, []); | }, []); | ||||
| // 定时刷新耗时 | |||||
| useEffect(() => { | |||||
| if (finish_time) { | |||||
| setCurrentTime(new Date(finish_time)); | |||||
| } else { | |||||
| const timer = setInterval(() => { | |||||
| setCurrentTime(now()); | |||||
| }, 1000); | |||||
| return () => { | |||||
| clearInterval(timer); | |||||
| }; | |||||
| } | |||||
| }, [finish_time, now]); | |||||
| // 获取流水线模版 | // 获取流水线模版 | ||||
| const getWorkflow = async () => { | const getWorkflow = async () => { | ||||
| const [res] = await to(getWorkflowById(locationParams.workflowId)); | const [res] = await to(getWorkflowById(locationParams.workflowId)); | ||||
| @@ -492,7 +476,7 @@ function ExperimentText() { | |||||
| </div> | </div> | ||||
| <div className={styles['pipeline-container__top__info']}> | <div className={styles['pipeline-container__top__info']}> | ||||
| 执行时长: | 执行时长: | ||||
| {elapsedTime(experimentIns?.create_time, currentTime)} | |||||
| <RunDuration createTime={experimentIns?.create_time} finishTime={experimentIns?.finish_time} /> | |||||
| </div> | </div> | ||||
| <div className={styles['pipeline-container__top__info']}> | <div className={styles['pipeline-container__top__info']}> | ||||
| 状态: | 状态: | ||||
| @@ -1,11 +1,11 @@ | |||||
| import RunDuration from '@/components/RunDuration'; | |||||
| import { ExperimentStatus } from '@/enums'; | import { ExperimentStatus } from '@/enums'; | ||||
| import { useServerTime } from '@/hooks/useServerTime'; | |||||
| import { experimentStatusInfo } from '@/pages/Experiment/status'; | import { experimentStatusInfo } from '@/pages/Experiment/status'; | ||||
| import { PipelineNodeModelSerialize } from '@/types'; | import { PipelineNodeModelSerialize } from '@/types'; | ||||
| import { elapsedTime, formatDate } from '@/utils/date'; | |||||
| import { formatDate } from '@/utils/date'; | |||||
| import { CloseOutlined, DatabaseOutlined, ProfileOutlined } from '@ant-design/icons'; | import { CloseOutlined, DatabaseOutlined, ProfileOutlined } from '@ant-design/icons'; | ||||
| import { Drawer, Tabs, Typography } from 'antd'; | import { Drawer, Tabs, Typography } from 'antd'; | ||||
| import { useEffect, useMemo, useState } from 'react'; | |||||
| import { useMemo } from 'react'; | |||||
| import ExperimentParameter from '../ExperimentParameter'; | import ExperimentParameter from '../ExperimentParameter'; | ||||
| import ExperimentResult from '../ExperimentResult'; | import ExperimentResult from '../ExperimentResult'; | ||||
| import LogList from '../LogList'; | import LogList from '../LogList'; | ||||
| @@ -42,23 +42,6 @@ const ExperimentDrawer = ({ | |||||
| instanceNodeStartTime, | instanceNodeStartTime, | ||||
| instanceNodeEndTime, | instanceNodeEndTime, | ||||
| }: ExperimentDrawerProps) => { | }: ExperimentDrawerProps) => { | ||||
| const [now] = useServerTime(); | |||||
| const [currentTime, setCurrentTime] = useState(now()); | |||||
| // 定时刷新耗时 | |||||
| useEffect(() => { | |||||
| if (instanceNodeEndTime) { | |||||
| setCurrentTime(new Date(instanceNodeEndTime)); | |||||
| } else { | |||||
| const timer = setInterval(() => { | |||||
| setCurrentTime(now()); | |||||
| }, 1000); | |||||
| return () => { | |||||
| clearInterval(timer); | |||||
| }; | |||||
| } | |||||
| }, [instanceNodeEndTime, now]); | |||||
| // 如果性能有问题,可以进一步拆解 | // 如果性能有问题,可以进一步拆解 | ||||
| const items = useMemo( | const items = useMemo( | ||||
| () => [ | () => [ | ||||
| @@ -160,7 +143,7 @@ const ExperimentDrawer = ({ | |||||
| </div> | </div> | ||||
| <div className={styles['experiment-drawer__info']}> | <div className={styles['experiment-drawer__info']}> | ||||
| 耗时: | 耗时: | ||||
| {elapsedTime(instanceNodeStartTime, currentTime)} | |||||
| <RunDuration createTime={instanceNodeStartTime} finishTime={instanceNodeEndTime} /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <Tabs | <Tabs | ||||
| @@ -1,11 +1,11 @@ | |||||
| import RunDuration from '@/components/RunDuration'; | |||||
| import { ExperimentStatus } from '@/enums'; | import { ExperimentStatus } from '@/enums'; | ||||
| import { useServerTime } from '@/hooks/useServerTime'; | |||||
| import { useSSE, type MessageHandler } from '@/hooks/useSSE'; | import { useSSE, type MessageHandler } from '@/hooks/useSSE'; | ||||
| import { experimentStatusInfo } from '@/pages/Experiment/status'; | import { experimentStatusInfo } from '@/pages/Experiment/status'; | ||||
| import { ExperimentCompleted } from '@/utils/constant'; | import { ExperimentCompleted } from '@/utils/constant'; | ||||
| import { elapsedTime, formatDate } from '@/utils/date'; | |||||
| import { formatDate } from '@/utils/date'; | |||||
| import { Typography } from 'antd'; | import { Typography } from 'antd'; | ||||
| import React, { useCallback, useEffect, useState } from 'react'; | |||||
| import React, { useCallback } from 'react'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| type ExperimentInstanceProps = { | type ExperimentInstanceProps = { | ||||
| @@ -25,9 +25,6 @@ function ExperimentInstance({ | |||||
| argo_ins_ns, | argo_ins_ns, | ||||
| experimentInsId, | experimentInsId, | ||||
| }: ExperimentInstanceProps) { | }: ExperimentInstanceProps) { | ||||
| const [now] = useServerTime(); | |||||
| const [currentTime, setCurrentTime] = useState<Date>(now()); | |||||
| const handleSSEMessage: MessageHandler = useCallback( | const handleSSEMessage: MessageHandler = useCallback( | ||||
| (experimentInsId: number, status: string, finish_time: string) => { | (experimentInsId: number, status: string, finish_time: string) => { | ||||
| window.postMessage({ | window.postMessage({ | ||||
| @@ -43,24 +40,12 @@ function ExperimentInstance({ | |||||
| ); | ); | ||||
| useSSE(experimentInsId, status, argo_ins_name, argo_ins_ns, handleSSEMessage); | useSSE(experimentInsId, status, argo_ins_name, argo_ins_ns, handleSSEMessage); | ||||
| // 定时刷新耗时 | |||||
| useEffect(() => { | |||||
| if (finish_time) { | |||||
| setCurrentTime(new Date(finish_time)); | |||||
| } else { | |||||
| const timer = setInterval(() => { | |||||
| setCurrentTime(now()); | |||||
| }, 1000); | |||||
| return () => { | |||||
| clearInterval(timer); | |||||
| }; | |||||
| } | |||||
| }, [finish_time, now]); | |||||
| return ( | return ( | ||||
| <React.Fragment> | <React.Fragment> | ||||
| <div className={styles.description}> | <div className={styles.description}> | ||||
| <div style={{ width: '50%' }}>{elapsedTime(create_time, currentTime)}</div> | |||||
| <div style={{ width: '50%' }}> | |||||
| <RunDuration createTime={create_time} finishTime={finish_time} /> | |||||
| </div> | |||||
| <div style={{ width: '50%' }} className={styles.startTime}> | <div style={{ width: '50%' }} className={styles.startTime}> | ||||
| <Typography.Text ellipsis={{ tooltip: formatDate(create_time) }}> | <Typography.Text ellipsis={{ tooltip: formatDate(create_time) }}> | ||||
| {formatDate(create_time)} | {formatDate(create_time)} | ||||
| @@ -21,7 +21,7 @@ import tableCellRender, { TableCellValueType } from '@/utils/table'; | |||||
| import { modalConfirm } from '@/utils/ui'; | import { modalConfirm } from '@/utils/ui'; | ||||
| import { App, Button, ConfigProvider, Dropdown, Input, Space, Table, Tooltip } from 'antd'; | import { App, Button, ConfigProvider, Dropdown, Input, Space, Table, Tooltip } from 'antd'; | ||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { useCallback, useEffect, useState } from 'react'; | |||||
| import { useCallback, useEffect, useRef, useState } from 'react'; | |||||
| import { useNavigate } from 'react-router-dom'; | import { useNavigate } from 'react-router-dom'; | ||||
| import { ComparisonType } from './Comparison/config'; | import { ComparisonType } from './Comparison/config'; | ||||
| import AddExperimentModal from './components/AddExperimentModal'; | import AddExperimentModal from './components/AddExperimentModal'; | ||||
| @@ -54,6 +54,7 @@ function Experiment() { | |||||
| }, | }, | ||||
| ); | ); | ||||
| const { message } = App.useApp(); | const { message } = App.useApp(); | ||||
| const timerRef = useRef(); | |||||
| // 获取实验列表 | // 获取实验列表 | ||||
| const getExperimentList = useCallback(async () => { | const getExperimentList = useCallback(async () => { | ||||
| @@ -126,7 +127,13 @@ function Experiment() { | |||||
| : v, | : v, | ||||
| ), | ), | ||||
| ); | ); | ||||
| setTimeout(() => { | |||||
| if (timerRef.current) { | |||||
| clearTimeout(timerRef.current); | |||||
| timerRef.current = undefined; | |||||
| } | |||||
| timerRef.current = setTimeout(() => { | |||||
| refreshExperimentList(); | refreshExperimentList(); | ||||
| }, 10000); | }, 10000); | ||||
| } | } | ||||
| @@ -135,6 +142,10 @@ function Experiment() { | |||||
| window.addEventListener('message', handleMessage); | window.addEventListener('message', handleMessage); | ||||
| return () => { | return () => { | ||||
| window.removeEventListener('message', handleMessage); | window.removeEventListener('message', handleMessage); | ||||
| if (timerRef.current) { | |||||
| clearTimeout(timerRef.current); | |||||
| timerRef.current = undefined; | |||||
| } | |||||
| }; | }; | ||||
| }, [refreshExperimentList]); | }, [refreshExperimentList]); | ||||
| @@ -1,6 +1,5 @@ | |||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import { ExperimentStatus } from '@/enums'; | import { ExperimentStatus } from '@/enums'; | ||||
| import { useServerTime } from '@/hooks/useServerTime'; | |||||
| import { getRayInsReq } from '@/services/hyperParameter'; | import { getRayInsReq } from '@/services/hyperParameter'; | ||||
| import { NodeStatus } from '@/types'; | import { NodeStatus } from '@/types'; | ||||
| import { parseJsonText } from '@/utils'; | import { parseJsonText } from '@/utils'; | ||||
| @@ -36,9 +35,6 @@ function HyperParameterInstance() { | |||||
| const params = useParams(); | const params = useParams(); | ||||
| const instanceId = safeInvoke(Number)(params.id); | const instanceId = safeInvoke(Number)(params.id); | ||||
| const evtSourceRef = useRef<EventSource | null>(null); | const evtSourceRef = useRef<EventSource | null>(null); | ||||
| const [now] = useServerTime(); | |||||
| const [currentTime, setCurrentTime] = useState<Date>(now()); | |||||
| const finish_time = workflowStatus?.finishedAt; | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (instanceId) { | if (instanceId) { | ||||
| @@ -50,20 +46,6 @@ function HyperParameterInstance() { | |||||
| // eslint-disable-next-line react-hooks/exhaustive-deps | // eslint-disable-next-line react-hooks/exhaustive-deps | ||||
| }, [instanceId]); | }, [instanceId]); | ||||
| // 定时刷新耗时 | |||||
| useEffect(() => { | |||||
| if (finish_time) { | |||||
| setCurrentTime(new Date(finish_time)); | |||||
| } else { | |||||
| const timer = setInterval(() => { | |||||
| setCurrentTime(now()); | |||||
| }, 1000); | |||||
| return () => { | |||||
| clearInterval(timer); | |||||
| }; | |||||
| } | |||||
| }, [finish_time, now]); | |||||
| // 获取实验实例详情 | // 获取实验实例详情 | ||||
| const getExperimentInsInfo = async (isStatusDetermined: boolean) => { | const getExperimentInsInfo = async (isStatusDetermined: boolean) => { | ||||
| const [res] = await to(getRayInsReq(instanceId)); | const [res] = await to(getRayInsReq(instanceId)); | ||||
| @@ -71,7 +53,7 @@ function HyperParameterInstance() { | |||||
| const info = res.data as HyperParameterInstanceData; | const info = res.data as HyperParameterInstanceData; | ||||
| const { param, node_status, argo_ins_name, argo_ins_ns, status, create_time } = info; | const { param, node_status, argo_ins_name, argo_ins_ns, status, create_time } = info; | ||||
| // 解析配置参数 | // 解析配置参数 | ||||
| const paramJson = parseJsonText(param); | |||||
| const paramJson = parseJsonText(param).data; | |||||
| if (paramJson) { | if (paramJson) { | ||||
| // 实例详情返回的参数是字符串,需要转换 | // 实例详情返回的参数是字符串,需要转换 | ||||
| if (typeof paramJson.parameters === 'string') { | if (typeof paramJson.parameters === 'string') { | ||||
| @@ -186,7 +168,6 @@ function HyperParameterInstance() { | |||||
| className={styles['hyper-parameter-instance__basic']} | className={styles['hyper-parameter-instance__basic']} | ||||
| info={experimentInfo} | info={experimentInfo} | ||||
| runStatus={workflowStatus} | runStatus={workflowStatus} | ||||
| finishTime={currentTime} | |||||
| isInstance | isInstance | ||||
| /> | /> | ||||
| ), | ), | ||||
| @@ -1,4 +1,5 @@ | |||||
| import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; | import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; | ||||
| import RunDuration from '@/components/RunDuration'; | |||||
| import { hyperParameterOptimizedMode } from '@/enums'; | import { hyperParameterOptimizedMode } from '@/enums'; | ||||
| import { useComputingResource } from '@/hooks/useComputingResource'; | import { useComputingResource } from '@/hooks/useComputingResource'; | ||||
| import { experimentStatusInfo } from '@/pages/Experiment/status'; | import { experimentStatusInfo } from '@/pages/Experiment/status'; | ||||
| @@ -8,7 +9,6 @@ import { | |||||
| } from '@/pages/HyperParameter/components/CreateForm/utils'; | } from '@/pages/HyperParameter/components/CreateForm/utils'; | ||||
| import { HyperParameterData } from '@/pages/HyperParameter/types'; | import { HyperParameterData } from '@/pages/HyperParameter/types'; | ||||
| import { type NodeStatus } from '@/types'; | import { type NodeStatus } from '@/types'; | ||||
| import { elapsedTime } from '@/utils/date'; | |||||
| import { | import { | ||||
| formatCodeConfig, | formatCodeConfig, | ||||
| formatDataset, | formatDataset, | ||||
| @@ -33,14 +33,12 @@ type HyperParameterBasicProps = { | |||||
| className?: string; | className?: string; | ||||
| isInstance?: boolean; | isInstance?: boolean; | ||||
| runStatus?: NodeStatus; | runStatus?: NodeStatus; | ||||
| finishTime?: Date; | |||||
| }; | }; | ||||
| function HyperParameterBasic({ | function HyperParameterBasic({ | ||||
| info, | info, | ||||
| className, | className, | ||||
| runStatus, | runStatus, | ||||
| finishTime, | |||||
| isInstance = false, | isInstance = false, | ||||
| }: HyperParameterBasicProps) { | }: HyperParameterBasicProps) { | ||||
| const getResourceDescription = useComputingResource()[1]; | const getResourceDescription = useComputingResource()[1]; | ||||
| @@ -157,7 +155,7 @@ function HyperParameterBasic({ | |||||
| }, | }, | ||||
| { | { | ||||
| label: '执行时长', | label: '执行时长', | ||||
| value: elapsedTime(info.create_time, finishTime), | |||||
| value: <RunDuration createTime={info.create_time} finishTime={runStatus.finishedAt} />, | |||||
| ellipsis: true, | ellipsis: true, | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -184,7 +182,7 @@ function HyperParameterBasic({ | |||||
| ellipsis: true, | ellipsis: true, | ||||
| }, | }, | ||||
| ]; | ]; | ||||
| }, [runStatus, info, finishTime]); | |||||
| }, [runStatus, info]); | |||||
| return ( | return ( | ||||
| <div className={classNames(styles['hyper-parameter-basic'], className)}> | <div className={classNames(styles['hyper-parameter-basic'], className)}> | ||||