From 24b2247443098d74b55032825b3cf980dbb85006 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Fri, 24 May 2024 14:07:29 +0800 Subject: [PATCH 01/11] =?UTF-8?q?fix:=20modal=20=E4=B8=8D=E8=83=BD?= =?UTF-8?q?=E4=BD=BF=E7=94=A8App.useApp()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/Dataset/components/AddDatasetModal/index.tsx | 3 +-- react-ui/src/pages/Dataset/components/AddModelModal/index.tsx | 3 +-- .../src/pages/Dataset/components/AddVersionModal/index.tsx | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx b/react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx index 177bf2a0..b55aa08c 100644 --- a/react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx +++ b/react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx @@ -7,7 +7,6 @@ import { getDictSelectOption } from '@/services/system/dict'; import { to } from '@/utils/promise'; import { getFileListFromEvent, validateUploadFiles } from '@/utils/ui'; import { - App, Button, Form, Input, @@ -15,6 +14,7 @@ import { Select, Upload, UploadFile, + message, type ModalProps, type UploadProps, } from 'antd'; @@ -32,7 +32,6 @@ interface AddDatasetModalProps extends Omit { function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalProps) { const [uuid] = useState(Date.now()); const [clusterOptions, setClusterOptions] = useState([]); - const { message } = App.useApp(); useEffect(() => { getClusterOptions(); diff --git a/react-ui/src/pages/Dataset/components/AddModelModal/index.tsx b/react-ui/src/pages/Dataset/components/AddModelModal/index.tsx index f4d68c53..f132fb05 100644 --- a/react-ui/src/pages/Dataset/components/AddModelModal/index.tsx +++ b/react-ui/src/pages/Dataset/components/AddModelModal/index.tsx @@ -6,13 +6,13 @@ import { addModel } from '@/services/dataset/index.js'; import { to } from '@/utils/promise'; import { getFileListFromEvent, validateUploadFiles } from '@/utils/ui'; import { - App, Button, Form, Input, Select, Upload, UploadFile, + message, type ModalProps, type UploadProps, } from 'antd'; @@ -28,7 +28,6 @@ interface AddModelModalProps extends Omit { function AddModelModal({ typeList, tagList, onOk, ...rest }: AddModelModalProps) { const [uuid] = useState(Date.now()); - const { message } = App.useApp(); // 上传组件参数 const uploadProps: UploadProps = { diff --git a/react-ui/src/pages/Dataset/components/AddVersionModal/index.tsx b/react-ui/src/pages/Dataset/components/AddVersionModal/index.tsx index c00569f7..839c8e20 100644 --- a/react-ui/src/pages/Dataset/components/AddVersionModal/index.tsx +++ b/react-ui/src/pages/Dataset/components/AddVersionModal/index.tsx @@ -5,12 +5,12 @@ import { ResourceType, resourceConfig } from '@/pages/Dataset/types'; import { to } from '@/utils/promise'; import { getFileListFromEvent, validateUploadFiles } from '@/utils/ui'; import { - App, Button, Form, Input, Upload, UploadFile, + message, type ModalProps, type UploadProps, } from 'antd'; @@ -33,7 +33,6 @@ function AddVersionModal({ ...rest }: AddVersionModalProps) { const [uuid] = useState(Date.now()); - const { message } = App.useApp(); // 上传组件参数 const uploadProps: UploadProps = { From 43efbd0771ea92c4eed87074fa6754bf9d0796f0 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Fri, 24 May 2024 15:08:35 +0800 Subject: [PATCH 02/11] =?UTF-8?q?fix:=20=E6=B2=A1=E6=9C=89=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E4=B8=8D=E8=AF=B7=E6=B1=82=E6=97=A5=E5=BF=97=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ExperimentResult/index.less | 5 ++ .../components/ExperimentResult/index.tsx | 56 ++++++++++--------- .../Experiment/components/LogGroup/index.tsx | 22 +++++++- .../Experiment/components/LogList/index.less | 10 ++++ .../Experiment/components/LogList/index.tsx | 8 ++- .../src/pages/Experiment/training/props.tsx | 3 +- 6 files changed, 73 insertions(+), 31 deletions(-) diff --git a/react-ui/src/pages/Experiment/components/ExperimentResult/index.less b/react-ui/src/pages/Experiment/components/ExperimentResult/index.less index 4a99e254..241e9713 100644 --- a/react-ui/src/pages/Experiment/components/ExperimentResult/index.less +++ b/react-ui/src/pages/Experiment/components/ExperimentResult/index.less @@ -35,4 +35,9 @@ } } } + + &__empty { + margin-top: 10px; + text-align: center; + } } diff --git a/react-ui/src/pages/Experiment/components/ExperimentResult/index.tsx b/react-ui/src/pages/Experiment/components/ExperimentResult/index.tsx index e010edeb..845d684f 100644 --- a/react-ui/src/pages/Experiment/components/ExperimentResult/index.tsx +++ b/react-ui/src/pages/Experiment/components/ExperimentResult/index.tsx @@ -23,34 +23,38 @@ function ExperimentResult({ results }: ExperimentResultProps) { return (
- {results?.map((item) => ( -
-
- {item.name} - - {/* 导出到模型库 + {results && results.length > 0 ? ( + results.map((item) => ( +
+
+ {item.name} + + {/* 导出到模型库 导出到数据集 */} -
-
- 文件名称 - 文件大小 -
- {item.value?.map((ele) => ( -
- {ele.name} - {ele.size}
- ))} -
- ))} +
+ 文件名称 + 文件大小 +
+ {item.value?.map((ele) => ( +
+ {ele.name} + {ele.size} +
+ ))} +
+ )) + ) : ( +
暂无结果
+ )}
); diff --git a/react-ui/src/pages/Experiment/components/LogGroup/index.tsx b/react-ui/src/pages/Experiment/components/LogGroup/index.tsx index f87d1d09..00cea44b 100644 --- a/react-ui/src/pages/Experiment/components/LogGroup/index.tsx +++ b/react-ui/src/pages/Experiment/components/LogGroup/index.tsx @@ -22,6 +22,20 @@ type Log = { log_content: string; // 日志内容 }; +const scrollToBottom = (smooth: boolean = true) => { + const element = document.getElementsByClassName('ant-tabs-content-holder')?.[0]; + if (element) { + if (smooth) { + element.scrollTo({ + top: element.scrollHeight, + behavior: 'smooth', + }); + } else { + element.scrollTo({ top: element.scrollHeight }); + } + } +}; + function LogGroup({ log_type = 'normal', pod_name = '', @@ -34,6 +48,7 @@ function LogGroup({ const [completed, setCompleted] = useState(false); useEffect(() => { + scrollToBottom(false); if (status === ExperimentStatus.Running) { const timerId = setInterval(() => { requestExperimentPodsLog(); @@ -56,6 +71,9 @@ function LogGroup({ const { log_detail } = res.data; if (log_detail && log_detail.log_content) { setLogList((oldList) => oldList.concat(log_detail)); + setTimeout(() => { + scrollToBottom(); + }, 100); } else { setCompleted(true); } @@ -96,7 +114,9 @@ function LogGroup({ {collapse ? : }
)} - {showLog &&
{logText}
} + {showLog && ( +
{logText ? logText : '暂无日志'}
+ )}
{showMoreBtn && (
); } diff --git a/react-ui/src/pages/Experiment/training/props.tsx b/react-ui/src/pages/Experiment/training/props.tsx index ccd51997..48d72c0d 100644 --- a/react-ui/src/pages/Experiment/training/props.tsx +++ b/react-ui/src/pages/Experiment/training/props.tsx @@ -109,7 +109,8 @@ const Props = forwardRef((_, ref) => { // 获取实验日志和实验结果 setExperimentLogList([]); setExperimentResults([]); - if (e.item && e.item.getModel()) { + // 如果已经运行到了 + if (e.item?.getModel()?.component_id) { const model = e.item.getModel(); const start_time = dayjs(model.experimentStartTime).valueOf() * 1.0e6; const params = { From 7e8935f47178aaabde0b6f7eafbe5df48d84566a Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Tue, 28 May 2024 08:40:43 +0800 Subject: [PATCH 03/11] =?UTF-8?q?fix:=20=E5=BC=B9=E6=A1=86=E7=A6=81?= =?UTF-8?q?=E6=AD=A2=E7=82=B9=E5=87=BB=E5=A4=96=E9=9D=A2=E5=85=B3=E9=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/src/components/KFModal/index.tsx | 11 ++++++++++- react-ui/src/pages/Pipeline/editPipeline/utils.tsx | 1 + react-ui/src/pages/Pipeline/index.jsx | 3 +-- react-ui/src/styles/menu.less | 4 ++-- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/react-ui/src/components/KFModal/index.tsx b/react-ui/src/components/KFModal/index.tsx index 8fea54bc..c073ab27 100644 --- a/react-ui/src/components/KFModal/index.tsx +++ b/react-ui/src/components/KFModal/index.tsx @@ -12,12 +12,21 @@ import './index.less'; export interface KFModalProps extends ModalProps { image?: string; } -function KFModal({ title, image, children, className = '', centered, ...rest }: KFModalProps) { +function KFModal({ + title, + image, + children, + className = '', + centered, + maskClosable, + ...rest +}: KFModalProps) { return ( } > {children} diff --git a/react-ui/src/pages/Pipeline/editPipeline/utils.tsx b/react-ui/src/pages/Pipeline/editPipeline/utils.tsx index ffe4eb76..ecb65acd 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/utils.tsx +++ b/react-ui/src/pages/Pipeline/editPipeline/utils.tsx @@ -77,6 +77,7 @@ export function getInParameterComponent( return null; } +// 判断是否允许输入 export function canInput(parameter: PipelineNodeModelParameter) { const { type, item_type } = parameter; return !( diff --git a/react-ui/src/pages/Pipeline/index.jsx b/react-ui/src/pages/Pipeline/index.jsx index 2b18793d..cf5fb571 100644 --- a/react-ui/src/pages/Pipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/index.jsx @@ -101,9 +101,8 @@ const Pipeline = () => { page: pageOption.current.page - 1, size: pageOption.current.size, }; - console.log(params, pageOption); getWorkflow(params).then((ret) => { - if (ret.code == 200) { + if (ret.code === 200) { setPipeList(ret.data.content); setTotal(ret.data.totalElements); diff --git a/react-ui/src/styles/menu.less b/react-ui/src/styles/menu.less index 29e3ed61..1d547ff1 100644 --- a/react-ui/src/styles/menu.less +++ b/react-ui/src/styles/menu.less @@ -4,7 +4,7 @@ display: flex; align-items: center; justify-content: flex-start; - font-size: 16px; + font-size: @font-size-content; .anticon.kf-menu-item__default-icon { display: inline !important; @@ -54,6 +54,6 @@ .ant-menu-submenu { .ant-menu-submenu-title:hover { - color: #1664ff !important; + color: @primary-color !important; } } From afc2fbef5f9f97460cc5648eedd2f76551bd60c5 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Tue, 28 May 2024 08:41:14 +0800 Subject: [PATCH 04/11] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=B5=81=E6=B0=B4=E7=BA=BF=E6=97=B6=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E5=9B=BE=E5=9C=A8=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/src/pages/Pipeline/editPipeline/index.jsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/react-ui/src/pages/Pipeline/editPipeline/index.jsx b/react-ui/src/pages/Pipeline/editPipeline/index.jsx index 350f94ec..3701ff25 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/editPipeline/index.jsx @@ -51,8 +51,16 @@ const EditPipeline = () => { return item.id === val.id; }); data.nodes[index] = val; + const zoom = graph.getZoom(); + // 在拉取新数据重新渲染页面之前先获取点(0, 0)在画布上的位置 + const lastPoint = graph.getCanvasByPoint(0, 0); graph.changeData(data); graph.render(); + graph.zoomTo(zoom); + // 获取重新渲染之后点(0, 0)在画布的位置 + const newPoint = graph.getCanvasByPoint(0, 0); + // 移动画布相对位移; + graph.translate(lastPoint.x - newPoint.x, lastPoint.y - newPoint.y); } }; const savePipeline = async (val) => { @@ -432,7 +440,7 @@ const EditPipeline = () => { height: graphRef.current.clientHeight || '100%', animate: false, groupByTypes: false, - fitView: false, + fitView: true, plugins: [contextMenu], enabledStack: true, modes: { From 05608a9b80f42c5a48e7038dfabb01f854172ed1 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Tue, 28 May 2024 13:01:00 +0800 Subject: [PATCH 05/11] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E6=B5=81?= =?UTF-8?q?=E6=B0=B4=E7=BA=BF=E7=BB=84=E4=BB=B6=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/src/pages/Experiment/index.jsx | 14 +-- react-ui/src/pages/Experiment/index.less | 9 +- .../ModelMenu/index.less} | 0 .../Pipeline/components/ModelMenu/index.tsx | 90 +++++++++++++++++++ .../src/pages/Pipeline/editPipeline/index.jsx | 6 +- .../Pipeline/editPipeline/modelMenus.jsx | 67 -------------- react-ui/src/types.ts | 4 +- 7 files changed, 112 insertions(+), 78 deletions(-) rename react-ui/src/pages/Pipeline/{editPipeline/modelMenus.less => components/ModelMenu/index.less} (100%) create mode 100644 react-ui/src/pages/Pipeline/components/ModelMenu/index.tsx delete mode 100644 react-ui/src/pages/Pipeline/editPipeline/modelMenus.jsx diff --git a/react-ui/src/pages/Experiment/index.jsx b/react-ui/src/pages/Experiment/index.jsx index 057eb4e4..a35591a1 100644 --- a/react-ui/src/pages/Experiment/index.jsx +++ b/react-ui/src/pages/Experiment/index.jsx @@ -18,7 +18,7 @@ import themes from '@/styles/theme.less'; import { elapsedTime, formatDate } from '@/utils/date'; import { to } from '@/utils/promise'; import { modalConfirm } from '@/utils/ui'; -import { App, Button, ConfigProvider, Space, Table } from 'antd'; +import { App, Button, ConfigProvider, Space, Table, Tooltip } from 'antd'; import classNames from 'classnames'; import { useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; @@ -279,14 +279,14 @@ function Experiment() { dataIndex: 'name', key: 'name', render: (text) =>
{text}
, - width: '20%', + width: '16%', }, { title: '关联流水线名称', dataIndex: 'workflow_name', key: 'workflow_name', render: (text, record) => routeToEdit(e, record)}>{text}, - width: '20%', + width: '16%', }, { title: '实验描述', @@ -443,13 +443,17 @@ function Experiment() {
{elapsedTime(item.create_time, item.finish_time)}
-
{formatDate(item.create_time)}
+
+ + {formatDate(item.create_time)} + +
{' '} + /> void; +}; +const ModelMenu = ({ onComponentDragEnd }: ModelMenuProps) => { + const [modelMenusList, setModelMenusList] = useState([]); + const [collapseItems, setCollapseItems] = useState([]); + + useEffect(() => { + getAllComponents(); + }, []); + + // 获取所有组件 + const getAllComponents = async () => { + const [res] = await to(getComponentAll()); + if (res && res.data) { + const menus = res.data as ModelMenuData[]; + setModelMenusList(menus); + const items = menus.map((item) => { + return { + key: item.key, + label: item.name, + children: item.value.map((ele) => { + return ( +
{ + dragEnd(e, ele); + }} + className={Styles.collapseItem} + > + {ele.icon_path && ( + + )} + {ele.component_label} +
+ ); + }), + }; + }); + setCollapseItems(items); + } + }; + + const dragEnd = (e: React.DragEvent, data: PipelineNodeModel) => { + onComponentDragEnd({ + ...data, + x: e.clientX, + y: e.clientY, + label: data.component_label, + img: `/assets/images/${data.icon_path}.png`, + }); + }; + + const defaultActiveKey = modelMenusList.map((item) => item.key + ''); + return ( +
+
组件库
+ {modelMenusList.length > 0 ? ( + + ) : null} +
+ ); +}; + +export default ModelMenu; diff --git a/react-ui/src/pages/Pipeline/editPipeline/index.jsx b/react-ui/src/pages/Pipeline/editPipeline/index.jsx index 3701ff25..e02ecd0f 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/editPipeline/index.jsx @@ -8,8 +8,8 @@ import { useEffect, useRef } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { s8 } from '../../../utils'; import GlobalParamsDrawer from '../components/GlobalParamsDrawer'; +import ModelMenu from '../components/ModelMenu'; import styles from './index.less'; -import ModelMenus from './modelMenus'; import Props from './props'; import { findAllParentNodes, findFirstDuplicate } from './utils'; @@ -97,7 +97,7 @@ const EditPipeline = () => { closeParamsDrawer(); setTimeout(() => { if (val) { - navgite({ pathname: `/pipeline` }); + navgite({ pathname: `/pipeline/template` }); } }, 500); }); @@ -699,7 +699,7 @@ const EditPipeline = () => { }; return (
- +
- ); -}; -export default ModelMenus; diff --git a/react-ui/src/types.ts b/react-ui/src/types.ts index 855584c6..605131a4 100644 --- a/react-ui/src/types.ts +++ b/react-ui/src/types.ts @@ -41,9 +41,11 @@ export type PipelineNodeModel = { control_strategy: string; in_parameters: string; out_parameters: string; + component_label: string; + icon_path: string; }; -// 流水线 +// 流水线节点模型数据 export type PipelineNodeModelParameter = { label: string; value: any; From 5c6fb6087ba91cfb9f9c64930623eb8c86952432 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Tue, 28 May 2024 13:02:35 +0800 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20=E6=A8=A1=E5=9E=8B=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E6=B7=BB=E5=8A=A0=E4=BD=BF=E7=94=A8=E6=8C=87=E5=8D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/ModelDeployment/Info/index.less | 45 ++- .../src/pages/ModelDeployment/Info/index.tsx | 266 ++++++++++-------- .../src/services/modelDeployment/index.ts | 8 + 3 files changed, 170 insertions(+), 149 deletions(-) diff --git a/react-ui/src/pages/ModelDeployment/Info/index.less b/react-ui/src/pages/ModelDeployment/Info/index.less index f1a0416c..aaeb8056 100644 --- a/react-ui/src/pages/ModelDeployment/Info/index.less +++ b/react-ui/src/pages/ModelDeployment/Info/index.less @@ -1,6 +1,16 @@ .model-deployment-info { height: 100%; + &__content { + display: flex; + flex-direction: column; + height: calc(100% - 60px); + margin-top: 10px; + padding: 30px 30px 0; + background-color: white; + border-radius: 10px; + } + &__basic { &__item { display: flex; @@ -23,34 +33,13 @@ } } - &__content { - height: calc(100% - 60px); + &__guide { + flex: 1; margin-top: 10px; - padding: 30px 30px 0; - background-color: white; - border-radius: 10px; - - &__title { - display: flex; - align-items: center; - } - - &__table { - :global { - .ant-table-wrapper { - height: 100%; - .ant-spin-nested-loading { - height: 100%; - } - .ant-spin-container { - height: 100%; - } - .ant-table { - height: calc(100% - 74px); - overflow: auto; - } - } - } - } + padding: 10px; + overflow-y: auto; + color: white; + white-space: pre-wrap; + background-color: rgba(0, 0, 0, 0.85); } } diff --git a/react-ui/src/pages/ModelDeployment/Info/index.tsx b/react-ui/src/pages/ModelDeployment/Info/index.tsx index bd809f68..c6025188 100644 --- a/react-ui/src/pages/ModelDeployment/Info/index.tsx +++ b/react-ui/src/pages/ModelDeployment/Info/index.tsx @@ -8,48 +8,70 @@ import PageTitle from '@/components/PageTitle'; import SubAreaTitle from '@/components/SubAreaTitle'; import { useComputingResource } from '@/hooks/resource'; import { useSessionStorage } from '@/hooks/sessionStorage'; +import { getModelDeploymentDocsReq } from '@/services/modelDeployment'; import { formatDate } from '@/utils/date'; +import { to } from '@/utils/promise'; import { modelDeploymentInfoKey } from '@/utils/sessionStorage'; import { Col, Row, Tabs, type TabsProps } from 'antd'; +import { pick } from 'lodash'; import { useEffect, useState } from 'react'; import ModelDeploymentStatusCell from '../components/ModelDeployStatusCell'; import { ModelDeploymentData } from '../types'; import styles from './index.less'; +export enum ModelDeploymentTabKey { + Predict = 'Predict', + Guide = 'Guide', + Log = 'Log', +} + const tabItems = [ { - key: '1', + key: ModelDeploymentTabKey.Predict, label: '预测', icon: , }, { - key: '2', + key: ModelDeploymentTabKey.Guide, label: '调用指南', icon: , }, { - key: '3', + key: ModelDeploymentTabKey.Log, label: '服务日志', icon: , }, ]; function ModelDeploymentInfo() { - const [activeTab, setActiveTab] = useState('1'); + const [activeTab, setActiveTab] = useState(ModelDeploymentTabKey.Predict); const [modelDeployementInfo] = useSessionStorage( modelDeploymentInfoKey, true, undefined, ); const getResourceDescription = useComputingResource()[2]; + const [docs, setDocs] = useState(''); - useEffect(() => {}, []); + useEffect(() => { + getModelDeploymentDocs(); + }, [modelDeployementInfo]); + + // 获取模型部署文档 + const getModelDeploymentDocs = async () => { + const params = pick(modelDeployementInfo, ['service_id', 'service_ins_id']); + const [res] = await to(getModelDeploymentDocsReq(params)); + if (res && res.data && res.data.docs) { + setDocs(JSON.stringify(res.data.docs, null, 2)); + } + }; // 切换 Tab,重置数据 const hanleTabChange: TabsProps['onChange'] = (value) => { setActiveTab(value); }; + // 格式化环境变量 const formatEnvText = () => { if (!modelDeployementInfo?.env) { return '--'; @@ -64,128 +86,130 @@ function ModelDeploymentInfo() {
-
- -
- - -
-
服务名称:
-
- {modelDeployementInfo?.service_name ?? '--'} -
-
- - -
-
镜  像:
-
{modelDeployementInfo?.image ?? '--'}
-
- -
- - -
-
状  态:
-
- {ModelDeploymentStatusCell(modelDeployementInfo?.status)} -
-
- - -
-
模  型:
-
- {modelDeployementInfo?.model?.show_value ?? '--'} -
-
- -
- - -
-
创建人:
-
{modelDeployementInfo?.created_by ?? '--'}
-
- - -
-
挂载路径:
-
{modelDeployementInfo?.model_path ?? '--'}
-
- -
- - -
-
API URL:
-
{modelDeployementInfo?.url ?? '--'}
-
- - -
-
副本数量:
-
{modelDeployementInfo?.replicas ?? '--'}
-
- -
- - -
-
创建时间:
-
- {modelDeployementInfo?.create_time - ? formatDate(modelDeployementInfo.create_time) - : '--'} -
+ +
+ + +
+
服务名称:
+
{modelDeployementInfo?.service_name ?? '--'}
+
+ + +
+
镜  像:
+
{modelDeployementInfo?.image ?? '--'}
+
+ +
+ + +
+
状  态:
+
+ {ModelDeploymentStatusCell(modelDeployementInfo?.status)}
- - -
-
更新时间:
-
- {modelDeployementInfo?.update_time - ? formatDate(modelDeployementInfo.update_time) - : '--'} -
+
+ + +
+
模  型:
+
+ {modelDeployementInfo?.model?.show_value ?? '--'}
- - - - -
-
环境变量:
-
{formatEnvText()}
+
+ +
+ + +
+
创建人:
+
{modelDeployementInfo?.created_by ?? '--'}
+
+ + +
+
挂载路径:
+
{modelDeployementInfo?.model_path ?? '--'}
+
+ +
+ + +
+
API URL:
+
{modelDeployementInfo?.url ?? '--'}
+
+ + +
+
副本数量:
+
{modelDeployementInfo?.replicas ?? '--'}
+
+ +
+ + +
+
创建时间:
+
+ {modelDeployementInfo?.create_time + ? formatDate(modelDeployementInfo.create_time) + : '--'}
- - -
-
资源规格:
-
- {modelDeployementInfo?.resource - ? getResourceDescription(modelDeployementInfo.resource) - : '--'} -
+
+ + +
+
更新时间:
+
+ {modelDeployementInfo?.update_time + ? formatDate(modelDeployementInfo.update_time) + : '--'}
- - - - -
-
描  述:
-
{modelDeployementInfo?.description ?? '--'}
+
+ +
+ + +
+
环境变量:
+
{formatEnvText()}
+
+ + +
+
资源规格:
+
+ {modelDeployementInfo?.resource + ? getResourceDescription(modelDeployementInfo.resource) + : '--'}
- - -
-
- -
+
+ + + + +
+
描  述:
+
{modelDeployementInfo?.description ?? '--'}
+
+ +
+ + {activeTab === ModelDeploymentTabKey.Guide && ( +
{docs}
+ )}
); diff --git a/react-ui/src/services/modelDeployment/index.ts b/react-ui/src/services/modelDeployment/index.ts index 7416eeef..5004b357 100644 --- a/react-ui/src/services/modelDeployment/index.ts +++ b/react-ui/src/services/modelDeployment/index.ts @@ -59,3 +59,11 @@ export function updateModelDeploymentReq(data: any) { data, }); } + +// 获取模型部署操作指南 +export function getModelDeploymentDocsReq(data: any) { + return request(`/api/v1/model/getDocs`, { + method: 'POST', + data, + }); +} From 8d2811702611d81b737c6046dad066971101967e Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Tue, 28 May 2024 15:53:03 +0800 Subject: [PATCH 07/11] =?UTF-8?q?chore:=20=E6=97=A5=E5=BF=97=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Experiment/components/LogGroup/index.less | 5 +++ .../Experiment/components/LogGroup/index.tsx | 41 ++++++++++++++++--- .../components/TensorBoardStatus/index.less | 6 +-- .../components/ViewParamsModal/index.less | 8 ++-- react-ui/src/pages/Experiment/index.jsx | 3 -- react-ui/src/pages/Experiment/status.ts | 18 ++++---- react-ui/src/styles/theme.less | 5 ++- 7 files changed, 62 insertions(+), 24 deletions(-) diff --git a/react-ui/src/pages/Experiment/components/LogGroup/index.less b/react-ui/src/pages/Experiment/components/LogGroup/index.less index ede8b0cf..2962a2c6 100644 --- a/react-ui/src/pages/Experiment/components/LogGroup/index.less +++ b/react-ui/src/pages/Experiment/components/LogGroup/index.less @@ -21,8 +21,13 @@ color: white; font-size: 14px; white-space: pre-line; + text-align: left; word-break: break-all; background: #19253b; + + &--empty { + text-align: center; + } } &__more-button { diff --git a/react-ui/src/pages/Experiment/components/LogGroup/index.tsx b/react-ui/src/pages/Experiment/components/LogGroup/index.tsx index 00cea44b..38b98af8 100644 --- a/react-ui/src/pages/Experiment/components/LogGroup/index.tsx +++ b/react-ui/src/pages/Experiment/components/LogGroup/index.tsx @@ -10,6 +10,7 @@ import { ExperimentLog } from '@/pages/Experiment/training/props'; import { getExperimentPodsLog } from '@/services/experiment/index.js'; import { DoubleRightOutlined, DownOutlined, UpOutlined } from '@ant-design/icons'; import { Button } from 'antd'; +import classNames from 'classnames'; import { useEffect, useState } from 'react'; import styles from './index.less'; @@ -22,6 +23,7 @@ type Log = { log_content: string; // 日志内容 }; +// 滚动到底部 const scrollToBottom = (smooth: boolean = true) => { const element = document.getElementsByClassName('ant-tabs-content-holder')?.[0]; if (element) { @@ -46,6 +48,8 @@ function LogGroup({ const [collapse, setCollapse] = useState(true); const [logList, setLogList, logListRef] = useStateRef([]); const [completed, setCompleted] = useState(false); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [isMouseDown, setIsMouseDown, isMouseDownRef] = useStateRef(false); useEffect(() => { scrollToBottom(false); @@ -59,6 +63,24 @@ function LogGroup({ } }, []); + useEffect(() => { + const mouseDown = () => { + setIsMouseDown(true); + }; + + const mouseUp = () => { + setIsMouseDown(false); + }; + + document.addEventListener('mousedown', mouseDown); + document.addEventListener('mouseup', mouseUp); + + return () => { + document.removeEventListener('mousedown', mouseDown); + document.removeEventListener('mouseup', mouseUp); + }; + }, []); + // 请求日志 const requestExperimentPodsLog = async () => { const list = logListRef.current; @@ -69,11 +91,14 @@ function LogGroup({ }; const res = await getExperimentPodsLog(params); const { log_detail } = res.data; - if (log_detail && log_detail.log_content) { + if (log_detail) { setLogList((oldList) => oldList.concat(log_detail)); - setTimeout(() => { - scrollToBottom(); - }, 100); + + if (!isMouseDownRef.current && log_detail.log_content) { + setTimeout(() => { + scrollToBottom(); + }, 100); + } } else { setCompleted(true); } @@ -115,7 +140,13 @@ function LogGroup({
)} {showLog && ( -
{logText ? logText : '暂无日志'}
+
+ {logText ? logText : '暂无日志'} +
)}
{showMoreBtn && ( diff --git a/react-ui/src/pages/Experiment/components/TensorBoardStatus/index.less b/react-ui/src/pages/Experiment/components/TensorBoardStatus/index.less index 743970b9..579fa7c3 100644 --- a/react-ui/src/pages/Experiment/components/TensorBoardStatus/index.less +++ b/react-ui/src/pages/Experiment/components/TensorBoardStatus/index.less @@ -8,15 +8,15 @@ font-size: 15px; &--running { - color: #6ac21d; + color: @success-color; } &--failed { - color: #df6d6d; + color: @error-color; } } &__icon { width: 14px; - color: #6ac21d; + color: @success-color; cursor: pointer; & + & { diff --git a/react-ui/src/pages/Experiment/components/ViewParamsModal/index.less b/react-ui/src/pages/Experiment/components/ViewParamsModal/index.less index 54e164bf..a2b0ded5 100644 --- a/react-ui/src/pages/Experiment/components/ViewParamsModal/index.less +++ b/react-ui/src/pages/Experiment/components/ViewParamsModal/index.less @@ -11,8 +11,8 @@ margin-bottom: 15px; &_label { - width: 120px; - color: #1d1d20; + width: 180px; + color: @text-color; font-size: 15px; } &_value { @@ -20,8 +20,8 @@ width: 100px; margin-left: 15px; padding: 10px 20px; - color: #1d1d20; - font-size: 15px; + color: @text-color; + font-size: @font-size; line-height: 20px; background: #f6f6f6; border: 1px solid #e0e0e1; diff --git a/react-ui/src/pages/Experiment/index.jsx b/react-ui/src/pages/Experiment/index.jsx index a35591a1..aa6349d8 100644 --- a/react-ui/src/pages/Experiment/index.jsx +++ b/react-ui/src/pages/Experiment/index.jsx @@ -84,7 +84,6 @@ function Experiment() { // 获取实验实例 const getQueryByExperiment = (val) => { getQueryByExperimentId(val).then((ret) => { - console.log(val); setExpandedRowKeys(val); if (ret && ret.data && ret.data.length > 0) { try { @@ -162,7 +161,6 @@ function Experiment() { }; const expandChange = (e, record) => { clearExperimentInTimers(); - console.log(e, record); if (record.id === expandedRowKeys) { setExpandedRowKeys(null); } else { @@ -238,7 +236,6 @@ function Experiment() { }; // 当前页面切换 const paginationChange = async (current, size) => { - console.log('page', current, size); pageOption.current = { page: current, size: size, diff --git a/react-ui/src/pages/Experiment/status.ts b/react-ui/src/pages/Experiment/status.ts index 71999346..b9c45af6 100644 --- a/react-ui/src/pages/Experiment/status.ts +++ b/react-ui/src/pages/Experiment/status.ts @@ -1,3 +1,5 @@ +import themes from '@/styles/theme.less'; + export interface StatusInfo { label: string; color: string; @@ -18,42 +20,42 @@ export enum ExperimentStatus { export const experimentStatusInfo: Record = { Running: { label: '运行中', - color: '#1664ff', + color: themes.primaryColor, icon: '/assets/images/running-icon.png', }, Succeeded: { label: '成功', - color: '#63a728', + color: themes.successColor, icon: '/assets/images/success-icon.png', }, Pending: { label: '等待中', - color: '#f981eb', + color: themes.pendingColor, icon: '/assets/images/pending-icon.png', }, Failed: { label: '失败', - color: '#c73131', + color: themes.errorColor, icon: '/assets/images/fail-icon.png', }, Error: { label: '错误', - color: '#c73131', + color: themes.errorColor, icon: '/assets/images/fail-icon.png', }, Terminated: { label: '终止', - color: '#8a8a8a', + color: themes.abortColor, icon: '/assets/images/omitted-icon.png', }, Skipped: { label: '未执行', - color: '#8a8a8a', + color: themes.abortColor, icon: '/assets/images/omitted-icon.png', }, Omitted: { label: '未执行', - color: '#8a8a8a', + color: themes.abortColor, icon: '/assets/images/omitted-icon.png', }, }; diff --git a/react-ui/src/styles/theme.less b/react-ui/src/styles/theme.less index 5d5ebccd..f1a7b2b2 100644 --- a/react-ui/src/styles/theme.less +++ b/react-ui/src/styles/theme.less @@ -11,10 +11,11 @@ @background-color: #f9fafb; // 页面背景颜色 @text-color: #1d1d20; @text-color-secondary: #575757; -@success-color: #1ace62; +@success-color: #6ac21d; @error-color: #c73131; @warning-color: #f98e1b; @abort-color: #8a8a8a; +@pending-color: #ecb934; @border-color: rgba(22, 100, 255, 0.3); @border-color-secondary: rgba(22, 100, 255, 0.1); @@ -78,4 +79,6 @@ fontSizeInput: @font-size-input; fontSizeInputLg: @font-size-input-lg; siderBGColor: @sider-background-color; + abortColor: @abort-color; + pendingColor: @pending-color; } From 0ed1d59a223cdfce6054081c6e35fc3a80c27cb0 Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Wed, 29 May 2024 10:50:03 +0800 Subject: [PATCH 08/11] =?UTF-8?q?feat:=20=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=B7=BB=E5=8A=A0=E4=B8=8B=E6=8B=89=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E6=95=B0=E6=8D=AE=E9=9B=86=E3=80=81=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E3=80=81=E8=B5=84=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/ParameterInput/index.tsx | 2 - .../src/components/ParameterSelect/index.less | 0 .../src/components/ParameterSelect/index.tsx | 119 +++++++++++++ .../components/AddDatasetModal/index.tsx | 2 +- .../components/AddModelModal/index.tsx | 2 +- .../components/AddVersionModal/index.tsx | 2 +- .../Dataset/components/CategoryItem/index.tsx | 2 +- .../Dataset/components/CategoryList/index.tsx | 2 +- .../Dataset/components/ResourceList/index.tsx | 2 +- .../Dataset/components/ResourcePage/index.tsx | 2 +- .../Dataset/components/Resourcetem/index.tsx | 2 +- .../pages/Dataset/{types.tsx => config.tsx} | 0 .../pages/Dataset/{index.jsx => index.tsx} | 2 +- react-ui/src/pages/Dataset/intro.jsx | 2 +- .../src/pages/Model/{index.jsx => index.tsx} | 2 +- react-ui/src/pages/Model/intro.jsx | 2 +- .../ResourceSelectorModal/config.tsx | 7 +- .../ResourceSelectorModal/index.tsx | 68 ++++---- .../editPipeline/{props.jsx => props.tsx} | 162 +++++++++--------- react-ui/src/types.ts | 11 +- 20 files changed, 254 insertions(+), 139 deletions(-) create mode 100644 react-ui/src/components/ParameterSelect/index.less create mode 100644 react-ui/src/components/ParameterSelect/index.tsx rename react-ui/src/pages/Dataset/{types.tsx => config.tsx} (100%) rename react-ui/src/pages/Dataset/{index.jsx => index.tsx} (81%) rename react-ui/src/pages/Model/{index.jsx => index.tsx} (77%) rename react-ui/src/pages/Pipeline/editPipeline/{props.jsx => props.tsx} (79%) diff --git a/react-ui/src/components/ParameterInput/index.tsx b/react-ui/src/components/ParameterInput/index.tsx index 27ba2856..aa573091 100644 --- a/react-ui/src/components/ParameterInput/index.tsx +++ b/react-ui/src/components/ParameterInput/index.tsx @@ -37,8 +37,6 @@ function ParameterInput({ disabled = false, ...rest }: ParameterInputProps) { - // console.log('ParameterInput', value); - const valueObj = typeof value === 'string' ? { value: value, fromSelect: false, showValue: value } : value; if (valueObj && !valueObj.showValue) { diff --git a/react-ui/src/components/ParameterSelect/index.less b/react-ui/src/components/ParameterSelect/index.less new file mode 100644 index 00000000..e69de29b diff --git a/react-ui/src/components/ParameterSelect/index.tsx b/react-ui/src/components/ParameterSelect/index.tsx new file mode 100644 index 00000000..d96a886c --- /dev/null +++ b/react-ui/src/components/ParameterSelect/index.tsx @@ -0,0 +1,119 @@ +import { to } from '@/utils/promise'; +import { useEffect, useState } from 'react'; +// import styles from './index.less'; +import { getDatasetList, getModelList } from '@/services/dataset/index.js'; +import { getComputingResourceReq } from '@/services/pipeline'; +import { ComputingResource, PipelineNodeModelParameter } from '@/types'; +import { Select, type SelectProps } from 'antd'; + +// 过滤资源规格 +const filterResourceStandard: SelectProps['filterOption'] = ( + input: string, + option?: ComputingResource, +) => { + return ( + option?.computing_resource?.toLocaleLowerCase()?.includes(input.toLocaleLowerCase()) ?? false + ); +}; + +type SelectPropsConfig = { + getOptions: () => Promise; + fieldNames?: SelectProps['fieldNames']; + filterOption?: SelectProps['filterOption']; +}; + +const config: Record = { + dataset: { + getOptions: async () => { + const res = await getDatasetList({ + page: 0, + size: 1000, + available_range: 0, + }); + return res?.data?.content ?? []; + }, + fieldNames: { + label: 'name', + value: 'id', + }, + }, + model: { + getOptions: async () => { + const res = await getModelList({ + page: 0, + size: 1000, + available_range: 0, + }); + return res?.data?.content ?? []; + }, + fieldNames: { + label: 'name', + value: 'id', + }, + }, + resource: { + getOptions: async () => { + const res = await getComputingResourceReq({ + page: 0, + size: 1000, + resource_type: '', + }); + return res?.data?.content ?? []; + }, + fieldNames: { + label: 'description', + value: 'standard', + }, + filterOption: filterResourceStandard as SelectProps['filterOption'], + }, +}; + +type ParameterSelectProps = { + value?: PipelineNodeModelParameter; + onChange?: (value: PipelineNodeModelParameter) => void; +}; + +function ParameterSelect({ value, onChange }: ParameterSelectProps) { + const [options, setOptions] = useState([]); + const valueNonNullable = value ?? ({} as PipelineNodeModelParameter); + const { item_type } = valueNonNullable; + + useEffect(() => { + getSelectOptions(); + }, []); + + const hangleChange = (e: string) => { + onChange?.({ + ...valueNonNullable, + value: e, + }); + }; + + // 获取下拉数据 + const getSelectOptions = async () => { + const propsConfig = config[item_type]; + if (!propsConfig) { + return; + } + const getOptions = propsConfig.getOptions; + const [res] = await to(getOptions()); + if (res) { + setOptions(res); + } + }; + + return ( + { label: 'description', value: 'standard', }} + showSearch + allowClear /> { { - handleParameterClick(['control_strategy', item.key], { - ...item.value, - value, - fromSelect: true, - showValue: value, - }); - }} - /> - } - // getValueProps={(e) => { - // return { value: e.value }; - // }} - // getValueFromEvent={(e) => { - // return { - // ...item.value, - // value: e.target.value, - // }; - // }} + label={getLabel(item, 'control_strategy')} > @@ -365,20 +394,7 @@ const Props = forwardRef(({ onParentChange }, ref) => { {inParametersList.map((item) => ( { - handleParameterClick(['in_parameters', item.key], { - ...item.value, - value, - fromSelect: true, - showValue: value, - }); - }} - /> - } + label={getLabel(item, 'in_parameters')} required={item.value.require ? true : false} >
@@ -387,11 +403,15 @@ const Props = forwardRef(({ onParentChange }, ref) => { noStyle rules={[{ required: item.value.require ? true : false }]} > - + {item.value.type === 'select' ? ( + + ) : ( + + )} {item.value.type === 'ref' && ( @@ -416,30 +436,8 @@ const Props = forwardRef(({ onParentChange }, ref) => { { - handleParameterClick(['out_parameters', item.key], { - ...item.value, - value, - fromSelect: true, - showValue: value, - }); - }} - /> - } + label={getLabel(item, 'out_parameters')} rules={[{ required: item.value.require ? true : false }]} - // getValueProps={(e) => { - // return { value: e.value }; - // }} - // getValueFromEvent={(e) => { - // return { - // ...item.value, - // value: e.target.value, - // }; - // }} > @@ -449,4 +447,4 @@ const Props = forwardRef(({ onParentChange }, ref) => { ); }); -export default Props; +export default PipelineNodeParameter; diff --git a/react-ui/src/types.ts b/react-ui/src/types.ts index 605131a4..9f558618 100644 --- a/react-ui/src/types.ts +++ b/react-ui/src/types.ts @@ -47,16 +47,19 @@ export type PipelineNodeModel = { // 流水线节点模型数据 export type PipelineNodeModelParameter = { - label: string; - value: any; - require: number; type: string; item_type: string; + label: string; + value: any; + require?: number; placeholder?: string; describe?: string; fromSelect?: boolean; showValue?: any; - editable: number; + editable?: number; + activeTab?: string; // ResourceSelectorModal tab + expandedKeys?: string[]; // ResourceSelectorModal expandedKeys + checkedKeys?: string[]; // ResourceSelectorModal checkedKeys }; // type ChangePropertyType = Omit & { [P in K]: NewType } From 7ebb9436534a109c03c15cdb1d1e9a056e63228c Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Wed, 29 May 2024 14:11:08 +0800 Subject: [PATCH 09/11] =?UTF-8?q?chore:=20=E4=BC=98=E5=8C=96=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E9=9B=86=E3=80=81=E6=A8=A1=E5=9E=8B=E9=80=89=E6=8B=A9?= =?UTF-8?q?=EF=BC=8C=E5=86=8D=E6=AC=A1=E6=89=93=E5=BC=80=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E4=B8=8A=E6=AC=A1=E7=9A=84=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/ParameterInput/index.tsx | 5 +- .../src/components/ParameterSelect/index.tsx | 7 +- .../src/pages/Pipeline/editPipeline/props.tsx | 79 ++++++++++--------- 3 files changed, 50 insertions(+), 41 deletions(-) diff --git a/react-ui/src/components/ParameterInput/index.tsx b/react-ui/src/components/ParameterInput/index.tsx index aa573091..369f504a 100644 --- a/react-ui/src/components/ParameterInput/index.tsx +++ b/react-ui/src/components/ParameterInput/index.tsx @@ -66,9 +66,12 @@ function ParameterInput({ e.stopPropagation(); onChange?.({ ...valueObj, - fromSelect: false, value: undefined, showValue: undefined, + fromSelect: false, + activeTab: undefined, + expandedKeys: undefined, + checkedKeys: undefined, }); }} /> diff --git a/react-ui/src/components/ParameterSelect/index.tsx b/react-ui/src/components/ParameterSelect/index.tsx index d96a886c..b9fa030e 100644 --- a/react-ui/src/components/ParameterSelect/index.tsx +++ b/react-ui/src/components/ParameterSelect/index.tsx @@ -16,6 +16,9 @@ const filterResourceStandard: SelectProps['filterOpti ); }; +// id 从 number 转换为 string +const convertId = (item: any) => ({ ...item, id: String(item.id) }); + type SelectPropsConfig = { getOptions: () => Promise; fieldNames?: SelectProps['fieldNames']; @@ -30,7 +33,7 @@ const config: Record = { size: 1000, available_range: 0, }); - return res?.data?.content ?? []; + return res?.data?.content?.map(convertId) ?? []; }, fieldNames: { label: 'name', @@ -44,7 +47,7 @@ const config: Record = { size: 1000, available_range: 0, }); - return res?.data?.content ?? []; + return res?.data?.content?.map(convertId) ?? []; }, fieldNames: { label: 'name', diff --git a/react-ui/src/pages/Pipeline/editPipeline/props.tsx b/react-ui/src/pages/Pipeline/editPipeline/props.tsx index 9bd1ee69..52ff665a 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/props.tsx +++ b/react-ui/src/pages/Pipeline/editPipeline/props.tsx @@ -2,6 +2,7 @@ import KFIcon from '@/components/KFIcon'; import ParameterInput from '@/components/ParameterInput'; import ParameterSelect from '@/components/ParameterSelect'; import SubAreaTitle from '@/components/SubAreaTitle'; +import { CommonTabKeys } from '@/enums'; import { useComputingResource } from '@/hooks/resource'; import { PipelineGlobalParam, @@ -13,11 +14,9 @@ import { to } from '@/utils/promise'; import { INode } from '@antv/g6'; import { Button, Drawer, Form, Input, MenuProps, Select } from 'antd'; import { NamePath } from 'antd/es/form/interface'; -import { pick } from 'lodash'; import { forwardRef, useImperativeHandle, useState } from 'react'; import PropsLabel from '../components/PropsLabel'; import ResourceSelectorModal, { - ResourceSelectorResponse, ResourceSelectorType, selectorTypeConfig, } from '../components/ResourceSelectorModal'; @@ -35,12 +34,6 @@ const PipelineNodeParameter = forwardRef(({ onParentChange }: PipelineNodeParame {} as PipelineNodeModelSerialize, ); const [open, setOpen] = useState(false); - const [selectedModel, setSelectedModel] = useState( - undefined, - ); // 选择的模型,为了再次打开时恢复原来的选择 - const [selectedDataset, setSelectedDataset] = useState( - undefined, - ); // 选择的数据集,为了再次打开时恢复原来的选择 const [resourceStandardList, filterResourceStandard] = useComputingResource(); // 资源规模 const [menuItems, setMenuItems] = useState([]); @@ -94,8 +87,6 @@ const PipelineNodeParameter = forwardRef(({ onParentChange }: PipelineNodeParame } catch (error) { console.log(error); } - setSelectedModel(undefined); - setSelectedDataset(undefined); setOpen(true); // 参数下拉菜单 @@ -109,57 +100,69 @@ const PipelineNodeParameter = forwardRef(({ onParentChange }: PipelineNodeParame // 选择数据集、模型、镜像 const selectResource = ( - name: NamePath, - item: PipelineNodeModelParameter | { item_type: string }, + formItemName: NamePath, + item: PipelineNodeModelParameter | Pick, ) => { let type: ResourceSelectorType; - let resource: any; switch (item.item_type) { case 'dataset': type = ResourceSelectorType.Dataset; - resource = selectedDataset; break; case 'model': type = ResourceSelectorType.Model; - resource = selectedModel; break; default: type = ResourceSelectorType.Mirror; break; } + + const fieldValue = form.getFieldValue(formItemName); + const activeTab = fieldValue?.activeTab as CommonTabKeys | undefined; + const expandedKeys = Array.isArray(fieldValue?.expandedKeys) ? fieldValue?.expandedKeys : []; + const checkedKeys = Array.isArray(fieldValue?.checkedKeys) ? fieldValue?.checkedKeys : []; const { close } = openAntdModal(ResourceSelectorModal, { type, - defaultExpandedKeys: resource ? [resource.id] : [], - defaultCheckedKeys: resource ? [`${resource.id}-${resource.version}`] : [], - defaultActiveTab: resource?.activeTab, + defaultExpandedKeys: expandedKeys, + defaultCheckedKeys: checkedKeys, + defaultActiveTab: activeTab, onOk: (res) => { if (res) { if (type === ResourceSelectorType.Mirror) { - const path = res.path; - if (name === 'image') { - form.setFieldValue(name, path); + const { activeTab, id, version, path } = res; + if (formItemName === 'image') { + form.setFieldValue(formItemName, path); } else { - form.setFieldValue(name, { ...item, value: path, showValue: path, fromSelect: true }); + form.setFieldValue(formItemName, { + ...item, + value: path, + showValue: path, + fromSelect: true, + activeTab, + expandedKeys: [id], + checkedKeys: [`${id}-${version}`], + }); } } else { - const jsonObj = pick(res, ['id', 'version', 'path']); + const { activeTab, id, name, version, path } = res; + const jsonObj = { + id, + version, + path, + }; const value = JSON.stringify(jsonObj); - const showValue = `${res.name}:${res.version}`; - form.setFieldValue(name, { ...item, value, showValue, fromSelect: true }); - - if (type === ResourceSelectorType.Dataset) { - setSelectedDataset(res); - } else if (type === ResourceSelectorType.Model) { - setSelectedModel(res); - } + const showValue = `${name}:${version}`; + form.setFieldValue(formItemName, { + ...item, + value, + showValue, + fromSelect: true, + activeTab, + expandedKeys: [id], + checkedKeys: [`${id}-${version}`], + }); } } else { - if (type === ResourceSelectorType.Dataset) { - setSelectedDataset(undefined); - } else if (type === ResourceSelectorType.Model) { - setSelectedModel(undefined); - } - form.setFieldValue(name, ''); + form.setFieldValue(formItemName, ''); } close(); }, @@ -167,7 +170,7 @@ const PipelineNodeParameter = forwardRef(({ onParentChange }: PipelineNodeParame }; // 获取选择数据集、模型后面按钮 icon - const getSelectBtnIcon = (item: PipelineNodeModelParameter | { item_type: string }) => { + const getSelectBtnIcon = (item: { item_type: string }) => { const type = item.item_type; let selectorType: ResourceSelectorType; if (type === 'dataset') { From 299b6635b03743f038606495e72070024fee0a3e Mon Sep 17 00:00:00 2001 From: cp3hnu Date: Wed, 29 May 2024 14:54:51 +0800 Subject: [PATCH 10/11] =?UTF-8?q?fix:=20=E5=AE=9E=E9=AA=8C=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/ParameterInput/index.tsx | 2 +- .../src/components/ParameterSelect/config.tsx | 72 ++++++++++++++++ .../src/components/ParameterSelect/index.less | 0 .../src/components/ParameterSelect/index.tsx | 84 +++---------------- .../components/ExperimentParameter/index.tsx | 27 +++--- .../src/pages/Pipeline/editPipeline/props.tsx | 10 +-- 6 files changed, 96 insertions(+), 99 deletions(-) create mode 100644 react-ui/src/components/ParameterSelect/config.tsx delete mode 100644 react-ui/src/components/ParameterSelect/index.less diff --git a/react-ui/src/components/ParameterInput/index.tsx b/react-ui/src/components/ParameterInput/index.tsx index 369f504a..4b838b2d 100644 --- a/react-ui/src/components/ParameterInput/index.tsx +++ b/react-ui/src/components/ParameterInput/index.tsx @@ -29,7 +29,6 @@ function ParameterInput({ onClick, canInput = true, textArea = false, - placeholder, allowClear, className, style, @@ -44,6 +43,7 @@ function ParameterInput({ } const isSelect = valueObj?.fromSelect; const InputComponent = textArea ? Input.TextArea : Input; + const placeholder = valueObj?.placeholder; return ( <> diff --git a/react-ui/src/components/ParameterSelect/config.tsx b/react-ui/src/components/ParameterSelect/config.tsx new file mode 100644 index 00000000..84c99914 --- /dev/null +++ b/react-ui/src/components/ParameterSelect/config.tsx @@ -0,0 +1,72 @@ +import { getDatasetList, getModelList } from '@/services/dataset/index.js'; +import { getComputingResourceReq } from '@/services/pipeline'; +import { ComputingResource } from '@/types'; +import { type SelectProps } from 'antd'; + +// 过滤资源规格 +const filterResourceStandard: SelectProps['filterOption'] = ( + input: string, + option?: ComputingResource, +) => { + return ( + option?.computing_resource?.toLocaleLowerCase()?.includes(input.toLocaleLowerCase()) ?? false + ); +}; + +// id 从 number 转换为 string +const convertId = (item: any) => ({ ...item, id: String(item.id) }); + +export type SelectPropsConfig = { + getOptions: () => Promise; + fieldNames?: SelectProps['fieldNames']; + optionFilterProp?: SelectProps['optionFilterProp']; + filterOption?: SelectProps['filterOption']; +}; + +export const paramSelectConfig: Record = { + dataset: { + getOptions: async () => { + const res = await getDatasetList({ + page: 0, + size: 1000, + available_range: 0, + }); + return res?.data?.content?.map(convertId) ?? []; + }, + fieldNames: { + label: 'name', + value: 'id', + }, + optionFilterProp: 'name', + }, + model: { + getOptions: async () => { + const res = await getModelList({ + page: 0, + size: 1000, + available_range: 0, + }); + return res?.data?.content?.map(convertId) ?? []; + }, + fieldNames: { + label: 'name', + value: 'id', + }, + optionFilterProp: 'name', + }, + resource: { + getOptions: async () => { + const res = await getComputingResourceReq({ + page: 0, + size: 1000, + resource_type: '', + }); + return res?.data?.content ?? []; + }, + fieldNames: { + label: 'description', + value: 'standard', + }, + filterOption: filterResourceStandard as SelectProps['filterOption'], + }, +}; diff --git a/react-ui/src/components/ParameterSelect/index.less b/react-ui/src/components/ParameterSelect/index.less deleted file mode 100644 index e69de29b..00000000 diff --git a/react-ui/src/components/ParameterSelect/index.tsx b/react-ui/src/components/ParameterSelect/index.tsx index b9fa030e..5b181a01 100644 --- a/react-ui/src/components/ParameterSelect/index.tsx +++ b/react-ui/src/components/ParameterSelect/index.tsx @@ -1,85 +1,20 @@ +import { PipelineNodeModelParameter } from '@/types'; import { to } from '@/utils/promise'; +import { Select } from 'antd'; import { useEffect, useState } from 'react'; -// import styles from './index.less'; -import { getDatasetList, getModelList } from '@/services/dataset/index.js'; -import { getComputingResourceReq } from '@/services/pipeline'; -import { ComputingResource, PipelineNodeModelParameter } from '@/types'; -import { Select, type SelectProps } from 'antd'; - -// 过滤资源规格 -const filterResourceStandard: SelectProps['filterOption'] = ( - input: string, - option?: ComputingResource, -) => { - return ( - option?.computing_resource?.toLocaleLowerCase()?.includes(input.toLocaleLowerCase()) ?? false - ); -}; - -// id 从 number 转换为 string -const convertId = (item: any) => ({ ...item, id: String(item.id) }); - -type SelectPropsConfig = { - getOptions: () => Promise; - fieldNames?: SelectProps['fieldNames']; - filterOption?: SelectProps['filterOption']; -}; - -const config: Record = { - dataset: { - getOptions: async () => { - const res = await getDatasetList({ - page: 0, - size: 1000, - available_range: 0, - }); - return res?.data?.content?.map(convertId) ?? []; - }, - fieldNames: { - label: 'name', - value: 'id', - }, - }, - model: { - getOptions: async () => { - const res = await getModelList({ - page: 0, - size: 1000, - available_range: 0, - }); - return res?.data?.content?.map(convertId) ?? []; - }, - fieldNames: { - label: 'name', - value: 'id', - }, - }, - resource: { - getOptions: async () => { - const res = await getComputingResourceReq({ - page: 0, - size: 1000, - resource_type: '', - }); - return res?.data?.content ?? []; - }, - fieldNames: { - label: 'description', - value: 'standard', - }, - filterOption: filterResourceStandard as SelectProps['filterOption'], - }, -}; +import { paramSelectConfig } from './config'; type ParameterSelectProps = { value?: PipelineNodeModelParameter; onChange?: (value: PipelineNodeModelParameter) => void; + disabled?: boolean; }; -function ParameterSelect({ value, onChange }: ParameterSelectProps) { +function ParameterSelect({ value, onChange, disabled = false }: ParameterSelectProps) { const [options, setOptions] = useState([]); const valueNonNullable = value ?? ({} as PipelineNodeModelParameter); const { item_type } = valueNonNullable; + const propsConfig = paramSelectConfig[item_type]; useEffect(() => { getSelectOptions(); @@ -94,7 +29,6 @@ function ParameterSelect({ value, onChange }: ParameterSelectProps) { // 获取下拉数据 const getSelectOptions = async () => { - const propsConfig = config[item_type]; if (!propsConfig) { return; } @@ -108,11 +42,13 @@ function ParameterSelect({ value, onChange }: ParameterSelectProps) { return (