| @@ -5,8 +5,9 @@ import { NodeStatus } from '@/types'; | |||||
| export type MessageHandler = (experimentInsId: number, status: string, finishedAt: string, nodes: Record<string, NodeStatus>) => void | export type MessageHandler = (experimentInsId: number, status: string, finishedAt: string, nodes: Record<string, NodeStatus>) => void | ||||
| export const useSSE = (experimentInsId: number, status: ExperimentStatus, name: string, namespace: string, onMessage: MessageHandler) => { | export const useSSE = (experimentInsId: number, status: ExperimentStatus, name: string, namespace: string, onMessage: MessageHandler) => { | ||||
| const isRunning = status === ExperimentStatus.Pending || status === ExperimentStatus.Running | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (status === ExperimentStatus.Pending || status === ExperimentStatus.Running) { | |||||
| if (isRunning) { | |||||
| const { origin } = location; | const { origin } = location; | ||||
| const params = encodeURIComponent(`metadata.namespace=${namespace},metadata.name=${name}`); | const params = encodeURIComponent(`metadata.namespace=${namespace},metadata.name=${name}`); | ||||
| const evtSource = new EventSource( | const evtSource = new EventSource( | ||||
| @@ -35,5 +36,5 @@ export const useSSE = (experimentInsId: number, status: ExperimentStatus, name: | |||||
| } | } | ||||
| } | } | ||||
| }, [experimentInsId, status, name, namespace, onMessage]); | |||||
| }, [experimentInsId, isRunning, name, namespace, onMessage]); | |||||
| }; | }; | ||||
| @@ -11,44 +11,43 @@ import { useCallback, useEffect, useState } from 'react'; | |||||
| let globalTimeOffset: number | undefined = undefined; | let globalTimeOffset: number | undefined = undefined; | ||||
| export const globalGetSeverTime = async () => { | export const globalGetSeverTime = async () => { | ||||
| const requestStartTime = Date.now() | |||||
| const requestStartTime = Date.now(); | |||||
| const [res] = await to(getSeverTimeReq()); | const [res] = await to(getSeverTimeReq()); | ||||
| const requestEndTime = Date.now() | |||||
| const requestEndTime = Date.now(); | |||||
| const requestDuration = (requestEndTime - requestStartTime) / 2; | const requestDuration = (requestEndTime - requestStartTime) / 2; | ||||
| if (res && res.data) { | if (res && res.data) { | ||||
| const serverDate = new Date(res.data); | const serverDate = new Date(res.data); | ||||
| const timeOffset = serverDate.getTime() + requestDuration - requestEndTime ; | |||||
| const timeOffset = serverDate.getTime() + requestDuration - requestEndTime; | |||||
| globalTimeOffset = timeOffset; | globalTimeOffset = timeOffset; | ||||
| return timeOffset | |||||
| return timeOffset; | |||||
| } | } | ||||
| }; | }; | ||||
| export const now = () => { | export const now = () => { | ||||
| return new Date(Date.now() + (globalTimeOffset ?? 0)) | |||||
| } | |||||
| return new Date(Date.now() + (globalTimeOffset ?? 0)); | |||||
| }; | |||||
| /** 获取服务器时间 */ | /** 获取服务器时间 */ | ||||
| export function useServerTime() { | export function useServerTime() { | ||||
| const [timeOffset, setTimeOffset] = useState<number>(globalTimeOffset ?? 0); | const [timeOffset, setTimeOffset] = useState<number>(globalTimeOffset ?? 0); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| // 获取服务器时间 | |||||
| const getSeverTime = async () => { | const getSeverTime = async () => { | ||||
| const [res] = await to(globalGetSeverTime()); | const [res] = await to(globalGetSeverTime()); | ||||
| if (res) { | if (res) { | ||||
| setTimeOffset(res) | |||||
| setTimeOffset(res); | |||||
| } | } | ||||
| }; | }; | ||||
| // 获取服务器时间,防止第一次加载时,请求失败 | |||||
| if (!globalTimeOffset) { | if (!globalTimeOffset) { | ||||
| getSeverTime(); | getSeverTime(); | ||||
| } | } | ||||
| }, []); | }, []); | ||||
| const now = useCallback(() => { | const now = useCallback(() => { | ||||
| return new Date(Date.now() + timeOffset) | |||||
| }, [timeOffset]) | |||||
| return new Date(Date.now() + timeOffset); | |||||
| }, [timeOffset]); | |||||
| return [now, timeOffset] as const; | |||||
| return [now] as const; | |||||
| } | } | ||||
| @@ -1,3 +1,5 @@ | |||||
| @cellWidth: calc(100% + 32px + 33px - 48px - 200px - 344px); | |||||
| .tableExpandBox { | .tableExpandBox { | ||||
| display: flex; | display: flex; | ||||
| align-items: center; | align-items: center; | ||||
| @@ -11,22 +13,22 @@ | |||||
| } | } | ||||
| .check { | .check { | ||||
| width: calc((100% + 32px + 33px) / 5 / 2); | |||||
| width: calc(@cellWidth * 3 / 20); // 15% | |||||
| } | } | ||||
| .index { | .index { | ||||
| width: calc((100% + 32px + 33px) / 5 / 2); | |||||
| width: calc(@cellWidth * 3 / 20); // 15% | |||||
| } | } | ||||
| .description { | .description { | ||||
| display: flex; | display: flex; | ||||
| flex: 1; | |||||
| align-items: center; | align-items: center; | ||||
| width: calc(@cellWidth / 2); // 50% | |||||
| } | } | ||||
| .startTime { | .startTime { | ||||
| .singleLine(); | .singleLine(); | ||||
| width: 200px; | |||||
| width: calc(@cellWidth / 5); // 20% | |||||
| } | } | ||||
| .status { | .status { | ||||
| @@ -302,7 +302,7 @@ function ExperimentList({ type }: ExperimentListProps) { | |||||
| title: '类型', | title: '类型', | ||||
| dataIndex: 'type', | dataIndex: 'type', | ||||
| key: 'type', | key: 'type', | ||||
| width: '10%', | |||||
| width: '15%', | |||||
| render: tableCellRender(false, TableCellValueType.Enum, { | render: tableCellRender(false, TableCellValueType.Enum, { | ||||
| options: autoMLTypeOptions, | options: autoMLTypeOptions, | ||||
| }), | }), | ||||
| @@ -316,7 +316,7 @@ function ExperimentList({ type }: ExperimentListProps) { | |||||
| title: '实验名称', | title: '实验名称', | ||||
| dataIndex: config.nameProperty, | dataIndex: config.nameProperty, | ||||
| key: 'name', | key: 'name', | ||||
| width: '20%', | |||||
| width: '30%', | |||||
| render: tableCellRender(false, TableCellValueType.Link, { | render: tableCellRender(false, TableCellValueType.Link, { | ||||
| onClick: gotoDetail, | onClick: gotoDetail, | ||||
| }), | }), | ||||
| @@ -326,13 +326,14 @@ function ExperimentList({ type }: ExperimentListProps) { | |||||
| dataIndex: config.descProperty, | dataIndex: config.descProperty, | ||||
| key: 'description', | key: 'description', | ||||
| render: tableCellRender(true), | render: tableCellRender(true), | ||||
| width: type === ExperimentListType.AutoML ? '35%' : '50%', | |||||
| }, | }, | ||||
| ...diffColumns, | ...diffColumns, | ||||
| { | { | ||||
| title: '创建时间', | title: '创建时间', | ||||
| dataIndex: 'update_time', | dataIndex: 'update_time', | ||||
| key: 'update_time', | key: 'update_time', | ||||
| width: 200, | |||||
| width: '20%', | |||||
| render: tableCellRender(false, TableCellValueType.Date), | render: tableCellRender(false, TableCellValueType.Date), | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -58,5 +58,6 @@ | |||||
| align-items: center; | align-items: center; | ||||
| color: #808080; | color: #808080; | ||||
| font-size: 13px; | font-size: 13px; | ||||
| min-width: 0; | |||||
| } | } | ||||
| } | } | ||||
| @@ -14,6 +14,10 @@ type ResourceItemProps = { | |||||
| }; | }; | ||||
| function ResourceItem({ item, isPublic, onClick, onRemove }: ResourceItemProps) { | function ResourceItem({ item, isPublic, onClick, onRemove }: ResourceItemProps) { | ||||
| const timeAgo = | |||||
| '最近更新: ' + | |||||
| (item.update_time ? formatDate(item.update_time, 'YYYY-MM-DD') : item.time_ago ?? ''); | |||||
| const create_by = item.create_by ?? ''; | |||||
| return ( | return ( | ||||
| <div className={styles['resource-item']} onClick={() => onClick(item)}> | <div className={styles['resource-item']} onClick={() => onClick(item)}> | ||||
| <Flex justify="space-between" align="center" style={{ marginBottom: '20px', height: '32px' }}> | <Flex justify="space-between" align="center" style={{ marginBottom: '20px', height: '32px' }}> | ||||
| @@ -37,7 +41,7 @@ function ResourceItem({ item, isPublic, onClick, onRemove }: ResourceItemProps) | |||||
| )} | )} | ||||
| </Flex> | </Flex> | ||||
| <div className={styles['resource-item__description']}>{item.description}</div> | <div className={styles['resource-item__description']}>{item.description}</div> | ||||
| <Flex justify="space-between"> | |||||
| <Flex justify="space-between" gap={'0 8px'}> | |||||
| <div className={styles['resource-item__time']}> | <div className={styles['resource-item__time']}> | ||||
| <img | <img | ||||
| style={{ width: '17px', marginRight: '6px' }} | style={{ width: '17px', marginRight: '6px' }} | ||||
| @@ -45,14 +49,11 @@ function ResourceItem({ item, isPublic, onClick, onRemove }: ResourceItemProps) | |||||
| draggable={false} | draggable={false} | ||||
| alt="" | alt="" | ||||
| /> | /> | ||||
| <span>{item.create_by ?? ''}</span> | |||||
| <Typography.Text ellipsis={{ tooltip: create_by }}>{create_by}</Typography.Text> | |||||
| </div> | </div> | ||||
| <div className={styles['resource-item__time']}> | <div className={styles['resource-item__time']}> | ||||
| <img style={{ width: '12px', marginRight: '5px' }} src={clock} draggable={false} alt="" /> | <img style={{ width: '12px', marginRight: '5px' }} src={clock} draggable={false} alt="" /> | ||||
| <span> | |||||
| {'最近更新: '} | |||||
| {item.update_time ? formatDate(item.update_time, 'YYYY-MM-DD') : item.time_ago ?? ''} | |||||
| </span> | |||||
| <Typography.Text ellipsis={{ tooltip: timeAgo }}>{timeAgo}</Typography.Text> | |||||
| </div> | </div> | ||||
| </Flex> | </Flex> | ||||
| </div> | </div> | ||||
| @@ -1,3 +1,4 @@ | |||||
| import RunDuration from '@/components/RunDuration'; | |||||
| import { ExperimentStatus } from '@/enums'; | import { ExperimentStatus } from '@/enums'; | ||||
| import { useStateRef } from '@/hooks/useStateRef'; | import { useStateRef } from '@/hooks/useStateRef'; | ||||
| import { useVisible } from '@/hooks/useVisible'; | import { useVisible } from '@/hooks/useVisible'; | ||||
| @@ -5,7 +6,7 @@ import { getExperimentIns } from '@/services/experiment/index.js'; | |||||
| import { getWorkflowById } from '@/services/pipeline/index.js'; | import { getWorkflowById } from '@/services/pipeline/index.js'; | ||||
| import themes from '@/styles/theme.less'; | import themes from '@/styles/theme.less'; | ||||
| import { fittingString, parseJsonText } from '@/utils'; | import { fittingString, parseJsonText } from '@/utils'; | ||||
| import { elapsedTime, formatDate } from '@/utils/date'; | |||||
| import { formatDate } from '@/utils/date'; | |||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import G6, { Util } from '@antv/g6'; | import G6, { Util } from '@antv/g6'; | ||||
| import { Button } from 'antd'; | import { Button } from 'antd'; | ||||
| @@ -15,8 +16,6 @@ import ExperimentDrawer from '../components/ExperimentDrawer'; | |||||
| import ParamsModal from '../components/ViewParamsModal'; | 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 RunDuration from '@/components/RunDuration'; | |||||
| let graph = null; | let graph = null; | ||||
| @@ -476,7 +475,10 @@ function ExperimentText() { | |||||
| </div> | </div> | ||||
| <div className={styles['pipeline-container__top__info']}> | <div className={styles['pipeline-container__top__info']}> | ||||
| 执行时长: | 执行时长: | ||||
| <RunDuration createTime={experimentIns?.create_time} finishTime={experimentIns?.finish_time} /> | |||||
| <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']}> | ||||
| 状态: | 状态: | ||||
| @@ -36,6 +36,13 @@ | |||||
| .ant-btn-variant-text { | .ant-btn-variant-text { | ||||
| color: #565658; | color: #565658; | ||||
| } | } | ||||
| .anticon-question-circle { | |||||
| margin-top: -12px; | |||||
| margin-left: 1px !important; | |||||
| color: @text-color-tertiary !important; | |||||
| font-size: 12px !important; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -337,7 +337,11 @@ function CreateServiceVersion() { | |||||
| </Row> | </Row> | ||||
| <Row gutter={8}> | <Row gutter={8}> | ||||
| <Col span={10}> | <Col span={10}> | ||||
| <Form.Item label="代码配置" name="code_config"> | |||||
| <Form.Item | |||||
| label="代码配置" | |||||
| name="code_config" | |||||
| tooltip="此处代码配置为可引用的代码配置,具体代码编写指南见用户手册中服务部署模块" | |||||
| > | |||||
| <CodeSelect | <CodeSelect | ||||
| placeholder="请选择代码配置" | placeholder="请选择代码配置" | ||||
| canInput={false} | canInput={false} | ||||