From 90f959af63d00c967b04c710b36cff42e0f684ea Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Tue, 15 Oct 2024 14:21:36 +0800 Subject: [PATCH 1/8] =?UTF-8?q?fix:=20JSON.parse=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=B8=BAparseJsonText?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/src/hooks/pageCacheState.ts | 7 ++----- react-ui/src/pages/Experiment/Info/index.jsx | 4 ++-- react-ui/src/pages/Pipeline/Info/index.jsx | 6 +++--- .../Pipeline/components/PipelineNodeDrawer/index.tsx | 2 +- react-ui/src/pages/User/Login/index.tsx | 3 ++- react-ui/src/utils/index.ts | 2 +- react-ui/src/utils/localStorage.ts | 10 ++++------ react-ui/src/utils/sessionStorage.ts | 12 ++++-------- 8 files changed, 19 insertions(+), 27 deletions(-) diff --git a/react-ui/src/hooks/pageCacheState.ts b/react-ui/src/hooks/pageCacheState.ts index 9268a07a..e320b0a6 100644 --- a/react-ui/src/hooks/pageCacheState.ts +++ b/react-ui/src/hooks/pageCacheState.ts @@ -4,6 +4,7 @@ * @Description: 页面状态缓存,pop 回到这个页面的时候,重新构建之前的状态 */ +import { parseJsonText } from '@/utils'; import { useCallback, useState } from 'react'; const pageKeys: string[] = []; @@ -14,11 +15,7 @@ const getCacheState = (key: string) => { const jsonStr = sessionStorage.getItem(key); if (jsonStr) { removeCacheState(key); - try { - return JSON.parse(jsonStr); - } catch (error) { - return undefined; - } + return parseJsonText(jsonStr); } return undefined; }; diff --git a/react-ui/src/pages/Experiment/Info/index.jsx b/react-ui/src/pages/Experiment/Info/index.jsx index a958794b..c96d781e 100644 --- a/react-ui/src/pages/Experiment/Info/index.jsx +++ b/react-ui/src/pages/Experiment/Info/index.jsx @@ -3,7 +3,7 @@ import { useStateRef, useVisible } from '@/hooks'; import { getExperimentIns } from '@/services/experiment/index.js'; import { getWorkflowById } from '@/services/pipeline/index.js'; import themes from '@/styles/theme.less'; -import { fittingString } from '@/utils'; +import { fittingString, parseJsonText } from '@/utils'; import { elapsedTime, formatDate } from '@/utils/date'; import { to } from '@/utils/promise'; import G6, { Util } from '@antv/g6'; @@ -88,7 +88,7 @@ function ExperimentText() { setExperimentIns(res.data); const { status, nodes_status, argo_ins_ns, argo_ins_name } = res.data; const workflowData = workflowRef.current; - const experimentStatusObjs = JSON.parse(nodes_status); + const experimentStatusObjs = parseJsonText(nodes_status); workflowData.nodes.forEach((item) => { const experimentNode = experimentStatusObjs?.[item.id]; updateWorkflowNode(item, experimentNode); diff --git a/react-ui/src/pages/Pipeline/Info/index.jsx b/react-ui/src/pages/Pipeline/Info/index.jsx index b538fa50..3ae7ea59 100644 --- a/react-ui/src/pages/Pipeline/Info/index.jsx +++ b/react-ui/src/pages/Pipeline/Info/index.jsx @@ -2,7 +2,7 @@ import KFIcon from '@/components/KFIcon'; import { useStateRef, useVisible } from '@/hooks'; import { getWorkflowById, saveWorkflow } from '@/services/pipeline/index.js'; import themes from '@/styles/theme.less'; -import { fittingString, s8 } from '@/utils'; +import { fittingString, parseJsonText, s8 } from '@/utils'; import { to } from '@/utils/promise'; import G6 from '@antv/g6'; import { useNavigate, useParams } from '@umijs/max'; @@ -130,7 +130,7 @@ const EditPipeline = () => { // 渲染数据 const getGraphData = (data) => { - if (graph) { + if (graph && data) { graph.data(data); graph.render(); } else { @@ -283,7 +283,7 @@ const EditPipeline = () => { const { global_param, dag } = res.data; setGlobalParam(global_param || []); if (dag) { - getGraphData(JSON.parse(dag)); + getGraphData(parseJsonText(dag)); } } }; diff --git a/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx b/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx index bea129dd..2eae5c64 100644 --- a/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx +++ b/react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx @@ -80,7 +80,7 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete out_parameters: JSON.parse(model.out_parameters), control_strategy: JSON.parse(model.control_strategy), }; - console.log('model', nodeData); + // console.log('model', nodeData); setStagingItem({ ...nodeData, }); diff --git a/react-ui/src/pages/User/Login/index.tsx b/react-ui/src/pages/User/Login/index.tsx index a4585bfa..9ef18148 100644 --- a/react-ui/src/pages/User/Login/index.tsx +++ b/react-ui/src/pages/User/Login/index.tsx @@ -1,5 +1,6 @@ import { clearSessionToken, setSessionToken } from '@/access'; import { getCaptchaImg, login } from '@/services/system/auth'; +import { parseJsonText } from '@/utils'; import { safeInvoke } from '@/utils/functional'; import LocalStorage from '@/utils/localStorage'; import { to } from '@/utils/promise'; @@ -37,7 +38,7 @@ const Login = () => { const userJson = safeInvoke((text: string) => CryptoJS.AES.decrypt(text, AESKEY).toString(CryptoJS.enc.Utf8), )(userStorage); - const user = safeInvoke(JSON.parse)(userJson); + const user = safeInvoke(parseJsonText)(userJson); if (user && typeof user === 'object' && user.version === VERSION) { const { username, password } = user; form.setFieldsValue({ username: username, password: password, autoLogin: true }); diff --git a/react-ui/src/utils/index.ts b/react-ui/src/utils/index.ts index 01b6cb36..0af6f5aa 100644 --- a/react-ui/src/utils/index.ts +++ b/react-ui/src/utils/index.ts @@ -21,7 +21,7 @@ export function getNameByCode(list: any[], code: any) { // 解析 json 字符串 export function parseJsonText(text?: string | null): any | null { - if (!text) { + if (text === undefined || text === null || text === '') { return null; } try { diff --git a/react-ui/src/utils/localStorage.ts b/react-ui/src/utils/localStorage.ts index beb2c2b0..4d224465 100644 --- a/react-ui/src/utils/localStorage.ts +++ b/react-ui/src/utils/localStorage.ts @@ -1,3 +1,5 @@ +import { parseJsonText } from './index'; + export default class LocalStorage { // 登录的用户,包括用户名、密码和版本号 static readonly loginUserKey = 'login-user'; @@ -10,13 +12,9 @@ export default class LocalStorage { return jsonStr; } if (jsonStr) { - try { - return JSON.parse(jsonStr); - } catch (error) { - return undefined; - } + return parseJsonText(jsonStr); } - return undefined; + return null; } static setItem(key: string, state?: any, isObject: boolean = false) { diff --git a/react-ui/src/utils/sessionStorage.ts b/react-ui/src/utils/sessionStorage.ts index 701ef63c..41117e1e 100644 --- a/react-ui/src/utils/sessionStorage.ts +++ b/react-ui/src/utils/sessionStorage.ts @@ -1,3 +1,5 @@ +import { parseJsonText } from './index'; + export default class SessionStorage { // 用于新建镜像 static readonly mirrorNameKey = 'mirror-name'; @@ -7,8 +9,6 @@ export default class SessionStorage { static readonly serviceVersionInfoKey = 'service-version-info'; // 编辑器 url static readonly editorUrlKey = 'editor-url'; - // 数据集、模型资源 - static readonly resourceItemKey = 'resource-item'; static getItem(key: string, isObject: boolean = false) { const jsonStr = sessionStorage.getItem(key); @@ -16,13 +16,9 @@ export default class SessionStorage { return jsonStr; } if (jsonStr) { - try { - return JSON.parse(jsonStr); - } catch (error) { - return undefined; - } + return parseJsonText(jsonStr); } - return undefined; + return null; } static setItem(key: string, state?: any, isObject: boolean = false) { From a7c743e825a9866ddd434fe1e89cbd18cace5b9e Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Thu, 17 Oct 2024 10:52:45 +0800 Subject: [PATCH 2/8] =?UTF-8?q?fix:=20=E7=BB=9F=E4=B8=80tablecell=20render?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/CommonTableCell/index.tsx | 25 ----- .../src/components/DateTableCell/index.tsx | 20 ---- .../components/ResourceVersion/index.tsx | 23 ++--- .../DevelopmentEnvironment/List/index.tsx | 11 +-- .../src/pages/Experiment/Comparison/index.tsx | 13 +-- react-ui/src/pages/Experiment/index.jsx | 18 ++-- react-ui/src/pages/Mirror/Info/index.tsx | 11 +-- react-ui/src/pages/Mirror/List/index.tsx | 11 +-- .../src/pages/ModelDeployment/List/index.tsx | 28 +++--- .../ModelDeployment/ServiceInfo/index.tsx | 27 ++---- react-ui/src/pages/Pipeline/index.jsx | 27 +++--- react-ui/src/utils/table.tsx | 95 +++++++++++++++---- 12 files changed, 149 insertions(+), 160 deletions(-) delete mode 100644 react-ui/src/components/CommonTableCell/index.tsx delete mode 100644 react-ui/src/components/DateTableCell/index.tsx diff --git a/react-ui/src/components/CommonTableCell/index.tsx b/react-ui/src/components/CommonTableCell/index.tsx deleted file mode 100644 index c86ef9a9..00000000 --- a/react-ui/src/components/CommonTableCell/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * @Author: 赵伟 - * @Date: 2024-04-28 14:18:11 - * @Description: 自定义 Table 单元格,没有数据时展示 -- - */ - -import { Tooltip } from 'antd'; - -function renderCell(text?: any | null) { - return {text ?? '--'}; -} - -function CommonTableCell(ellipsis: boolean = false) { - if (ellipsis) { - return (text?: any | null) => ( - - {renderCell(text)} - - ); - } else { - return renderCell; - } -} - -export default CommonTableCell; diff --git a/react-ui/src/components/DateTableCell/index.tsx b/react-ui/src/components/DateTableCell/index.tsx deleted file mode 100644 index ea629ba7..00000000 --- a/react-ui/src/components/DateTableCell/index.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* - * @Author: 赵伟 - * @Date: 2024-04-28 14:18:11 - * @Description: 自定义 Table 日期类单元格 - */ - -import { formatDate } from '@/utils/date'; -import dayjs from 'dayjs'; - -function DateTableCell(text?: string | null) { - if (text === undefined || text === null || text === '') { - return --; - } - if (!dayjs(text).isValid()) { - return 无效的日期; - } - return {formatDate(text)}; -} - -export default DateTableCell; diff --git a/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx b/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx index b357ee00..4a6d190c 100644 --- a/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx +++ b/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx @@ -1,5 +1,3 @@ -import CommonTableCell from '@/components/CommonTableCell'; -import DateTableCell from '@/components/DateTableCell'; import KFIcon from '@/components/KFIcon'; import { ResourceData, @@ -8,7 +6,8 @@ import { resourceConfig, } from '@/pages/Dataset/config'; import { downLoadZip } from '@/utils/downloadfile'; -import { Button, Flex, Table } from 'antd'; +import tableCellRender, { TableCellValueType } from '@/utils/table'; +import { Button, Flex, Table, TableProps } from 'antd'; import styles from './index.less'; type ResourceVersionProps = { @@ -38,37 +37,33 @@ function ResourceVersion({ resourceType, info }: ResourceVersionProps) { downLoadZip(url, { url: record.url }); }; - const columns = [ + const columns: TableProps['columns'] = [ { title: '序号', dataIndex: 'index', key: 'index', width: 80, - render(_text: string, _record: ResourceFileData, index: number) { - return {index + 1}; - }, + render: tableCellRender(false, TableCellValueType.Index), }, { title: '文件名称', dataIndex: 'file_name', key: 'file_name', - render: (text: string, record: ResourceFileData) => ( - downloadAlone(record)}> - {text} - - ), + render: tableCellRender(false, TableCellValueType.Link, { + onClick: downloadAlone, + }), }, { title: '文件大小', dataIndex: 'file_size', key: 'file_size', - render: CommonTableCell(), + render: tableCellRender(), }, { title: '更新时间', dataIndex: 'update_time', key: 'update_time', - render: DateTableCell, + render: tableCellRender(false, TableCellValueType.Date), }, { title: '操作', diff --git a/react-ui/src/pages/DevelopmentEnvironment/List/index.tsx b/react-ui/src/pages/DevelopmentEnvironment/List/index.tsx index 3cbda163..b6a36e0f 100644 --- a/react-ui/src/pages/DevelopmentEnvironment/List/index.tsx +++ b/react-ui/src/pages/DevelopmentEnvironment/List/index.tsx @@ -4,8 +4,6 @@ * @Description: 开发环境列表 */ -import CommonTableCell from '@/components/CommonTableCell'; -import DateTableCell from '@/components/DateTableCell'; import KFIcon from '@/components/KFIcon'; import { DevEditorStatus } from '@/enums'; import { useCacheState } from '@/hooks/pageCacheState'; @@ -19,6 +17,7 @@ import themes from '@/styles/theme.less'; import { openAntdModal } from '@/utils/modal'; import { to } from '@/utils/promise'; import SessionStorage from '@/utils/sessionStorage'; +import tableCellRender, { TableCellValueType } from '@/utils/table'; import { modalConfirm } from '@/utils/ui'; import { useNavigate } from '@umijs/max'; import { @@ -153,7 +152,7 @@ function EditorList() { }; // 分页切换 - const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => { + const handleTableChange: TableProps['onChange'] = (pagination, _filters, _sorter, { action }) => { if (action === 'paginate') { setPagination(pagination); } @@ -186,21 +185,21 @@ function EditorList() { dataIndex: 'computing_resource', key: 'computing_resource', width: '20%', - render: CommonTableCell(), + render: tableCellRender(), }, { title: '创建者', dataIndex: 'update_by', key: 'update_by', width: '20%', - render: CommonTableCell(), + render: tableCellRender(), }, { title: '创建时间', dataIndex: 'create_time', key: 'create_time', width: '20%', - render: DateTableCell, + render: tableCellRender(false, TableCellValueType.Date), }, { title: '操作', diff --git a/react-ui/src/pages/Experiment/Comparison/index.tsx b/react-ui/src/pages/Experiment/Comparison/index.tsx index c4695d59..7c389c67 100644 --- a/react-ui/src/pages/Experiment/Comparison/index.tsx +++ b/react-ui/src/pages/Experiment/Comparison/index.tsx @@ -5,7 +5,7 @@ import { getExpTrainInfosReq, } from '@/services/experiment'; import { to } from '@/utils/promise'; -import tableCellRender, { arrayFormatter, dateFormatter } from '@/utils/table'; +import tableCellRender, { TableCellValueType } from '@/utils/table'; import { useSearchParams } from '@umijs/max'; import { App, Button, Table, /* TablePaginationConfig,*/ TableProps, Tooltip } from 'antd'; import classNames from 'classnames'; @@ -23,7 +23,7 @@ type TableData = { metrics_names: string[]; metrics: Record; params_names: string[]; - params: Record; + params: Record; }; function ExperimentComparison() { @@ -98,11 +98,12 @@ function ExperimentComparison() { }, }; - const columns: TableProps['columns'] = useMemo(() => { + const columns: TableProps['columns'] = useMemo(() => { const first: TableData | undefined = tableData[0]; return [ { title: '基本信息', + align: 'center', children: [ { title: '实例 ID', @@ -120,7 +121,7 @@ function ExperimentComparison() { width: 180, fixed: 'left', align: 'center', - render: tableCellRender(false, dateFormatter), + render: tableCellRender(false, TableCellValueType.Date), }, { title: '运行状态', @@ -128,7 +129,7 @@ function ExperimentComparison() { key: 'status', width: 100, fixed: 'left', - align: 'center', + // align: 'center', render: ExperimentStatusCell, }, { @@ -138,7 +139,7 @@ function ExperimentComparison() { width: 180, fixed: 'left', align: 'center', - render: tableCellRender(true, arrayFormatter()), + render: tableCellRender(true, TableCellValueType.Array), ellipsis: { showTitle: false }, }, ], diff --git a/react-ui/src/pages/Experiment/index.jsx b/react-ui/src/pages/Experiment/index.jsx index b09ba986..2d5bfba4 100644 --- a/react-ui/src/pages/Experiment/index.jsx +++ b/react-ui/src/pages/Experiment/index.jsx @@ -1,4 +1,3 @@ -import CommonTableCell from '@/components/CommonTableCell'; import KFIcon from '@/components/KFIcon'; import { ExperimentStatus, TensorBoardStatus } from '@/enums'; import { @@ -15,6 +14,7 @@ import { import { getWorkflow } from '@/services/pipeline/index.js'; import themes from '@/styles/theme.less'; import { to } from '@/utils/promise'; +import tableCellRender, { TableCellValueType } from '@/utils/table'; import { modalConfirm } from '@/utils/ui'; import { App, Button, ConfigProvider, Dropdown, Space, Table } from 'antd'; import classNames from 'classnames'; @@ -273,8 +273,7 @@ function Experiment() { }; // 跳转到流水线 - const gotoPipeline = (e, record) => { - e.stopPropagation(); + const gotoPipeline = (record) => { navigate({ pathname: `/pipeline/template/info/${record.workflow_id}` }); }; @@ -348,25 +347,23 @@ function Experiment() { title: '实验名称', dataIndex: 'name', key: 'name', - render: (text) =>
{text}
, + render: tableCellRender(), width: '16%', }, { title: '关联流水线名称', dataIndex: 'workflow_name', key: 'workflow_name', - render: (text, record) => ( - gotoPipeline(e, record)}> - {text} - - ), + render: tableCellRender(false, TableCellValueType.Link, { + onClick: gotoPipeline, + }), width: '16%', }, { title: '实验描述', dataIndex: 'description', key: 'description', - render: CommonTableCell(true), + render: tableCellRender(true), ellipsis: { showTitle: false }, }, { @@ -395,7 +392,6 @@ function Experiment() { ); }, }, - { title: '操作', key: 'action', diff --git a/react-ui/src/pages/Mirror/Info/index.tsx b/react-ui/src/pages/Mirror/Info/index.tsx index 7d5dcc17..a4100dbb 100644 --- a/react-ui/src/pages/Mirror/Info/index.tsx +++ b/react-ui/src/pages/Mirror/Info/index.tsx @@ -3,8 +3,6 @@ * @Date: 2024-04-16 13:58:08 * @Description: 镜像详情 */ -import CommonTableCell from '@/components/CommonTableCell'; -import DateTableCell from '@/components/DateTableCell'; import KFIcon from '@/components/KFIcon'; import PageTitle from '@/components/PageTitle'; import SubAreaTitle from '@/components/SubAreaTitle'; @@ -20,6 +18,7 @@ import themes from '@/styles/theme.less'; import { formatDate } from '@/utils/date'; import { to } from '@/utils/promise'; import SessionStorage from '@/utils/sessionStorage'; +import tableCellRender, { TableCellValueType } from '@/utils/table'; import { modalConfirm } from '@/utils/ui'; import { useNavigate, useParams } from '@umijs/max'; import { @@ -156,13 +155,13 @@ function MirrorInfo() { dataIndex: 'tag_name', key: 'tag_name', width: '25%', - render: CommonTableCell(), + render: tableCellRender(), }, { title: '镜像地址', dataIndex: 'url', key: 'url', - render: CommonTableCell(), + render: tableCellRender(), }, { title: '状态', @@ -176,14 +175,14 @@ function MirrorInfo() { dataIndex: 'file_size', key: 'file_size', width: 150, - render: CommonTableCell(), + render: tableCellRender(), }, { title: '创建时间', dataIndex: 'create_time', key: 'create_time', width: 200, - render: DateTableCell, + render: tableCellRender(false, TableCellValueType.Date), }, { title: '操作', diff --git a/react-ui/src/pages/Mirror/List/index.tsx b/react-ui/src/pages/Mirror/List/index.tsx index 1408dac8..0aee1808 100644 --- a/react-ui/src/pages/Mirror/List/index.tsx +++ b/react-ui/src/pages/Mirror/List/index.tsx @@ -3,8 +3,6 @@ * @Date: 2024-04-16 13:58:08 * @Description: 镜像列表 */ -import CommonTableCell from '@/components/CommonTableCell'; -import DateTableCell from '@/components/DateTableCell'; import KFIcon from '@/components/KFIcon'; import { CommonTabKeys } from '@/enums'; import { useCacheState } from '@/hooks/pageCacheState'; @@ -12,6 +10,7 @@ import { deleteMirrorReq, getMirrorListReq } from '@/services/mirror'; import themes from '@/styles/theme.less'; import { to } from '@/utils/promise'; import SessionStorage from '@/utils/sessionStorage'; +import tableCellRender, { TableCellValueType } from '@/utils/table'; import { modalConfirm } from '@/utils/ui'; import { useNavigate } from '@umijs/max'; import { @@ -169,21 +168,21 @@ function MirrorList() { dataIndex: 'name', key: 'name', width: '30%', - render: CommonTableCell(), + render: tableCellRender(), }, { title: '版本数据', dataIndex: 'version_count', key: 'version_count', width: '15%', - render: CommonTableCell(), + render: tableCellRender(), }, { title: '镜像描述', dataIndex: 'description', key: 'description', width: '35%', - render: CommonTableCell(true), + render: tableCellRender(true), ellipsis: { showTitle: false }, }, { @@ -191,7 +190,7 @@ function MirrorList() { dataIndex: 'create_time', key: 'create_time', width: '20%', - render: DateTableCell, + render: tableCellRender(false, TableCellValueType.Date), }, { title: '操作', diff --git a/react-ui/src/pages/ModelDeployment/List/index.tsx b/react-ui/src/pages/ModelDeployment/List/index.tsx index 2667f5a2..e6c77b18 100644 --- a/react-ui/src/pages/ModelDeployment/List/index.tsx +++ b/react-ui/src/pages/ModelDeployment/List/index.tsx @@ -3,8 +3,6 @@ * @Date: 2024-04-16 13:58:08 * @Description: 模型部署服务列表 */ -import CommonTableCell from '@/components/CommonTableCell'; -import DateTableCell from '@/components/DateTableCell'; import KFIcon from '@/components/KFIcon'; import PageTitle from '@/components/PageTitle'; import { serviceTypeOptions } from '@/enums'; @@ -13,6 +11,7 @@ import { deleteServiceReq, getServiceListReq } from '@/services/modelDeployment' import themes from '@/styles/theme.less'; import { to } from '@/utils/promise'; import SessionStorage from '@/utils/sessionStorage'; +import tableCellRender, { TableCellValueType } from '@/utils/table'; import { modalConfirm } from '@/utils/ui'; import { useNavigate } from '@umijs/max'; import { @@ -190,42 +189,39 @@ function ModelDeployment() { dataIndex: 'index', key: 'index', width: '20%', - render(_text, _record, index) { - return {(pagination.current! - 1) * pagination.pageSize! + index + 1}; - }, + render: tableCellRender(false, TableCellValueType.PageIndex, { + page: pagination.current! - 1, + pageSize: pagination.pageSize!, + }), }, { title: '服务名称', dataIndex: 'service_name', key: 'service_name', width: '20%', - render: (text, record) => { - return ( - toDetail(record)}> - {text} - - ); - }, + render: tableCellRender(false, TableCellValueType.Link, { + onClick: toDetail, + }), }, { title: '服务类型', dataIndex: 'service_type_name', key: 'service_type_name', width: '20%', - render: CommonTableCell(), + render: tableCellRender(), }, { title: '版本数量', dataIndex: 'version_count', key: 'version_count', width: '20%', - render: CommonTableCell(), + render: tableCellRender(), }, { title: '服务描述', dataIndex: 'description', key: 'description', - render: CommonTableCell(), + render: tableCellRender(), width: '20%', }, { @@ -233,7 +229,7 @@ function ModelDeployment() { dataIndex: 'update_time', key: 'update_time', width: '20%', - render: DateTableCell, + render: tableCellRender(false, TableCellValueType.Date), }, { title: '操作', diff --git a/react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx b/react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx index e14b829d..c00b1ea0 100644 --- a/react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx +++ b/react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx @@ -4,7 +4,6 @@ * @Description: 模型部署列表 */ import BasicInfo from '@/components/BasicInfo'; -import CommonTableCell from '@/components/CommonTableCell'; import KFIcon from '@/components/KFIcon'; import PageTitle from '@/components/PageTitle'; import SubAreaTitle from '@/components/SubAreaTitle'; @@ -21,6 +20,7 @@ import themes from '@/styles/theme.less'; import { formatDate } from '@/utils/date'; import { to } from '@/utils/promise'; import SessionStorage from '@/utils/sessionStorage'; +import tableCellRender, { TableCellValueType } from '@/utils/table'; import { modalConfirm } from '@/utils/ui'; import { useNavigate, useParams } from '@umijs/max'; import { @@ -222,31 +222,24 @@ function ServiceInfo() { dataIndex: 'index', key: 'index', width: '20%', - render(_text, _record, index) { - return {(pagination.current! - 1) * pagination.pageSize! + index + 1}; - }, + render: tableCellRender(false, TableCellValueType.PageIndex, { + page: pagination.current! - 1, + pageSize: pagination.pageSize!, + }), }, { title: '服务版本', dataIndex: 'version', key: 'version', width: '20%', - render: CommonTableCell(), + render: tableCellRender(), }, { title: '模型版本', - dataIndex: 'model', + dataIndex: ['model', 'show_value'], key: 'model', width: '20%', - render: (_text: string, record: ServiceVersionData) => ( - - {record.model.show_value} - - ), + render: tableCellRender(true), ellipsis: { showTitle: false }, }, { @@ -261,14 +254,14 @@ function ServiceInfo() { dataIndex: 'image', key: 'image', width: '20%', - render: CommonTableCell(true), + render: tableCellRender(true), ellipsis: { showTitle: false }, }, { title: '副本数量', dataIndex: 'replicas', key: 'replicas', - render: CommonTableCell(), + render: tableCellRender(), width: '20%', }, { diff --git a/react-ui/src/pages/Pipeline/index.jsx b/react-ui/src/pages/Pipeline/index.jsx index 371c3f4c..4374b24c 100644 --- a/react-ui/src/pages/Pipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/index.jsx @@ -1,5 +1,3 @@ -import CommonTableCell from '@/components/CommonTableCell'; -import DateTableCell from '@/components/DateTableCell'; import KFIcon from '@/components/KFIcon'; import KFModal from '@/components/KFModal'; import { @@ -11,6 +9,7 @@ import { removeWorkflow, } from '@/services/pipeline/index.js'; import themes from '@/styles/theme.less'; +import tableCellRender, { TableCellValueType } from '@/utils/table'; import { modalConfirm } from '@/utils/ui'; import { App, Button, ConfigProvider, Form, Input, Space, Table } from 'antd'; import classNames from 'classnames'; @@ -41,8 +40,7 @@ const Pipeline = () => { } }); }; - const routeToEdit = (e, record) => { - e.stopPropagation(); + const routeToEdit = (record) => { navigate({ pathname: `/pipeline/template/info/${record.id}` }); }; const showModal = () => { @@ -114,38 +112,37 @@ const Pipeline = () => { key: 'index', width: 120, align: 'center', - render(text, record, index) { - return {(pageOption.current.page - 1) * pageOption.current.size + index + 1}; - }, + render: tableCellRender(false, TableCellValueType.PageIndex, { + page: pageOption.current.page - 1, + size: pageOption.current.size, + }), }, { title: '流水线名称', dataIndex: 'name', key: 'name', - render: (text, record) => ( - routeToEdit(e, record)}> - {text} - - ), + render: tableCellRender(false, TableCellValueType.Link, { + onClick: routeToEdit, + }), }, { title: '流水线描述', dataIndex: 'description', key: 'description', - render: CommonTableCell(true), + render: tableCellRender(true), ellipsis: { showTitle: false }, }, { title: '创建时间', dataIndex: 'create_time', key: 'create_time', - render: DateTableCell, + render: tableCellRender(false, TableCellValueType.Date), }, { title: '修改时间', dataIndex: 'update_time', key: 'update_time', - render: DateTableCell, + render: tableCellRender(false, TableCellValueType.Date), }, { title: '操作', diff --git a/react-ui/src/utils/table.tsx b/react-ui/src/utils/table.tsx index 3058284a..1353fe09 100644 --- a/react-ui/src/utils/table.tsx +++ b/react-ui/src/utils/table.tsx @@ -1,22 +1,33 @@ /* * @Author: 赵伟 * @Date: 2024-06-26 10:05:52 - * @Description: 列表自定义 render + * @Description: Table cell 自定义 render */ import { formatDate } from '@/utils/date'; import { Tooltip } from 'antd'; import dayjs from 'dayjs'; -type TableCellFormatter = (value?: any | null) => string | undefined | null; +export enum TableCellValueType { + Index = 'Index', + PageIndex = 'PageIndex', + Text = 'Text', + Date = 'Date', + Array = 'Array', + Link = 'Link', +} -// 字符串转换函数 -export const stringFormatter: TableCellFormatter = (value?: any | null) => { - return value; +export type TableCellValueOptions = { + page?: number; + pageSize?: number; + property?: string; + onClick?: (record: T, e: React.MouseEvent) => void; }; +type TableCellFormatter = (value: any | undefined | null) => string | undefined | null; + // 日期转换函数 -export const dateFormatter: TableCellFormatter = (value?: any | null) => { +const formatDateText: TableCellFormatter = (value?: any | null) => { if (value === undefined || value === null || value === '') { return null; } @@ -26,8 +37,12 @@ export const dateFormatter: TableCellFormatter = (value?: any | null) => { return formatDate(value); }; -// 数组转换函数 -export function arrayFormatter(property?: string) { +/** + * 数组转换函数,将数组元素转换为字符串,用逗号分隔 + * @param {string} property 如果数组元素是对象,那么取数组元素的某个属性 + * @returns {TableCellFormatter} Table cell 渲染函数 + */ +function formatArray(property?: string): TableCellFormatter { return (value?: any | null): ReturnType => { if ( value === undefined || @@ -38,31 +53,75 @@ export function arrayFormatter(property?: string) { return null; } - let list = value; - if (property && typeof value[0] === 'object') { - list = value.map((item) => item[property]); - } + const list = + property && typeof value[0] === 'object' ? value.map((item) => item[property]) : value; return list.join(','); }; } -function tableCellRender(ellipsis: boolean = false, format: TableCellFormatter = stringFormatter) { - return (value?: any | null) => { - const text = format(value); +function tableCellRender( + ellipsis: boolean = false, + type: TableCellValueType = TableCellValueType.Text, + options?: TableCellValueOptions, +) { + return (value: any | undefined | null, record: T, index: number) => { + let text = value; + switch (type) { + case TableCellValueType.Index: + text = index + 1; + break; + case TableCellValueType.PageIndex: + text = (options?.page ?? 1) * (options?.pageSize ?? 10) + index + 1; + break; + case TableCellValueType.Text: + case TableCellValueType.Link: + text = value; + break; + case TableCellValueType.Date: + text = formatDateText(value); + break; + case TableCellValueType.Array: + text = formatArray(options?.property)(value); + break; + default: + break; + } + if (ellipsis && text) { return ( - {renderCell(text)} + {renderCell(text, type === TableCellValueType.Link, record, options?.onClick)} ); } else { - return renderCell(text); + return renderCell(text, type === TableCellValueType.Link, record, options?.onClick); } }; } -function renderCell(text?: any | null) { +function renderCell( + text: any | undefined | null, + isLink: boolean, + record: T, + onClick?: (record: T, e: React.MouseEvent) => void, +) { + return isLink ? renderLink(text, record, onClick) : renderText(text); +} + +function renderText(text: any | undefined | null) { return {text ?? '--'}; } +function renderLink( + text: any | undefined | null, + record: T, + onClick?: (record: T, e: React.MouseEvent) => void, +) { + return ( + onClick?.(record, e)}> + {text} + + ); +} + export default tableCellRender; From d8f65f337538ed5f86bf1f666464e3bcb489de7b Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Thu, 17 Oct 2024 15:01:32 +0800 Subject: [PATCH 3/8] =?UTF-8?q?chore:=20=E5=88=A0=E9=99=A4openapi=E7=9A=84?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/config/config.ts | 16 +- react-ui/config/oneapi.json | 593 ------------------ react-ui/src/services/ant-design-pro/api.ts | 11 - react-ui/src/services/ant-design-pro/index.ts | 12 - react-ui/src/services/ant-design-pro/login.ts | 38 -- react-ui/src/services/ant-design-pro/rule.ts | 42 -- .../src/services/ant-design-pro/typings.d.ts | 114 ---- react-ui/src/services/swagger/index.ts | 12 - react-ui/src/services/swagger/pet.ts | 153 ----- react-ui/src/services/swagger/store.ts | 48 -- react-ui/src/services/swagger/typings.d.ts | 112 ---- react-ui/src/services/swagger/user.ts | 100 --- 12 files changed, 1 insertion(+), 1250 deletions(-) delete mode 100644 react-ui/config/oneapi.json delete mode 100644 react-ui/src/services/ant-design-pro/api.ts delete mode 100644 react-ui/src/services/ant-design-pro/index.ts delete mode 100644 react-ui/src/services/ant-design-pro/login.ts delete mode 100644 react-ui/src/services/ant-design-pro/rule.ts delete mode 100644 react-ui/src/services/ant-design-pro/typings.d.ts delete mode 100644 react-ui/src/services/swagger/index.ts delete mode 100644 react-ui/src/services/swagger/pet.ts delete mode 100644 react-ui/src/services/swagger/store.ts delete mode 100644 react-ui/src/services/swagger/typings.d.ts delete mode 100644 react-ui/src/services/swagger/user.ts diff --git a/react-ui/config/config.ts b/react-ui/config/config.ts index 515b79cb..c10b23b6 100644 --- a/react-ui/config/config.ts +++ b/react-ui/config/config.ts @@ -1,6 +1,5 @@ // https://umijs.org/config/ import { defineConfig } from '@umijs/max'; -import { join } from 'path'; import defaultSettings from './defaultSettings'; import proxy from './proxy'; import routes from './routes'; @@ -145,20 +144,7 @@ export default defineConfig({ * @description 基于 openapi 的规范生成serve 和mock,能减少很多样板代码 * @doc https://pro.ant.design/zh-cn/docs/openapi/ */ - openAPI: [ - { - requestLibPath: "import { request } from '@umijs/max'", - // 或者使用在线的版本 - // schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json" - schemaPath: join(__dirname, 'oneapi.json'), - mock: false, - }, - { - requestLibPath: "import { request } from '@umijs/max'", - schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json', - projectName: 'swagger', - }, - ], + // openAPI: [], // mfsu: { // strategy: 'normal', // }, diff --git a/react-ui/config/oneapi.json b/react-ui/config/oneapi.json deleted file mode 100644 index c77d988b..00000000 --- a/react-ui/config/oneapi.json +++ /dev/null @@ -1,593 +0,0 @@ -{ - "openapi": "3.0.1", - "info": { - "title": "Ant Design Pro", - "version": "1.0.0" - }, - "servers": [ - { - "url": "http://localhost:8000/" - }, - { - "url": "https://localhost:8000/" - } - ], - "paths": { - "/api/currentUser": { - "get": { - "tags": ["api"], - "description": "获取当前的用户", - "operationId": "currentUser", - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CurrentUser" - } - } - } - }, - "401": { - "description": "Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - } - }, - "x-swagger-router-controller": "api" - }, - "/api/login/captcha": { - "post": { - "description": "发送验证码", - "operationId": "getFakeCaptcha", - "tags": ["login"], - "parameters": [ - { - "name": "phone", - "in": "query", - "description": "手机号", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FakeCaptcha" - } - } - } - } - } - } - }, - "/api/login/outLogin": { - "post": { - "description": "登录接口", - "operationId": "outLogin", - "tags": ["login"], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "object" - } - } - } - }, - "401": { - "description": "Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - } - }, - "x-swagger-router-controller": "api" - }, - "/api/login/account": { - "post": { - "tags": ["login"], - "description": "登录接口", - "operationId": "login", - "requestBody": { - "description": "登录系统", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginParams" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginResult" - } - } - } - }, - "401": { - "description": "Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "x-codegen-request-body-name": "body" - }, - "x-swagger-router-controller": "api" - }, - "/api/notices": { - "summary": "getNotices", - "description": "NoticeIconItem", - "get": { - "tags": ["api"], - "operationId": "getNotices", - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NoticeIconList" - } - } - } - } - } - } - }, - "/api/rule": { - "get": { - "tags": ["rule"], - "description": "获取规则列表", - "operationId": "rule", - "parameters": [ - { - "name": "current", - "in": "query", - "description": "当前的页码", - "schema": { - "type": "number" - } - }, - { - "name": "pageSize", - "in": "query", - "description": "页面的容量", - "schema": { - "type": "number" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RuleList" - } - } - } - }, - "401": { - "description": "Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - } - }, - "post": { - "tags": ["rule"], - "description": "新建规则", - "operationId": "addRule", - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RuleListItem" - } - } - } - }, - "401": { - "description": "Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - } - }, - "put": { - "tags": ["rule"], - "description": "新建规则", - "operationId": "updateRule", - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RuleListItem" - } - } - } - }, - "401": { - "description": "Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - } - }, - "delete": { - "tags": ["rule"], - "description": "删除规则", - "operationId": "removeRule", - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "object" - } - } - } - }, - "401": { - "description": "Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - } - }, - "x-swagger-router-controller": "api" - }, - "/swagger": { - "x-swagger-pipe": "swagger_raw" - } - }, - "components": { - "schemas": { - "CurrentUser": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "avatar": { - "type": "string" - }, - "userid": { - "type": "string" - }, - "email": { - "type": "string" - }, - "signature": { - "type": "string" - }, - "title": { - "type": "string" - }, - "group": { - "type": "string" - }, - "tags": { - "type": "array", - "items": { - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "label": { - "type": "string" - } - } - } - }, - "notifyCount": { - "type": "integer", - "format": "int32" - }, - "unreadCount": { - "type": "integer", - "format": "int32" - }, - "country": { - "type": "string" - }, - "access": { - "type": "string" - }, - "geographic": { - "type": "object", - "properties": { - "province": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "key": { - "type": "string" - } - } - }, - "city": { - "type": "object", - "properties": { - "label": { - "type": "string" - }, - "key": { - "type": "string" - } - } - } - } - }, - "address": { - "type": "string" - }, - "phone": { - "type": "string" - } - } - }, - "LoginResult": { - "type": "object", - "properties": { - "status": { - "type": "string" - }, - "type": { - "type": "string" - }, - "currentAuthority": { - "type": "string" - } - } - }, - "PageParams": { - "type": "object", - "properties": { - "current": { - "type": "number" - }, - "pageSize": { - "type": "number" - } - } - }, - "RuleListItem": { - "type": "object", - "properties": { - "key": { - "type": "integer", - "format": "int32" - }, - "disabled": { - "type": "boolean" - }, - "href": { - "type": "string" - }, - "avatar": { - "type": "string" - }, - "name": { - "type": "string" - }, - "owner": { - "type": "string" - }, - "desc": { - "type": "string" - }, - "callNo": { - "type": "integer", - "format": "int32" - }, - "status": { - "type": "integer", - "format": "int32" - }, - "updatedAt": { - "type": "string", - "format": "datetime" - }, - "createdAt": { - "type": "string", - "format": "datetime" - }, - "progress": { - "type": "integer", - "format": "int32" - } - } - }, - "RuleList": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RuleListItem" - } - }, - "total": { - "type": "integer", - "description": "列表的内容总数", - "format": "int32" - }, - "success": { - "type": "boolean" - } - } - }, - "FakeCaptcha": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "status": { - "type": "string" - } - } - }, - "LoginParams": { - "type": "object", - "properties": { - "username": { - "type": "string" - }, - "password": { - "type": "string" - }, - "autoLogin": { - "type": "boolean" - }, - "type": { - "type": "string" - } - } - }, - "ErrorResponse": { - "required": ["errorCode"], - "type": "object", - "properties": { - "errorCode": { - "type": "string", - "description": "业务约定的错误码" - }, - "errorMessage": { - "type": "string", - "description": "业务上的错误信息" - }, - "success": { - "type": "boolean", - "description": "业务上的请求是否成功" - } - } - }, - "NoticeIconList": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NoticeIconItem" - } - }, - "total": { - "type": "integer", - "description": "列表的内容总数", - "format": "int32" - }, - "success": { - "type": "boolean" - } - } - }, - "NoticeIconItemType": { - "title": "NoticeIconItemType", - "description": "已读未读列表的枚举", - "type": "string", - "properties": {}, - "enum": ["notification", "message", "event"] - }, - "NoticeIconItem": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "extra": { - "type": "string", - "format": "any" - }, - "key": { "type": "string" }, - "read": { - "type": "boolean" - }, - "avatar": { - "type": "string" - }, - "title": { - "type": "string" - }, - "status": { - "type": "string" - }, - "datetime": { - "type": "string", - "format": "date" - }, - "description": { - "type": "string" - }, - "type": { - "extensions": { - "x-is-enum": true - }, - "$ref": "#/components/schemas/NoticeIconItemType" - } - } - } - } - } -} diff --git a/react-ui/src/services/ant-design-pro/api.ts b/react-ui/src/services/ant-design-pro/api.ts deleted file mode 100644 index 64a950a7..00000000 --- a/react-ui/src/services/ant-design-pro/api.ts +++ /dev/null @@ -1,11 +0,0 @@ -// @ts-ignore -/* eslint-disable */ -import { request } from '@umijs/max'; - -/** 此处后端没有提供注释 GET /api/notices */ -export async function getNotices(options?: { [key: string]: any }) { - return request('/api/notices', { - method: 'GET', - ...(options || {}), - }); -} diff --git a/react-ui/src/services/ant-design-pro/index.ts b/react-ui/src/services/ant-design-pro/index.ts deleted file mode 100644 index 9ae58be7..00000000 --- a/react-ui/src/services/ant-design-pro/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -// @ts-ignore -/* eslint-disable */ -// API 更新时间: -// API 唯一标识: -import * as api from './api'; -import * as login from './login'; -import * as rule from './rule'; -export default { - api, - login, - rule, -}; diff --git a/react-ui/src/services/ant-design-pro/login.ts b/react-ui/src/services/ant-design-pro/login.ts deleted file mode 100644 index 3b00b436..00000000 --- a/react-ui/src/services/ant-design-pro/login.ts +++ /dev/null @@ -1,38 +0,0 @@ -// @ts-ignore -/* eslint-disable */ -import { request } from '@umijs/max'; - -/** 登录接口 POST /api/login/account */ -export async function login(body: API.LoginParams, options?: { [key: string]: any }) { - return request('/api/login/account', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - data: body, - ...(options || {}), - }); -} - -/** 发送验证码 POST /api/login/captcha */ -export async function getFakeCaptcha( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.getFakeCaptchaParams, - options?: { [key: string]: any }, -) { - return request('/api/login/captcha', { - method: 'POST', - params: { - ...params, - }, - ...(options || {}), - }); -} - -/** 登录接口 POST /api/login/outLogin */ -export async function outLogin(options?: { [key: string]: any }) { - return request>('/api/login/outLogin', { - method: 'POST', - ...(options || {}), - }); -} diff --git a/react-ui/src/services/ant-design-pro/rule.ts b/react-ui/src/services/ant-design-pro/rule.ts deleted file mode 100644 index 4b8ebc5b..00000000 --- a/react-ui/src/services/ant-design-pro/rule.ts +++ /dev/null @@ -1,42 +0,0 @@ -// @ts-ignore -/* eslint-disable */ -import { request } from '@umijs/max'; - -/** 获取规则列表 GET /api/rule */ -export async function rule( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.ruleParams, - options?: { [key: string]: any }, -) { - return request('/api/rule', { - method: 'GET', - params: { - ...params, - }, - ...(options || {}), - }); -} - -/** 新建规则 PUT /api/rule */ -export async function updateRule(options?: { [key: string]: any }) { - return request('/api/rule', { - method: 'PUT', - ...(options || {}), - }); -} - -/** 新建规则 POST /api/rule */ -export async function addRule(options?: { [key: string]: any }) { - return request('/api/rule', { - method: 'POST', - ...(options || {}), - }); -} - -/** 删除规则 DELETE /api/rule */ -export async function removeRule(options?: { [key: string]: any }) { - return request>('/api/rule', { - method: 'DELETE', - ...(options || {}), - }); -} diff --git a/react-ui/src/services/ant-design-pro/typings.d.ts b/react-ui/src/services/ant-design-pro/typings.d.ts deleted file mode 100644 index e94832c6..00000000 --- a/react-ui/src/services/ant-design-pro/typings.d.ts +++ /dev/null @@ -1,114 +0,0 @@ -declare namespace API { - type CurrentUser = UserInfo & { - signature?: string; - title?: string; - group?: string; - tags?: { key?: string; label?: string }[]; - notifyCount?: number; - unreadCount?: number; - country?: string; - access?: string; - geographic?: { - province?: { label?: string; key?: string }; - city?: { label?: string; key?: string }; - }; - address?: string; - phone?: string; - roleNames?: { - roleName?: string; - }[]; - }; - - type ErrorResponse = { - /** 业务约定的错误码 */ - errorCode: string; - /** 业务上的错误信息 */ - errorMessage?: string; - /** 业务上的请求是否成功 */ - success?: boolean; - }; - - type FakeCaptcha = { - code?: number; - status?: string; - }; - - type getFakeCaptchaParams = { - /** 手机号 */ - phone?: string; - }; - - type LoginParams = { - username?: string; - password?: string; - uuid?: string; - autoLogin?: boolean; - type?: string; - }; - - type LoginResult = { - code: number; - msg?: string; - type?: string; - data?: { - access_token?: string; - expires_in?: number; - }; - }; - - type NoticeIconItem = { - id?: string; - extra?: string; - key?: string; - read?: boolean; - avatar?: string; - title?: string; - status?: string; - datetime?: string; - description?: string; - type?: NoticeIconItemType; - }; - - type NoticeIconItemType = 'notification' | 'message' | 'event'; - - type NoticeIconList = { - data?: NoticeIconItem[]; - /** 列表的内容总数 */ - total?: number; - success?: boolean; - }; - - type PageParams = { - current?: number; - pageSize?: number; - }; - - type RuleList = { - data?: RuleListItem[]; - /** 列表的内容总数 */ - total?: number; - success?: boolean; - }; - - type RuleListItem = { - key?: number; - disabled?: boolean; - href?: string; - avatar?: string; - name?: string; - owner?: string; - desc?: string; - callNo?: number; - status?: number; - updatedAt?: string; - createdAt?: string; - progress?: number; - }; - - type ruleParams = { - /** 当前的页码 */ - current?: number; - /** 页面的容量 */ - pageSize?: number; - }; -} diff --git a/react-ui/src/services/swagger/index.ts b/react-ui/src/services/swagger/index.ts deleted file mode 100644 index 83cf97ca..00000000 --- a/react-ui/src/services/swagger/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -// @ts-ignore -/* eslint-disable */ -// API 更新时间: -// API 唯一标识: -import * as pet from './pet'; -import * as store from './store'; -import * as user from './user'; -export default { - pet, - store, - user, -}; diff --git a/react-ui/src/services/swagger/pet.ts b/react-ui/src/services/swagger/pet.ts deleted file mode 100644 index b887475a..00000000 --- a/react-ui/src/services/swagger/pet.ts +++ /dev/null @@ -1,153 +0,0 @@ -// @ts-ignore -/* eslint-disable */ -import { request } from '@umijs/max'; - -/** Update an existing pet PUT /pet */ -export async function updatePet(body: API.Pet, options?: { [key: string]: any }) { - return request('/pet', { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - data: body, - ...(options || {}), - }); -} - -/** Add a new pet to the store POST /pet */ -export async function addPet(body: API.Pet, options?: { [key: string]: any }) { - return request('/pet', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - data: body, - ...(options || {}), - }); -} - -/** Find pet by ID Returns a single pet GET /pet/${param0} */ -export async function getPetById( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.getPetByIdParams, - options?: { [key: string]: any }, -) { - const { petId: param0, ...queryParams } = params; - return request(`/pet/${param0}`, { - method: 'GET', - params: { ...queryParams }, - ...(options || {}), - }); -} - -/** Updates a pet in the store with form data POST /pet/${param0} */ -export async function updatePetWithForm( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.updatePetWithFormParams, - body: { name?: string; status?: string }, - options?: { [key: string]: any }, -) { - const { petId: param0, ...queryParams } = params; - const formData = new FormData(); - - Object.keys(body).forEach((ele) => { - const item = (body as any)[ele]; - - if (item !== undefined && item !== null) { - formData.append( - ele, - typeof item === 'object' && !(item instanceof File) ? JSON.stringify(item) : item, - ); - } - }); - - return request(`/pet/${param0}`, { - method: 'POST', - params: { ...queryParams }, - data: formData, - ...(options || {}), - }); -} - -/** Deletes a pet DELETE /pet/${param0} */ -export async function deletePet( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.deletePetParams & { - // header - api_key?: string; - }, - options?: { [key: string]: any }, -) { - const { petId: param0, ...queryParams } = params; - return request(`/pet/${param0}`, { - method: 'DELETE', - headers: {}, - params: { ...queryParams }, - ...(options || {}), - }); -} - -/** uploads an image POST /pet/${param0}/uploadImage */ -export async function uploadFile( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.uploadFileParams, - body: { additionalMetadata?: string; file?: string }, - file?: File, - options?: { [key: string]: any }, -) { - const { petId: param0, ...queryParams } = params; - const formData = new FormData(); - - if (file) { - formData.append('file', file); - } - - Object.keys(body).forEach((ele) => { - const item = (body as any)[ele]; - - if (item !== undefined && item !== null) { - formData.append( - ele, - typeof item === 'object' && !(item instanceof File) ? JSON.stringify(item) : item, - ); - } - }); - - return request(`/pet/${param0}/uploadImage`, { - method: 'POST', - params: { ...queryParams }, - data: formData, - requestType: 'form', - ...(options || {}), - }); -} - -/** Finds Pets by status Multiple status values can be provided with comma separated strings GET /pet/findByStatus */ -export async function findPetsByStatus( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.findPetsByStatusParams, - options?: { [key: string]: any }, -) { - return request('/pet/findByStatus', { - method: 'GET', - params: { - ...params, - }, - ...(options || {}), - }); -} - -/** Finds Pets by tags Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. GET /pet/findByTags */ -export async function findPetsByTags( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.findPetsByTagsParams, - options?: { [key: string]: any }, -) { - return request('/pet/findByTags', { - method: 'GET', - params: { - ...params, - }, - ...(options || {}), - }); -} diff --git a/react-ui/src/services/swagger/store.ts b/react-ui/src/services/swagger/store.ts deleted file mode 100644 index b9c689a6..00000000 --- a/react-ui/src/services/swagger/store.ts +++ /dev/null @@ -1,48 +0,0 @@ -// @ts-ignore -/* eslint-disable */ -import { request } from '@umijs/max'; - -/** Returns pet inventories by status Returns a map of status codes to quantities GET /store/inventory */ -export async function getInventory(options?: { [key: string]: any }) { - return request>('/store/inventory', { - method: 'GET', - ...(options || {}), - }); -} - -/** Place an order for a pet POST /store/order */ -export async function placeOrder(body: API.Order, options?: { [key: string]: any }) { - return request('/store/order', { - method: 'POST', - data: body, - ...(options || {}), - }); -} - -/** Find purchase order by ID For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions GET /store/order/${param0} */ -export async function getOrderById( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.getOrderByIdParams, - options?: { [key: string]: any }, -) { - const { orderId: param0, ...queryParams } = params; - return request(`/store/order/${param0}`, { - method: 'GET', - params: { ...queryParams }, - ...(options || {}), - }); -} - -/** Delete purchase order by ID For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors DELETE /store/order/${param0} */ -export async function deleteOrder( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.deleteOrderParams, - options?: { [key: string]: any }, -) { - const { orderId: param0, ...queryParams } = params; - return request(`/store/order/${param0}`, { - method: 'DELETE', - params: { ...queryParams }, - ...(options || {}), - }); -} diff --git a/react-ui/src/services/swagger/typings.d.ts b/react-ui/src/services/swagger/typings.d.ts deleted file mode 100644 index d06bcfcb..00000000 --- a/react-ui/src/services/swagger/typings.d.ts +++ /dev/null @@ -1,112 +0,0 @@ -declare namespace API { - type ApiResponse = { - code?: number; - type?: string; - message?: string; - }; - - type Category = { - id?: number; - name?: string; - }; - - type deleteOrderParams = { - /** ID of the order that needs to be deleted */ - orderId: number; - }; - - type deletePetParams = { - api_key?: string; - /** Pet id to delete */ - petId: number; - }; - - type deleteUserParams = { - /** The name that needs to be deleted */ - username: string; - }; - - type findPetsByStatusParams = { - /** Status values that need to be considered for filter */ - status: ('available' | 'pending' | 'sold')[]; - }; - - type findPetsByTagsParams = { - /** Tags to filter by */ - tags: string[]; - }; - - type getOrderByIdParams = { - /** ID of pet that needs to be fetched */ - orderId: number; - }; - - type getPetByIdParams = { - /** ID of pet to return */ - petId: number; - }; - - type getUserByNameParams = { - /** The name that needs to be fetched. Use user1 for testing. */ - username: string; - }; - - type loginUserParams = { - /** The user name for login */ - username: string; - /** The password for login in clear text */ - password: string; - }; - - type Order = { - id?: number; - petId?: number; - quantity?: number; - shipDate?: string; - /** Order Status */ - status?: 'placed' | 'approved' | 'delivered'; - complete?: boolean; - }; - - type Pet = { - id?: number; - category?: Category; - name: string; - photoUrls: string[]; - tags?: Tag[]; - /** pet status in the store */ - status?: 'available' | 'pending' | 'sold'; - }; - - type Tag = { - id?: number; - name?: string; - }; - - type updatePetWithFormParams = { - /** ID of pet that needs to be updated */ - petId: number; - }; - - type updateUserParams = { - /** name that need to be updated */ - username: string; - }; - - type uploadFileParams = { - /** ID of pet to update */ - petId: number; - }; - - type User = { - id?: number; - username?: string; - firstName?: string; - lastName?: string; - email?: string; - password?: string; - phone?: string; - /** User Status */ - userStatus?: number; - }; -} diff --git a/react-ui/src/services/swagger/user.ts b/react-ui/src/services/swagger/user.ts deleted file mode 100644 index 4dd6f421..00000000 --- a/react-ui/src/services/swagger/user.ts +++ /dev/null @@ -1,100 +0,0 @@ -// @ts-ignore -/* eslint-disable */ -import { request } from '@umijs/max'; - -/** Create user This can only be done by the logged in user. POST /user */ -export async function createUser(body: API.User, options?: { [key: string]: any }) { - return request('/user', { - method: 'POST', - data: body, - ...(options || {}), - }); -} - -/** Get user by user name GET /user/${param0} */ -export async function getUserByName( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.getUserByNameParams, - options?: { [key: string]: any }, -) { - const { username: param0, ...queryParams } = params; - return request(`/user/${param0}`, { - method: 'GET', - params: { ...queryParams }, - ...(options || {}), - }); -} - -/** Updated user This can only be done by the logged in user. PUT /user/${param0} */ -export async function updateUser( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.updateUserParams, - body: API.User, - options?: { [key: string]: any }, -) { - const { username: param0, ...queryParams } = params; - return request(`/user/${param0}`, { - method: 'PUT', - params: { ...queryParams }, - data: body, - ...(options || {}), - }); -} - -/** Delete user This can only be done by the logged in user. DELETE /user/${param0} */ -export async function deleteUser( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.deleteUserParams, - options?: { [key: string]: any }, -) { - const { username: param0, ...queryParams } = params; - return request(`/user/${param0}`, { - method: 'DELETE', - params: { ...queryParams }, - ...(options || {}), - }); -} - -/** Creates list of users with given input array POST /user/createWithArray */ -export async function createUsersWithArrayInput( - body: API.User[], - options?: { [key: string]: any }, -) { - return request('/user/createWithArray', { - method: 'POST', - data: body, - ...(options || {}), - }); -} - -/** Creates list of users with given input array POST /user/createWithList */ -export async function createUsersWithListInput(body: API.User[], options?: { [key: string]: any }) { - return request('/user/createWithList', { - method: 'POST', - data: body, - ...(options || {}), - }); -} - -/** Logs user into the system GET /user/login */ -export async function loginUser( - // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) - params: API.loginUserParams, - options?: { [key: string]: any }, -) { - return request('/user/login', { - method: 'GET', - params: { - ...params, - }, - ...(options || {}), - }); -} - -/** Logs out current logged in user session GET /user/logout */ -export async function logoutUser(options?: { [key: string]: any }) { - return request('/user/logout', { - method: 'GET', - ...(options || {}), - }); -} From b043ed02dc8dd81a75f9c99ed2b276e03c71955b Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Sat, 19 Oct 2024 09:51:38 +0800 Subject: [PATCH 4/8] =?UTF-8?q?feat:=20Table=20cell=20render=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=87=AA=E5=AE=9A=E4=B9=89=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/ModelDeployment/List/index.tsx | 2 +- .../ModelDeployment/ServiceInfo/index.tsx | 15 ++----- react-ui/src/pages/Pipeline/index.jsx | 4 +- react-ui/src/utils/date.ts | 2 +- react-ui/src/utils/table.tsx | 44 ++++++++++--------- 5 files changed, 32 insertions(+), 35 deletions(-) diff --git a/react-ui/src/pages/ModelDeployment/List/index.tsx b/react-ui/src/pages/ModelDeployment/List/index.tsx index e6c77b18..7f73322d 100644 --- a/react-ui/src/pages/ModelDeployment/List/index.tsx +++ b/react-ui/src/pages/ModelDeployment/List/index.tsx @@ -189,7 +189,7 @@ function ModelDeployment() { dataIndex: 'index', key: 'index', width: '20%', - render: tableCellRender(false, TableCellValueType.PageIndex, { + render: tableCellRender(false, TableCellValueType.Index, { page: pagination.current! - 1, pageSize: pagination.pageSize!, }), diff --git a/react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx b/react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx index c00b1ea0..42b80e87 100644 --- a/react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx +++ b/react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx @@ -30,7 +30,6 @@ import { Input, Select, Table, - Tooltip, type TablePaginationConfig, type TableProps, } from 'antd'; @@ -222,7 +221,7 @@ function ServiceInfo() { dataIndex: 'index', key: 'index', width: '20%', - render: tableCellRender(false, TableCellValueType.PageIndex, { + render: tableCellRender(false, TableCellValueType.Index, { page: pagination.current! - 1, pageSize: pagination.pageSize!, }), @@ -269,15 +268,9 @@ function ServiceInfo() { dataIndex: 'resource', key: 'resource', width: '20%', - render: (resource: string) => ( - - {resource ? getResourceDescription(resource) : '--'} - - ), + render: tableCellRender(true, TableCellValueType.Custom, { + format: getResourceDescription, + }), ellipsis: { showTitle: false }, }, { diff --git a/react-ui/src/pages/Pipeline/index.jsx b/react-ui/src/pages/Pipeline/index.jsx index 4374b24c..0d1faf6c 100644 --- a/react-ui/src/pages/Pipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/index.jsx @@ -112,9 +112,9 @@ const Pipeline = () => { key: 'index', width: 120, align: 'center', - render: tableCellRender(false, TableCellValueType.PageIndex, { + render: tableCellRender(false, TableCellValueType.Index, { page: pageOption.current.page - 1, - size: pageOption.current.size, + pageSize: pageOption.current.size, }), }, { diff --git a/react-ui/src/utils/date.ts b/react-ui/src/utils/date.ts index 50b9e7e7..fbc83e35 100644 --- a/react-ui/src/utils/date.ts +++ b/react-ui/src/utils/date.ts @@ -79,7 +79,7 @@ export const canBeConvertToDate = (date?: Date | string | number | null): boolea * @return {string} The formatted date string. */ export const formatDate = ( - date?: Date | string | number | null, + date: Date | string | number | null | undefined, format: string = 'YYYY-MM-DD HH:mm:ss', ): string => { if (date === undefined || date === null || date === '') { diff --git a/react-ui/src/utils/table.tsx b/react-ui/src/utils/table.tsx index 1353fe09..0d4b1927 100644 --- a/react-ui/src/utils/table.tsx +++ b/react-ui/src/utils/table.tsx @@ -10,32 +10,36 @@ import dayjs from 'dayjs'; export enum TableCellValueType { Index = 'Index', - PageIndex = 'PageIndex', Text = 'Text', Date = 'Date', Array = 'Array', Link = 'Link', + Custom = 'Custom', } export type TableCellValueOptions = { - page?: number; - pageSize?: number; - property?: string; - onClick?: (record: T, e: React.MouseEvent) => void; + page?: number; // 类型为 Index 时有效 + pageSize?: number; // 类型为 Index 时有效 + property?: string; // 类型为 Array 时有效 + dateFormat?: string; // 类型为 Date 时有效 + onClick?: (record: T, e: React.MouseEvent) => void; // 类型为 Link 时有效 + format?: (value: any | undefined | null, record: T, index: number) => string | undefined | null; // 类型为 Custom 时有效 }; type TableCellFormatter = (value: any | undefined | null) => string | undefined | null; // 日期转换函数 -const formatDateText: TableCellFormatter = (value?: any | null) => { - if (value === undefined || value === null || value === '') { - return null; - } - if (!dayjs(value).isValid()) { - return null; - } - return formatDate(value); -}; +function formatDateText(dateFormat?: string): TableCellFormatter { + return (value: any | undefined | null): ReturnType => { + if (value === undefined || value === null || value === '') { + return null; + } + if (!dayjs(value).isValid()) { + return null; + } + return formatDate(value, dateFormat); + }; +} /** * 数组转换函数,将数组元素转换为字符串,用逗号分隔 @@ -43,7 +47,7 @@ const formatDateText: TableCellFormatter = (value?: any | null) => { * @returns {TableCellFormatter} Table cell 渲染函数 */ function formatArray(property?: string): TableCellFormatter { - return (value?: any | null): ReturnType => { + return (value: any | undefined | null): ReturnType => { if ( value === undefined || value === null || @@ -68,21 +72,21 @@ function tableCellRender( let text = value; switch (type) { case TableCellValueType.Index: - text = index + 1; - break; - case TableCellValueType.PageIndex: - text = (options?.page ?? 1) * (options?.pageSize ?? 10) + index + 1; + text = (options?.page ?? 0) * (options?.pageSize ?? 0) + index + 1; break; case TableCellValueType.Text: case TableCellValueType.Link: text = value; break; case TableCellValueType.Date: - text = formatDateText(value); + text = formatDateText(options?.dateFormat)(value); break; case TableCellValueType.Array: text = formatArray(options?.property)(value); break; + case TableCellValueType.Custom: + text = options?.format?.(value, record, index); + break; default: break; } From 66c47749395b86eb5200e0d71f35d75c72b1d610 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Sat, 19 Oct 2024 09:57:49 +0800 Subject: [PATCH 5/8] =?UTF-8?q?style:=20Table=20=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E9=A2=9C=E8=89=B2=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/src/app.tsx | 11 ++--------- react-ui/src/components/RobotFrame/index.less | 2 +- react-ui/src/components/SubAreaTitle/index.tsx | 8 +++++--- react-ui/src/overrides.less | 6 ++++++ react-ui/src/pages/Experiment/Comparison/index.less | 2 +- .../Workspace/components/ExperimentChart/index.tsx | 10 +++++----- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/react-ui/src/app.tsx b/react-ui/src/app.tsx index e6a09fb5..4f911013 100644 --- a/react-ui/src/app.tsx +++ b/react-ui/src/app.tsx @@ -118,18 +118,10 @@ export const layout: RuntimeConfig['layout'] = ({ initialState }) => { width: '331px', }, ], - // links: isDev - // ? [ - // - // - // OpenAPI 文档 - // , - // ] - // : [], // 自定义 403 页面 // unAccessible:
unAccessible
, - // 增加一个 loading 的状态 childrenRender: (children) => { + // 增加一个 loading 的状态 // if (initialState?.loading) return ; return (
@@ -236,6 +228,7 @@ export const antd: RuntimeAntdConfig = (memo) => { memo.theme.components.Table = { headerBg: 'rgba(242, 244, 247, 0.36)', headerBorderRadius: 4, + rowSelectedBg: 'rgba(22, 100, 255, 0.05)', }; memo.theme.components.Tabs = { titleFontSize: 16, diff --git a/react-ui/src/components/RobotFrame/index.less b/react-ui/src/components/RobotFrame/index.less index e3e5662e..a203ecc3 100644 --- a/react-ui/src/components/RobotFrame/index.less +++ b/react-ui/src/components/RobotFrame/index.less @@ -23,7 +23,7 @@ width: 100%; height: 60px; padding: 0 15px; - border-bottom: 1px solid #e8e8e8; + border-bottom: 1px solid @border-color-base; } &__iframe { diff --git a/react-ui/src/components/SubAreaTitle/index.tsx b/react-ui/src/components/SubAreaTitle/index.tsx index 0458f715..cd07b206 100644 --- a/react-ui/src/components/SubAreaTitle/index.tsx +++ b/react-ui/src/components/SubAreaTitle/index.tsx @@ -9,7 +9,7 @@ import './index.less'; type SubAreaTitleProps = { title: string; - image: string; + image?: string; style?: React.CSSProperties; className?: string; }; @@ -17,8 +17,10 @@ type SubAreaTitleProps = { function SubAreaTitle({ title, image, style, className }: SubAreaTitleProps) { return (
- - {title} + {image && ( + + )} + {title}
); } diff --git a/react-ui/src/overrides.less b/react-ui/src/overrides.less index af9591fe..9e4b34cc 100644 --- a/react-ui/src/overrides.less +++ b/react-ui/src/overrides.less @@ -79,6 +79,12 @@ background-color: #fff; } +.ant-table-row-selected { + .ant-table-cell { + color: @primary-color; + } +} + .ant-pro-page-container { overflow-y: auto; } diff --git a/react-ui/src/pages/Experiment/Comparison/index.less b/react-ui/src/pages/Experiment/Comparison/index.less index 7a97a588..b9198e74 100644 --- a/react-ui/src/pages/Experiment/Comparison/index.less +++ b/react-ui/src/pages/Experiment/Comparison/index.less @@ -25,7 +25,7 @@ .ant-table-thead { .ant-table-cell { background-color: rgb(247, 247, 247); - border-color: #e8e8e8 !important; + border-color: @border-color-base !important; } } .ant-table-tbody { diff --git a/react-ui/src/pages/Workspace/components/ExperimentChart/index.tsx b/react-ui/src/pages/Workspace/components/ExperimentChart/index.tsx index 89c1f34d..3cede1ef 100644 --- a/react-ui/src/pages/Workspace/components/ExperimentChart/index.tsx +++ b/react-ui/src/pages/Workspace/components/ExperimentChart/index.tsx @@ -153,11 +153,11 @@ function ExperimentChart({ chartData, style }: ExperimentChartProps) { show: false, }, data: [ - { value: chartData.Failed > 0 ? chartData.Failed : null, name: '失败' }, - { value: chartData.Succeeded > 0 ? chartData.Succeeded : null, name: '成功' }, - { value: chartData.Terminated > 0 ? chartData.Terminated : null, name: '中止' }, - { value: chartData.Pending > 0 ? chartData.Pending : null, name: '等待' }, - { value: chartData.Running > 0 ? chartData.Running : null, name: '运行中' }, + { value: chartData.Failed > 0 ? chartData.Failed : undefined, name: '失败' }, + { value: chartData.Succeeded > 0 ? chartData.Succeeded : undefined, name: '成功' }, + { value: chartData.Terminated > 0 ? chartData.Terminated : undefined, name: '中止' }, + { value: chartData.Pending > 0 ? chartData.Pending : undefined, name: '等待' }, + { value: chartData.Running > 0 ? chartData.Running : undefined, name: '运行中' }, ], }, { From 0281084c92bfbfa568c781a20224b6ae981c76ef Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Sat, 19 Oct 2024 14:33:53 +0800 Subject: [PATCH 6/8] =?UTF-8?q?feat:=20=E5=AE=9E=E9=AA=8C=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=E6=89=B9=E9=87=8F=E5=88=A0=E9=99=A4=20&=20=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=AE=9E=E9=AA=8C=E6=B7=BB=E5=8A=A0=E3=80=90=E7=A1=AE?= =?UTF-8?q?=E5=AE=9A=E5=B9=B6=E8=BF=90=E8=A1=8C=E3=80=91=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/src/hooks/index.ts | 44 +++++++++++- .../components/CodeConfigItem/index.less | 2 +- .../components/AddExperimentModal/index.tsx | 35 ++++++++-- .../components/ExperimentInstance/index.less | 7 +- .../components/ExperimentInstance/index.tsx | 68 ++++++++++++++++++- react-ui/src/pages/Experiment/index.jsx | 34 +++++++--- 6 files changed, 169 insertions(+), 21 deletions(-) diff --git a/react-ui/src/hooks/index.ts b/react-ui/src/hooks/index.ts index adf61e7d..6f5bdbbc 100644 --- a/react-ui/src/hooks/index.ts +++ b/react-ui/src/hooks/index.ts @@ -5,7 +5,7 @@ */ import { FormInstance } from 'antd'; import { debounce } from 'lodash'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; /** * 生成具有初始值的状态引用 * @@ -156,3 +156,45 @@ export const useEffectWhen = (effect: () => void, deps: React.DependencyList, wh } }, [when]); }; + +// 选择、全选操作 +export const useCheck = (list: T[]) => { + const [selected, setSelected] = useState([]); + + const checked = useMemo(() => { + return selected.length === list.length; + }, [selected, list]); + + const indeterminate = useMemo(() => { + return selected.length > 0 && selected.length < list.length; + }, [selected, list]); + + const checkAll = useCallback(() => { + setSelected(checked ? [] : list); + }, [list, checked]); + + const isSingleChecked = useCallback((item: T) => selected.includes(item), [selected]); + + const checkSingle = useCallback( + (item: T) => { + setSelected((prev) => { + if (isSingleChecked(item)) { + return prev.filter((i) => i !== item); + } else { + return [...prev, item]; + } + }); + }, + [selected, isSingleChecked], + ); + + return [ + selected, + setSelected, + checked, + indeterminate, + checkAll, + isSingleChecked, + checkSingle, + ] as const; +}; diff --git a/react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.less b/react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.less index 1f1a9a92..c5d4abaa 100644 --- a/react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.less +++ b/react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.less @@ -39,7 +39,7 @@ } &__url { - margin-bottom: 10px; + margin-bottom: 10px !important; color: @text-color-secondary; font-size: 14px; } diff --git a/react-ui/src/pages/Experiment/components/AddExperimentModal/index.tsx b/react-ui/src/pages/Experiment/components/AddExperimentModal/index.tsx index 126e0557..4758a165 100644 --- a/react-ui/src/pages/Experiment/components/AddExperimentModal/index.tsx +++ b/react-ui/src/pages/Experiment/components/AddExperimentModal/index.tsx @@ -2,7 +2,8 @@ import createExperimentIcon from '@/assets/img/create-experiment.png'; import editExperimentIcon from '@/assets/img/edit-experiment.png'; import KFModal from '@/components/KFModal'; import { type PipelineGlobalParam } from '@/types'; -import { Form, Input, Radio, Select, type FormRule } from 'antd'; +import { to } from '@/utils/promise'; +import { Button, Form, Input, Radio, Select, type FormRule } from 'antd'; import { useState } from 'react'; import styles from './index.less'; @@ -17,7 +18,7 @@ type AddExperimentModalProps = { isAdd: boolean; open: boolean; onCancel: () => void; - onFinish: () => void; + onFinish: (values: any, isRun: boolean) => void; workflowList: Workflow[]; initialValues: FormData; }; @@ -113,25 +114,45 @@ function AddExperimentModal({ form.setFieldValue('global_param', []); } }; + + const handleRun = async (run: boolean) => { + const [values, error] = await to(form.validateFields()); + if (!error && values) { + onFinish(values, run); + } + }; + + const footer = [ + , + , + ]; + if (!isAdd) { + footer.push( + , + ); + } + return (
{ + return experimentInList?.map((item) => item.id) || []; + }, [experimentInList]); + const [ + selectedIns, + setSelectedIns, + checked, + indeterminate, + checkAll, + isSingleChecked, + checkSingle, + ] = useCheck(allIntanceIds); + + useEffect(() => { + // 关闭时清空 + if (allIntanceIds.length === 0) { + setSelectedIns([]); + } + }, [experimentInList]); // 删除实验实例确认 const handleRemove = (instance: ExperimentInstance) => { @@ -56,6 +78,26 @@ function ExperimentInstanceComponent({ } }; + // 批量删除实验实例确认 + const handleDeleteAll = () => { + modalConfirm({ + title: '确定批量删除选中的实例吗?', + onOk: () => { + batchDeleteExperimentInstances(); + }, + }); + }; + + // 批量删除实验实例 + const batchDeleteExperimentInstances = async () => { + const [res] = await to(deleteManyExperimentIns(selectedIns)); + if (res) { + message.success('删除成功'); + setSelectedIns([]); + onRemove?.(); + } + }; + // 终止实验实例 const terminateExperimentInstance = async (instance: ExperimentInstance) => { const [res] = await to(putQueryByExperimentInsId(instance.id)); @@ -72,6 +114,9 @@ function ExperimentInstanceComponent({ return (
+
+ +
序号
可视化
@@ -79,7 +124,20 @@ function ExperimentInstanceComponent({
开始时间
状态
-
操作
+
+ 操作 + {selectedIns.length > 0 && ( + + )} +
{experimentInList.map((item, index) => ( @@ -87,6 +145,12 @@ function ExperimentInstanceComponent({ key={item.id} className={classNames(styles.tableExpandBox, styles.tableExpandBoxContent)} > +
+ checkSingle(item.id)} + > +
{ - getList(); + getExperimentList(); getWorkflowList(); return () => { clearExperimentInTimers(); @@ -68,7 +68,7 @@ function Experiment() { }, []); // 获取实验列表 - const getList = async () => { + const getExperimentList = async () => { const params = { offset: 0, page: pageOption.current.page - 1, @@ -228,8 +228,8 @@ function Experiment() { setIsModalOpen(false); }; - // 创建或者编辑实验接口请求 - const handleAddExperiment = async (values) => { + // 创建或者编辑实验 + const handleAddExperiment = async (values, isRun) => { const global_param = JSON.stringify(values.global_param); if (!experimentId) { const params = { @@ -240,7 +240,7 @@ function Experiment() { if (res) { message.success('新建实验成功'); setIsModalOpen(false); - getList(); + getExperimentList(); } } else { const params = { ...values, global_param, id: experimentId }; @@ -248,7 +248,12 @@ function Experiment() { if (res) { message.success('编辑实验成功'); setIsModalOpen(false); - getList(); + getExperimentList(); + + // 确定并运行 + if (isRun) { + runExperiment(experimentId); + } } } }; @@ -259,7 +264,7 @@ function Experiment() { page: current, size: size, }; - getList(); + getExperimentList(); }; // 运行实验 const runExperiment = async (id) => { @@ -297,8 +302,16 @@ function Experiment() { } }; + // 刷新实验列表状态, + // 目前是直接刷新实验列表,后续需要优化,只刷新状态 + const refreshExperimentList = () => { + getExperimentList(); + }; + // 实验实例终止 const handleInstanceTerminate = async (experimentIn) => { + // 刷新实验列表 + refreshExperimentList(); setExperimentInList((prevList) => { return prevList.map((item) => { if (item.id === experimentIn.id) { @@ -448,7 +461,7 @@ function Experiment() { deleteExperimentById(record.id).then((ret) => { if (ret.code === 200) { message.success('删除成功'); - getList(); + getExperimentList(); } else { message.error(ret.msg); } @@ -485,7 +498,10 @@ function Experiment() { experimentInsTotal={experimentInsTotal} onClickInstance={(item) => gotoInstanceInfo(item, record)} onClickTensorBoard={handleTensorboard} - onRemove={() => refreshExperimentIns(record.id)} + onRemove={() => { + refreshExperimentIns(record.id); + refreshExperimentList(); + }} onTerminate={handleInstanceTerminate} onLoadMore={() => loadMoreExperimentIns()} > From 7259cfcfdbac294d380c62adc4e9703b8143d2ff Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Sat, 19 Oct 2024 14:34:12 +0800 Subject: [PATCH 7/8] =?UTF-8?q?feat:=20=E5=AE=9E=E9=AA=8C=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=E6=89=B9=E9=87=8F=E5=88=A0=E9=99=A4=20&=20=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=AE=9E=E9=AA=8C=E6=B7=BB=E5=8A=A0=E3=80=90=E7=A1=AE?= =?UTF-8?q?=E5=AE=9A=E5=B9=B6=E8=BF=90=E8=A1=8C=E3=80=91=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/src/services/experiment/index.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/react-ui/src/services/experiment/index.js b/react-ui/src/services/experiment/index.js index 0d4e431f..5431e526 100644 --- a/react-ui/src/services/experiment/index.js +++ b/react-ui/src/services/experiment/index.js @@ -40,6 +40,13 @@ export function deleteQueryByExperimentInsId(id) { method: 'DELETE', }); } +// 批量删除实验实例 +export function deleteManyExperimentIns(data) { + return request(`/api/mmp/experimentIns/batchDelete`, { + method: 'DELETE', + data, + }); +} // 根据id终止实验实例 export function putQueryByExperimentInsId(id) { return request(`/api/mmp/experimentIns/${id}`, { From 4c24faafe921791c9d44a4348f3a79e254864c31 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Sat, 19 Oct 2024 16:45:00 +0800 Subject: [PATCH 8/8] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E6=8C=87=E6=A0=87=E5=AF=B9=E6=AF=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/assets/img/metrics-title-icon.png | Bin 0 -> 536 bytes react-ui/src/assets/img/model-metrics.png | Bin 0 -> 1224 bytes react-ui/src/components/BasicInfo/index.less | 80 +++--- react-ui/src/components/BasicInfo/index.tsx | 106 ++++--- .../src/components/BasicTableInfo/index.less | 64 +++++ .../src/components/BasicTableInfo/index.tsx | 43 +++ .../components/ResourceInfo/index.less | 10 +- .../Dataset/components/ResourceInfo/index.tsx | 11 +- .../components/ResourceIntro/index.less | 27 +- .../components/ResourceIntro/index.tsx | 134 ++++----- .../components/ResourceVersion/index.less | 5 + .../components/ResourceVersion/index.tsx | 2 +- .../src/pages/Experiment/Comparison/index.tsx | 6 +- .../Experiment/components/LogGroup/index.tsx | 8 +- .../Experiment/components/LogList/index.tsx | 3 +- .../Model/components/MetricsChart/index.less | 29 ++ .../Model/components/MetricsChart/index.tsx | 174 ++++++++++++ .../Model/components/MetricsChart/tooltip.css | 33 +++ .../components/ModelEvolution/index.less | 7 +- .../Model/components/ModelMetrics/index.less | 35 +++ .../Model/components/ModelMetrics/index.tsx | 259 ++++++++++++++++++ react-ui/src/services/dataset/index.js | 16 ++ react-ui/src/services/experiment/index.js | 7 +- 23 files changed, 897 insertions(+), 162 deletions(-) create mode 100644 react-ui/src/assets/img/metrics-title-icon.png create mode 100644 react-ui/src/assets/img/model-metrics.png create mode 100644 react-ui/src/components/BasicTableInfo/index.less create mode 100644 react-ui/src/components/BasicTableInfo/index.tsx create mode 100644 react-ui/src/pages/Model/components/MetricsChart/index.less create mode 100644 react-ui/src/pages/Model/components/MetricsChart/index.tsx create mode 100644 react-ui/src/pages/Model/components/MetricsChart/tooltip.css create mode 100644 react-ui/src/pages/Model/components/ModelMetrics/index.less create mode 100644 react-ui/src/pages/Model/components/ModelMetrics/index.tsx diff --git a/react-ui/src/assets/img/metrics-title-icon.png b/react-ui/src/assets/img/metrics-title-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..66cd461fa4ccfbd764bcf2d147d02ee2e091b62c GIT binary patch literal 536 zcmV+z0_XjSP)?=hv?0&#*I3M%G z*kb9l0@XTg(i2;(n2$bAmPgae$rMoIDwJHy;{t9IG-UvkNCdcxT7nZ$`!Yl2%z1D{{Lde&D|?9ww+&vy!@7$PGj714eu_KObX#c|-KQdTF1>|MHCRKJBg= zFteK7l+xS%JdA%2J9Wa;^_wo}E$`Kl5!c4;Q>1N?c(Mv^;5h$|DS#fvE<`ZLFtlJ8 zMqw9*VZaC*f!&!E{^6hhlKltwS`TAOZ;`gCiOh06VRL&h) zzP?T&)&tq9i7yEw`h+jEu92q)Yhfg>{h%ucKB$FpC(uRP+d+TEzZ9wMtYaEvfhHI> zB;bP}!yJh#pM$Nhx1+4oGxY||>%e`c!MqW~{}0dzk9T3r^_F6~i9sI*kx{tFG-s1M zpKeyrMS*M&#AXG}8KkF&M#1zPn7)|Dv`k+ASSl~pR4X(hd*J25n2s>x$nE>vDUX?G z1k+{nbhElgS}Ecou}=u*&R=L)Qa_V zJ5Tc|!#pF_a@;CBxfInN&H8fTJdG=c2##8urz7n=-KacmGCgWCeYPb^({?@WbZX!6 zm&;D&>BJiSLEnn>cCRYRmZn*vx53o!+f`N#(@3jJ4=2QYC2N%RX(${L9dxY{g+Ln^Hcu{R zu!Gzk7|R1KV$rdsOGo)wQ}t*B(`5s(H9`M<;q=mvZyG^V?Wi}?=B4@_;4!)c#{IPa z^{b1r??Au+scmJ*-Svsc+*icvOs>;JuFfsF>xG-LGmzxR3g!0hRw>X0-K%6OMU%;7 z%+Tl5`P$f^DV7&DkMT{vboxPd`9i>3qPtbpy)uiR{R|iZcG+P) ztBI78Tiq_BCFgtN)=7HixlbzwYM+oz$>nIT%Lz1qjRV+df&MjQ0;N>D4glv+I~%*r z-7OUV3Ytn$W2Y@e=(MU{H-+(^Af@jQh{r4byhXZv3$oLfFeYupRLZ7y+2vww?kkQ5 zC(x!}jsu8l&B6CDceYIT;EZK&eC9e|PDJK)Y-?iLoXo~|c!&dsgXV1foCw!LZyrJQ mR>=AoI4)PzTHmgvu>AvCc%NYt4@D9H0000 string | BasicInfoLink | BasicInfoLink[] | undefined; }; @@ -18,45 +20,73 @@ type BasicInfoProps = { datas: BasicInfoData[]; className?: string; style?: React.CSSProperties; - labelWidth?: number; + labelWidth: number; }; -function BasicInfo({ datas, className, style, labelWidth = 100 }: BasicInfoProps) { +type BasicInfoItemProps = { + data: BasicInfoData; + labelWidth: number; + classPrefix: string; +}; + +type BasicInfoItemValueProps = BasicInfoLink & { + ellipsis?: boolean; + classPrefix: string; +}; + +export default function BasicInfo({ datas, className, style, labelWidth }: BasicInfoProps) { return (
{datas.map((item) => ( - + ))}
); } -type BasicInfoItemProps = { - data: BasicInfoData; - labelWidth?: number; -}; -function BasicInfoItem({ data, labelWidth = 100 }: BasicInfoItemProps) { - const { label, value, format } = data; +export function BasicInfoItem({ data, labelWidth, classPrefix }: BasicInfoItemProps) { + const { label, value, format, ellipsis } = data; const formatValue = format ? format(value) : value; + const myClassName = `${classPrefix}__item`; let valueComponent = undefined; if (Array.isArray(formatValue)) { valueComponent = ( -
+
{formatValue.map((item: BasicInfoLink) => ( - + ))}
); } else if (typeof formatValue === 'object' && formatValue) { valueComponent = ( - + ); } else { - valueComponent = ; + valueComponent = ( + + ); } return ( -
-
+
+
{label}
{valueComponent} @@ -64,35 +94,39 @@ function BasicInfoItem({ data, labelWidth = 100 }: BasicInfoItemProps) { ); } -type BasicInfoItemValueProps = { - value: string; - link?: string; - url?: string; -}; - -function BasicInfoItemValue({ value, link, url }: BasicInfoItemValueProps) { +export function BasicInfoItemValue({ + value, + link, + url, + ellipsis, + classPrefix, +}: BasicInfoItemValueProps) { + const myClassName = `${classPrefix}__item__value`; + let component = undefined; if (url && value) { - return ( -
+ component = ( + {value} ); } else if (link && value) { - return ( - + component = ( + {value} ); } else { - return ( -
{value ?? '--'}
- ); + component = {value ?? '--'}; } -} -export default BasicInfo; + return ( + + {component} + + ); +} diff --git a/react-ui/src/components/BasicTableInfo/index.less b/react-ui/src/components/BasicTableInfo/index.less new file mode 100644 index 00000000..cc3d0984 --- /dev/null +++ b/react-ui/src/components/BasicTableInfo/index.less @@ -0,0 +1,64 @@ +.kf-basic-table-info { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: stretch; + width: 100%; + border: 1px solid @border-color-base; + border-bottom: none; + border-radius: 4px; + + &__item { + display: flex; + align-items: stretch; + width: 25%; + border-bottom: 1px solid @border-color-base; + + &__label { + flex: none; + padding: 12px 20px; + color: @text-color-secondary; + font-size: 14px; + text-align: left; + background-color: .addAlpha(#606b7a, 0.05) []; + } + + &__value-container { + display: flex; + flex: 1; + flex-direction: column; + align-items: flex-start; + min-width: 0; + } + + &__value { + flex: 1; + margin: 0 !important; + padding: 12px 20px 4px; + font-size: @font-size; + white-space: pre-line; + word-break: break-all; + + & + & { + padding-top: 0; + } + + &:last-child { + padding-bottom: 12px; + } + + &--ellipsis { + .singleLine(); + } + + &__text { + color: @text-color; + } + + &__link:hover { + text-decoration: underline @underline-color; + text-underline-offset: 3px; + } + } + } +} diff --git a/react-ui/src/components/BasicTableInfo/index.tsx b/react-ui/src/components/BasicTableInfo/index.tsx new file mode 100644 index 00000000..df167ae2 --- /dev/null +++ b/react-ui/src/components/BasicTableInfo/index.tsx @@ -0,0 +1,43 @@ +import classNames from 'classnames'; +import { BasicInfoItem, type BasicInfoData, type BasicInfoLink } from '../BasicInfo'; +import './index.less'; +export type { BasicInfoData, BasicInfoLink }; + +type BasicTableInfoProps = { + datas: BasicInfoData[]; + className?: string; + style?: React.CSSProperties; + labelWidth: number; +}; + +export default function BasicTableInfo({ + datas, + className, + style, + labelWidth, +}: BasicTableInfoProps) { + const remainder = datas.length % 4; + const array = []; + if (remainder > 0) { + for (let i = 0; i < 4 - remainder; i++) { + array.push({ + label: '', + value: '', + }); + } + } + const showDatas = [...datas, ...array]; + + return ( +
+ {showDatas.map((item) => ( + + ))} +
+ ); +} diff --git a/react-ui/src/pages/Dataset/components/ResourceInfo/index.less b/react-ui/src/pages/Dataset/components/ResourceInfo/index.less index 6103b602..8cbba3d6 100644 --- a/react-ui/src/pages/Dataset/components/ResourceInfo/index.less +++ b/react-ui/src/pages/Dataset/components/ResourceInfo/index.less @@ -38,10 +38,6 @@ &__bottom { position: relative; height: calc(100% - 135px); - padding: 8px 30px 20px; - background: #ffffff; - border-radius: 10px; - box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); &__legend { position: absolute; @@ -52,6 +48,12 @@ :global { .ant-tabs { height: 100%; + .ant-tabs-nav-wrap { + padding-top: 8px; + padding-left: 30px; + background-color: white; + border-radius: 10px 10px 0 0; + } .ant-tabs-content-holder { height: 100%; .ant-tabs-content { diff --git a/react-ui/src/pages/Dataset/components/ResourceInfo/index.tsx b/react-ui/src/pages/Dataset/components/ResourceInfo/index.tsx index fe1e9a86..159ba9f1 100644 --- a/react-ui/src/pages/Dataset/components/ResourceInfo/index.tsx +++ b/react-ui/src/pages/Dataset/components/ResourceInfo/index.tsx @@ -164,7 +164,16 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { key: ResourceInfoTabKeys.Introduction, label: `${typeName}简介`, icon: , - children: , + children: ( + + ), }, { key: ResourceInfoTabKeys.Version, diff --git a/react-ui/src/pages/Dataset/components/ResourceIntro/index.less b/react-ui/src/pages/Dataset/components/ResourceIntro/index.less index 57d40216..6ac9223b 100644 --- a/react-ui/src/pages/Dataset/components/ResourceIntro/index.less +++ b/react-ui/src/pages/Dataset/components/ResourceIntro/index.less @@ -1,10 +1,25 @@ .resource-intro { width: 100%; - margin-top: 24px; - &__basic { - width: 100%; - } - &__usage { - width: 100%; + + &__top { + padding: 20px 30px; + background: white; + border-radius: 0 0 10px 10px; + box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); + + pre { + margin-bottom: 0 !important; + } + + &__title { + margin: 15px 0; + color: @text-color-secondary; + font-size: 14px; + } + + &__desc { + color: @text-color; + font-size: @font-size; + } } } diff --git a/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx b/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx index 2ee7fb24..0aa3b7e3 100644 --- a/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx +++ b/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx @@ -1,4 +1,4 @@ -import BasicInfo, { BasicInfoData } from '@/components/BasicInfo'; +import BasicTableInfo, { BasicInfoData } from '@/components/BasicTableInfo'; import SubAreaTitle from '@/components/SubAreaTitle'; import { ResourceInfoTabKeys } from '@/pages/Dataset/components/ResourceInfo'; import { @@ -8,13 +8,19 @@ import { ProjectDependency, ResourceType, TrainTask, + resourceConfig, } from '@/pages/Dataset/config'; +import ModelMetrics from '@/pages/Model/components/ModelMetrics'; import { getGitUrl } from '@/utils'; import styles from './index.less'; type ResourceIntroProps = { resourceType: ResourceType; info: DatasetData | ModelData; + resourceId: number; + identifier: string; + owner: string; + version?: string; }; const formatDataset = (datasets?: DatasetData[]) => { @@ -27,29 +33,6 @@ const formatDataset = (datasets?: DatasetData[]) => { })); }; -const formatParams = (map?: Record, space: string = '') => { - if (!map || Object.keys(map).length === 0) { - return undefined; - } - return Object.entries(map) - .map(([key, value]) => `${space}${key} : ${value}`) - .join('\n'); -}; - -const formatMetrics = (map?: Record) => { - if (!map || Object.keys(map).length === 0) { - return undefined; - } - return Object.entries(map) - .map(([key, value]) => { - if (typeof value === 'object' && value !== null) { - return `${key} : \n${formatParams(value, ' ')}`; - } - return `${key} : ${value}`; - }) - .join('\n'); -}; - const getProjectUrl = (project?: ProjectDependency) => { if (!project || !project.url || !project.branch) { return undefined; @@ -93,49 +76,50 @@ const getDatasetDatas = (data: DatasetData): BasicInfoData[] => [ { label: '数据集名称', value: data.name, + ellipsis: true, }, { label: '版本', value: data.version, + ellipsis: true, }, { label: '创建人', value: data.create_by, + ellipsis: true, }, { label: '更新时间', value: data.update_time, + ellipsis: true, }, { label: '数据来源', value: data.dataset_source, format: formatSource, + ellipsis: true, }, { label: '训练任务', value: data.train_task, format: formatTrainTask, + ellipsis: true, }, { label: '处理代码', value: data.processing_code, format: formatProject, + ellipsis: true, }, { label: '数据集分类', value: data.data_type, + ellipsis: true, }, { label: '研究方向', value: data.data_tag, - }, - { - label: '数据集描述', - value: data.description, - }, - { - label: '版本描述', - value: data.version_desc, + ellipsis: true, }, ]; @@ -143,77 +127,79 @@ const getModelDatas = (data: ModelData): BasicInfoData[] => [ { label: '模型名称', value: data.name, + ellipsis: true, }, { label: '版本', value: data.version, + ellipsis: true, }, { label: '创建人', value: data.create_by, + ellipsis: true, }, { label: '更新时间', value: data.update_time, + ellipsis: true, }, { label: '训练镜像', value: data.image, + ellipsis: true, }, { label: '训练代码', value: data.project_depency, format: formatProject, + ellipsis: true, }, { label: '训练数据集', value: data.train_datasets, format: formatDataset, + ellipsis: true, }, { label: '测试数据集', value: data.test_datasets, format: formatDataset, - }, - { - label: '参数', - value: data.params, - format: formatParams, - }, - { - label: '指标', - value: data.metrics, - format: formatMetrics, + ellipsis: true, }, { label: '模型来源', value: data.model_source, format: formatSource, + ellipsis: true, }, { label: '训练任务', value: data.train_task, format: formatTrainTask, + ellipsis: true, }, { label: '模型框架', value: data.model_type, + ellipsis: true, }, { label: '模型能力', value: data.model_tag, - }, - { - label: '模型描述', - value: data.description, - }, - { - label: '版本描述', - value: data.version_desc, + ellipsis: true, }, ]; -function ResourceIntro({ resourceType, info }: ResourceIntroProps) { +function ResourceIntro({ + resourceType, + info, + resourceId, + identifier, + owner, + version, +}: ResourceIntroProps) { + const config = resourceConfig[resourceType]; const basicDatas: BasicInfoData[] = resourceType === ResourceType.Dataset ? getDatasetDatas(info as DatasetData) @@ -221,23 +207,37 @@ function ResourceIntro({ resourceType, info }: ResourceIntroProps) { return (
- -
- +
+ +
+ +
+
{`${config.name}描述`}
+
{info.description ?? '暂无描述'}
+
版本描述
+
{info.version_desc ?? '暂无描述'}
+ +
- -
+ {resourceType === ResourceType.Model && version && ( + + )}
); } diff --git a/react-ui/src/pages/Dataset/components/ResourceVersion/index.less b/react-ui/src/pages/Dataset/components/ResourceVersion/index.less index d36c5ab6..e40591bd 100644 --- a/react-ui/src/pages/Dataset/components/ResourceVersion/index.less +++ b/react-ui/src/pages/Dataset/components/ResourceVersion/index.less @@ -1,4 +1,9 @@ .resource-version { + min-height: 100%; + padding: 20px 30px; color: @text-color; font-size: @font-size-content; + background: white; + border-radius: 0 0 10px 10px; + box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); } diff --git a/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx b/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx index 4a6d190c..44c54320 100644 --- a/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx +++ b/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx @@ -86,7 +86,7 @@ function ResourceVersion({ resourceType, info }: ResourceVersionProps) { return (
- +