Browse Source

Merge remote-tracking branch 'origin/dev' into dev

pull/19/head
西大锐 1 year ago
parent
commit
6a2b63f8b6
28 changed files with 409 additions and 95 deletions
  1. BIN
      react-ui/public/assets/images/modal-back.png
  2. BIN
      react-ui/src/assets/img/tensor-board-export.png
  3. BIN
      react-ui/src/assets/img/tensor-board-failed.png
  4. BIN
      react-ui/src/assets/img/tensor-board-pending.png
  5. BIN
      react-ui/src/assets/img/tensor-board-running.png
  6. BIN
      react-ui/src/assets/img/tensor-board-stop.png
  7. BIN
      react-ui/src/assets/img/tensor-board-terminated.png
  8. BIN
      react-ui/src/assets/img/tensor-board-unknown.png
  9. +1
    -1
      react-ui/src/components/KFModal/index.less
  10. +1
    -0
      react-ui/src/components/ModalTitle/index.less
  11. +42
    -2
      react-ui/src/global.less
  12. +24
    -0
      react-ui/src/hooks/index.ts
  13. +3
    -3
      react-ui/src/pages/Dataset/datasetIntro.jsx
  14. +4
    -4
      react-ui/src/pages/Dataset/index.jsx
  15. +4
    -1
      react-ui/src/pages/Dataset/index.less
  16. +19
    -20
      react-ui/src/pages/Dataset/personalData.jsx
  17. +26
    -0
      react-ui/src/pages/Experiment/components/TensorBoardStatus/index.less
  18. +82
    -0
      react-ui/src/pages/Experiment/components/TensorBoardStatus/index.tsx
  19. +1
    -1
      react-ui/src/pages/Experiment/experimentText/paramsModal.less
  20. +122
    -14
      react-ui/src/pages/Experiment/index.jsx
  21. +4
    -1
      react-ui/src/pages/Model/index.less
  22. +9
    -7
      react-ui/src/pages/Model/modelIntro.jsx
  23. +17
    -19
      react-ui/src/pages/Model/personalData.jsx
  24. +1
    -0
      react-ui/src/pages/Pipeline/editPipeline/modelMenus.jsx
  25. +11
    -1
      react-ui/src/pages/Pipeline/editPipeline/modelMenus.less
  26. +18
    -20
      react-ui/src/pages/Pipeline/index.jsx
  27. +4
    -1
      react-ui/src/pages/Pipeline/index.less
  28. +16
    -0
      react-ui/src/services/experiment/index.js

BIN
react-ui/public/assets/images/modal-back.png View File

Before After
Width: 2475  |  Height: 942  |  Size: 154 kB

BIN
react-ui/src/assets/img/tensor-board-export.png View File

Before After
Width: 42  |  Height: 42  |  Size: 1.0 kB

BIN
react-ui/src/assets/img/tensor-board-failed.png View File

Before After
Width: 42  |  Height: 42  |  Size: 1.2 kB

BIN
react-ui/src/assets/img/tensor-board-pending.png View File

Before After
Width: 42  |  Height: 42  |  Size: 1.6 kB

BIN
react-ui/src/assets/img/tensor-board-running.png View File

Before After
Width: 42  |  Height: 42  |  Size: 1.1 kB

BIN
react-ui/src/assets/img/tensor-board-stop.png View File

Before After
Width: 42  |  Height: 42  |  Size: 815 B

BIN
react-ui/src/assets/img/tensor-board-terminated.png View File

Before After
Width: 42  |  Height: 42  |  Size: 923 B

BIN
react-ui/src/assets/img/tensor-board-unknown.png View File

Before After
Width: 42  |  Height: 42  |  Size: 1.6 kB

+ 1
- 1
react-ui/src/components/KFModal/index.less View File

@@ -5,7 +5,7 @@
border-radius: 21px;
}
.ant-modal-header {
margin: 20px 0;
margin: 20px 0 30px;
background-color: transparent;
}
.ant-modal-footer {


+ 1
- 0
react-ui/src/components/ModalTitle/index.less View File

@@ -3,6 +3,7 @@
display: flex;
align-items: center;
color: @kf-primary-color;
font-weight: 400;
font-size: 20px;

&_image {


+ 42
- 2
react-ui/src/global.less View File

@@ -31,6 +31,12 @@ body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a{
color:#1664ff;
}
.ant-btn-link{
color: #1664ff;
}
.ant-pro-layout .ant-pro-layout-content {
padding: 10px;
}
@@ -46,6 +52,10 @@ body {
.ant-menu-light .ant-menu-item-selected {
background: rgba(197, 232, 255, 0.8) !important;
}
.ant-pro-layout .ant-pro-sider .ant-layout-sider-children{
background:#f2f5f7;

}
.ant-pro-base-menu-inline {
// height: 87vh;
background: #f2f5f7;
@@ -54,7 +64,14 @@ body {
.ant-pro-layout .ant-pro-layout-content {
background-color: transparent;
}

.ant-table-wrapper .ant-table-pagination.ant-pagination{
background-color: #fff;
margin: 0;
padding: 21px 16px;
}
.ant-table-wrapper .ant-table{
height: 75vh;
}
.ant-pro-global-header-logo img {
height: 21px;
}
@@ -64,15 +81,38 @@ body {
.ant-pro-layout .ant-pro-layout-container {
height: 98vh;
}
.ant-modal .ant-modal-close-x{
border: 2px solid #272536;
border-radius: 50%;
width: 26px;
height: 26px;
color: #272536;
}
.ant-modal-content{
margin-left: -130px;
margin-top: 50px;
}
.ant-modal .ant-modal-close:hover {
background-color: transparent;
}
.ant-modal .ant-modal-footer >.ant-btn+.ant-btn{
margin-left: 20px;
}
.ant-pagination .ant-pagination-item-active a {
color: #fff;
background: #1664ff;
border-color: #1664ff;
border-radius:6px;
}
.ant-pagination .ant-pagination-item-active a:hover {
.ant-pagination .ant-pagination-item-active:hover {
color: #fff;
background: rgba(22, 100, 255, 0.8);
border-color: rgba(22, 100, 255, 0.8);
border-radius:6px;
}
.ant-pagination .ant-pagination-item {
border: 1px solid #e6e6e6;
border-radius:6px;
}
// ::-webkit-scrollbar-button {
// background: #97a1bd;


+ 24
- 0
react-ui/src/hooks/index.ts View File

@@ -37,3 +37,27 @@ export function useAntdModal(initialValue: boolean) {

return [visible, open, close];
}

type Callback<T> = (state: T) => void;

/**
* Generates a stateful value and a function to update it that triggers callbacks.
*
* @param initialValue - The initial value of the state.
* @return A tuple containing the current state value and a function to update the state.
*/
export function useCallbackState<T>(initialValue: T) {
const [state, _setState] = useState(initialValue);
const callbackQueue = useRef<Callback<T>[]>([]);
useEffect(() => {
callbackQueue.current.forEach((cb) => cb(state));
callbackQueue.current = [];
}, [state]);
const setState = (newValue: T, callback: Callback<T>) => {
_setState(newValue);
if (callback && typeof callback === 'function') {
callbackQueue.current.push(callback);
}
};
return [state, setState];
}

+ 3
- 3
react-ui/src/pages/Dataset/datasetIntro.jsx View File

@@ -39,9 +39,9 @@ const Dataset = () => {
return {
...form.getFieldsValue(),
dataset_id: locationParams.id,
file_name: item.response.data[0].fileName,
file_size: item.response.data[0].fileSize,
url: item.response.data[0].url,
file_name: item.response.code === 200 ? item.response.data[0].fileName : null,
file_size: item.response.code === 200 ? item.response.data[0].fileSize : null,
url: item.response.code === 200 ? item.response.data[0].url : null,
};
}),
);


+ 4
- 4
react-ui/src/pages/Dataset/index.jsx View File

@@ -1,6 +1,6 @@
import { getDatasetList } from '@/services/dataset/index.js';
import { Form, Input, Tabs } from 'antd';
import React, { useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import Styles from './index.less';
import PersonalData from './personalData';
@@ -9,7 +9,7 @@ const { Search } = Input;
const { TabPane } = Tabs;
const leftdataList = [1, 2, 3];

const Dataset = (React.FC = () => {
const Dataset = () => {
const [queryFlow, setQueryFlow] = useState({
page: 0,
size: 10,
@@ -52,7 +52,7 @@ const Dataset = (React.FC = () => {
console.log('Failed:', errorInfo);
};
useEffect(() => {
getDatasetlist();
//getDatasetlist();
return () => {};
}, []);
return (
@@ -70,5 +70,5 @@ const Dataset = (React.FC = () => {
</div>
</div>
);
});
};
export default Dataset;

+ 4
- 1
react-ui/src/pages/Dataset/index.less View File

@@ -263,7 +263,10 @@
.ant-modal-content {
width: 825px;
padding: 20px 67px;
background: linear-gradient(180deg, #cfdfff 0%, #d4e2ff 9.77%, #ffffff 40%, #ffffff 100%);
background-image: url(/assets/images/modal-back.png);
background-repeat:no-repeat;
background-size:100%;
background-position: top center;
border-radius: 21px;
}
.ant-modal-header {


+ 19
- 20
react-ui/src/pages/Dataset/personalData.jsx View File

@@ -51,6 +51,7 @@ const PublicData = (React.FC = () => {
const [total, setTotal] = useState(0);
const [form] = Form.useForm();
const [dialogTitle, setDialogTitle] = useState('新建数据');
const [uuid, setUuid] = useState(Date.now());
const getDatasetlist = (queryFlow) => {
getDatasetList(queryFlow).then((ret) => {
console.log(ret);
@@ -64,6 +65,7 @@ const PublicData = (React.FC = () => {
const showModal = () => {
form.resetFields();
setDialogTitle('新建数据集');
setUuid(Date.now());
setIsModalOpen(true);
};
const getAssetIconList = (params) => {
@@ -311,30 +313,27 @@ const PublicData = (React.FC = () => {
<Form.Item
label="数据名称"
name="name"
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
required
rules={[
{
required: true,
message: '请输入数据名称e!',
},
]}
>
<Input placeholder="请输入数据名称" />
<Input placeholder="请输入数据名称" showCount maxLength={64} />
</Form.Item>
<Form.Item
label="数据集版本"
name="version"
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
rules={[
{
required: true,
message: '请输入数据集版本!',
},
]}
>
<Input placeholder="请输入数据集版本" />
<Input placeholder="请输入数据集版本" showCount maxLength={64} />
</Form.Item>
<Form.Item
label="数据集分类"
@@ -391,7 +390,7 @@ const PublicData = (React.FC = () => {
]
}
>
<Input placeholder="请输入数据简介" />
<Input placeholder="请输入数据简介" showCount maxLength={256} />
</Form.Item>
<Form.Item label="选择流水线" name="range">
<Radio.Group>
@@ -400,7 +399,7 @@ const PublicData = (React.FC = () => {
</Radio.Group>
</Form.Item>
<Form.Item label="数据文件" name="dataset_version_vos">
<Upload {...props}>
<Upload {...props} data={{ uuid: uuid }}>
<Button
style={{
fontSize: '14px',


+ 26
- 0
react-ui/src/pages/Experiment/components/TensorBoardStatus/index.less View File

@@ -0,0 +1,26 @@
.tensorBoard-status {
display: flex;
align-items: center;
color: rgba(29, 29, 32, 0.75);

&__label {
color: rgba(29, 29, 32, 0.75);
font-size: 15px;

&--running {
color: #6ac21d;
}
&--failed {
color: #df6d6d;
}
}
&__icon {
width: 14px;
color: #6ac21d;
cursor: pointer;

& + & {
margin-left: 6px;
}
}
}

+ 82
- 0
react-ui/src/pages/Experiment/components/TensorBoardStatus/index.tsx View File

@@ -0,0 +1,82 @@
import exportImg from '@/assets/img/tensor-board-export.png';
import pendingImg from '@/assets/img/tensor-board-pending.png';
import { LoadingOutlined } from '@ant-design/icons';
import classNames from 'classnames';
import styles from './index.less';
// import stopImg from '@/assets/img/tensor-board-stop.png';
import terminatedImg from '@/assets/img/tensor-board-terminated.png';

export enum TensorBoardStatusEnum {
Unknown = 'Unknown', // 未知
Pending = 'Pending', // 启动中
Running = 'Running', // 运行中
Terminated = 'Terminated', // 未启动或者已终止
Failed = 'Failed', // 失败
}

const statusConfig = {
Unknown: {
label: '未知',
icon: terminatedImg,
classname: '',
},
Terminated: {
label: '未启动',
icon: terminatedImg,
classname: '',
},
Failed: {
label: '失败',
icon: terminatedImg,
classname: 'tensorBoard-status__label--failed',
},
Pending: {
label: '启动中',
icon: pendingImg,
classname: '',
},
Running: {
label: '运行中',
icon: exportImg,
classname: 'tensorBoard-status__label--running',
},
};

type TensorBoardStatusProps = {
status: TensorBoardStatusEnum;
onClick: () => void;
};

function TensorBoardStatus({
status = TensorBoardStatusEnum.Unknown,
onClick,
}: TensorBoardStatusProps) {
return (
<div className={styles['tensorBoard-status']}>
<div
className={classNames(
styles['tensorBoard-status__label'],
styles[statusConfig[status].classname],
)}
>
{statusConfig[status].label}
</div>
{statusConfig[status].icon ? (
<>
<div style={{ margin: '0 6px' }}>|</div>
{status === TensorBoardStatusEnum.Pending ? (
<LoadingOutlined className={styles['tensorBoard-status__icon']} />
) : (
<img
className={styles['tensorBoard-status__icon']}
src={statusConfig[status].icon}
onClick={onClick}
/>
)}
</>
) : null}
</div>
);
}

export default TensorBoardStatus;

+ 1
- 1
react-ui/src/pages/Experiment/experimentText/paramsModal.less View File

@@ -1,6 +1,6 @@
.params_container {
max-height: 230px;
padding: 15px;
padding: 15px 15px 0;
border: 1px solid #e6e6e6;
border-radius: 8px;



+ 122
- 14
react-ui/src/pages/Experiment/index.jsx View File

@@ -4,10 +4,12 @@ import {
getExperiment,
getExperimentById,
getQueryByExperimentId,
getTensorBoardStatusReq,
postExperiment,
putExperiment,
putQueryByExperimentInsId,
runExperiments,
runTensorBoardReq,
} from '@/services/experiment/index.js';
import { getWorkflow } from '@/services/pipeline/index.js';
import { elapsedTime } from '@/utils/date';
@@ -23,10 +25,14 @@ import { Button, Modal, Space, Table, message } from 'antd';
import momnet from 'moment';
import { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import TensorBoardStatus, { TensorBoardStatusEnum } from './components/TensorBoardStatus';
import AddExperimentModal from './experimentText/addExperimentModal';
import Styles from './index.less';
import { experimentStatusInfo } from './status';

// 定时器
const timerIds = new Map();

function Experiment() {
const navgite = useNavigate();
const [experimentList, setExperimentList] = useState([]);
@@ -44,9 +50,13 @@ function Experiment() {
const [isAdd, setIsAdd] = useState(true);
const [isModalOpen, setIsModalOpen] = useState(false);
const [addFormData, setAddFormData] = useState({});

useEffect(() => {
getList();
getWorkflowList();
return () => {
clearExperimentInTimers();
};
}, []);
// 获取实验列表
const getList = async () => {
@@ -72,11 +82,32 @@ function Experiment() {
setWorkflowList(res.data.content);
}
};
// 获取实验实例
const getQueryByExperiment = (val) => {
getQueryByExperimentId(val).then((ret) => {
setExpandedRowKeys(val);
if (ret.code === 200 && ret.data && ret.data.length > 0) {
setExperimentInList(ret.data);
if (ret && ret.data && ret.data.length > 0) {
try {
const list = ret.data.map((v) => {
const nodes_result = v.nodes_result ? JSON.parse(v.nodes_result) : {};
return {
...v,
nodes_result,
};
});
setExperimentInList(list);
// 获取 TensorBoard 状态
list.forEach((item) => {
if (item.nodes_result.tensorboard_log) {
const timerId = setTimeout(() => {
getTensorBoardStatus(item);
}, 0);
timerIds.set(item.id, timerId);
}
});
} catch (error) {
setExperimentInList([]);
}
getList();
} else {
setExperimentInList([]);
@@ -84,13 +115,66 @@ function Experiment() {
}
});
};
// 运行 TensorBoard
const runTensorBoard = async (experimentIn) => {
const params = {
namespace: experimentIn.nodes_result.tensorboard_log.namespace,
path: experimentIn.nodes_result.tensorboard_log.path,
pvc_name: experimentIn.nodes_result.tensorboard_log.pvc_name,
};
const [res] = await to(runTensorBoardReq(params));
if (res) {
experimentIn.tensorboardUrl = res.data;
const timerId = timerIds.get(experimentIn.id);
if (timerId) {
clearTimeout(timerId);
timerIds.delete(experimentIn.id);
getTensorBoardStatus(experimentIn);
}
}
};
// 获取 TensorBoard 状态
const getTensorBoardStatus = async (experimentIn) => {
const params = {
namespace: experimentIn.nodes_result.tensorboard_log.namespace,
path: experimentIn.nodes_result.tensorboard_log.path,
pvc_name: experimentIn.nodes_result.tensorboard_log.pvc_name,
};
const [res] = await to(getTensorBoardStatusReq(params));
if (res && res.data) {
setExperimentInList((prevList) => {
const newList = [...prevList];
const index = prevList.findIndex((item) => item.id === experimentIn.id);
const preObj = prevList[index];
const newObj = {
...preObj,
tensorBoardStatus: res.data.status,
tensorboardUrl: res.data.url,
};
newList.splice(index, 1, newObj);
return newList;
});
const timerId = setTimeout(() => {
getTensorBoardStatus(experimentIn);
}, 10000);
timerIds.set(experimentIn.id, timerId);
}
};
const expandChange = (e, record) => {
if (record.id === expandedRowKeys) {
clearExperimentInTimers();
setExpandedRowKeys(null);
} else {
getQueryByExperiment(record.id);
}
};
// 终止实验实例获取 TensorBoard 状态的定时器
const clearExperimentInTimers = () => {
timerIds.values().forEach((timerId) => {
clearTimeout(timerId);
});
timerIds.clear();
};
// 创建实验
const createExperiment = () => {
setIsAdd(true);
@@ -174,6 +258,19 @@ function Experiment() {
navgite({ pathname: `/experiment/pytorchtext/${record.workflow_id}/${item.id}` });
};

const handleTensorboard = async (experimentIn) => {
if (
experimentIn.tensorBoardStatus === TensorBoardStatusEnum.Terminated ||
experimentIn.tensorBoardStatus === TensorBoardStatusEnum.Failed
) {
await runTensorBoard(experimentIn);
} else if (
experimentIn.tensorBoardStatus === TensorBoardStatusEnum.Running &&
experimentIn.tensorboardUrl
) {
window.open(experimentIn.tensorboardUrl, '_blank');
}
};
const columns = [
{
title: '实验名称',
@@ -198,7 +295,6 @@ function Experiment() {
key: 'status_list',
render: (text) => {
let newText = text && text.replace(/\s+/g, '').split(',');
console.log(newText);
return (
<>
{newText && newText.length > 0
@@ -306,15 +402,17 @@ function Experiment() {
columns={columns}
dataSource={experimentList}
pagination={paginationProps}
rowKey="id"
expandable={{
expandedRowRender: (record) => (
<div>
{experimentInList && experimentInList.length > 0 ? (
<div className={Styles.tableExpandBox} style={{ paddingBottom: '16px' }}>
<div style={{ width: '50px' }}>序号</div>
<div style={{ width: '200px' }}>状态</div>
<div style={{ width: '150px' }}>序号</div>
<div style={{ width: '300px' }}>TensorBoard</div>
<div style={{ width: '300px' }}>运行时长</div>
<div style={{ width: '300px' }}>开始时间</div>
<div style={{ width: '200px' }}>状态</div>
<div style={{ width: '200px' }}>操作</div>
</div>
) : (
@@ -332,9 +430,27 @@ function Experiment() {
height: '45px',
}}
>
<a style={{ width: '50px' }} onClick={(e) => routerToText(e, item, record)}>
<a style={{ width: '150px' }} onClick={(e) => routerToText(e, item, record)}>
{index + 1}
</a>
<div style={{ width: '300px' }}>
{item.nodes_result.tensorboard_log ? (
<TensorBoardStatus
status={item.tensorBoardStatus}
onClick={() => handleTensorboard(item)}
></TensorBoardStatus>
) : (
'-'
)}
</div>
<div style={{ width: '300px' }}>
{item.finish_time
? elapsedTime(new Date(item.create_time), new Date(item.finish_time))
: elapsedTime(new Date(item.create_time), new Date())}
</div>
<div style={{ width: '300px' }}>
{momnet(item.create_time).format('YYYY-MM-DD HH:mm:ss')}
</div>
<div className={Styles.statusBox} style={{ width: '200px' }}>
<img
style={{ width: '17px', marginRight: '7px' }}
@@ -347,14 +463,6 @@ function Experiment() {
{experimentStatusInfo[item.status]?.label}
</span>
</div>
<div style={{ width: '300px' }}>
{item.finish_time
? elapsedTime(new Date(item.create_time), new Date(item.finish_time))
: elapsedTime(new Date(item.create_time), new Date())}
</div>
<div style={{ width: '300px' }}>
{momnet(item.create_time).format('YYYY-MM-DD HH:mm:ss')}
</div>
<div style={{ width: '200px' }}>
<Button
type="link"


+ 4
- 1
react-ui/src/pages/Model/index.less View File

@@ -259,7 +259,10 @@
.ant-modal-content {
width: 825px;
padding: 20px 67px;
background: linear-gradient(180deg, #cfdfff 0%, #d4e2ff 9.77%, #ffffff 40%, #ffffff 100%);
background-image: url(/assets/images/modal-back.png);
background-repeat:no-repeat;
background-size:100%;
background-position: top center;
border-radius: 21px;
}
.ant-modal-header {


+ 9
- 7
react-ui/src/pages/Model/modelIntro.jsx View File

@@ -39,9 +39,9 @@ const Dataset = () => {
return {
...form.getFieldsValue(),
models_id: locationParams.id,
file_name: item.response.data[0].fileName,
file_size: item.response.data[0].fileSize,
url: item.response.data[0].url,
file_name: item.response.code === 200 ? item.response.data[0].fileName : null,
file_size: item.response.code === 200 ? item.response.data[0].fileSize : null,
url: item.response.code === 200 ? item.response.data[0].url : null,
};
}),
);
@@ -59,6 +59,7 @@ const Dataset = () => {
const locationParams = useParams(); //新版本获取路由参数接口
console.log(locationParams);
const [wordList, setWordList] = useState([]);
const [uuid, setUuid] = useState(Date.now());
const getModelByDetail = () => {
getModelById(locationParams.id).then((ret) => {
console.log(ret);
@@ -68,7 +69,7 @@ const Dataset = () => {
const getModelVersionsList = () => {
getModelVersionsById(locationParams.id).then((ret) => {
console.log(ret);
if (ret.data && ret.data.length > 0) {
if (ret && ret.data && ret.data.length > 0) {
setVersionList(
ret.data.map((item) => {
return {
@@ -77,6 +78,8 @@ const Dataset = () => {
};
}),
);
setVersion(ret.data[0]);
getModelVersions({ version: ret.data[0], models_id: locationParams.id });
}
});
};
@@ -90,6 +93,7 @@ const Dataset = () => {
form.setFieldsValue({ name: datasetDetailObj.name });

setDialogTitle('创建新版本');
setUuid(Date.now());
setIsModalOpen(true);
};
const handleCancel = () => {
@@ -104,9 +108,7 @@ const Dataset = () => {

onOk: () => {
deleteModelVersion({ models_id: locationParams.id, version }).then((ret) => {
setVersion(null);
getModelVersionsList();
getModelVersions({ version, models_id: locationParams.id });
message.success('删除成功');
});
},
@@ -368,7 +370,7 @@ const Dataset = () => {
},
]}
>
<Upload {...props}>
<Upload {...props} data={{ uuid: uuid }}>
<Button
style={{
fontSize: '14px',


+ 17
- 19
react-ui/src/pages/Model/personalData.jsx View File

@@ -49,6 +49,7 @@ const PublicData = () => {
const [total, setTotal] = useState(0);
const [form] = Form.useForm();
const [dialogTitle, setDialogTitle] = useState('新建模型');
const [uuid, setUuid] = useState(Date.now());
const getModelLists = (queryFlow) => {
getModelList(queryFlow).then((ret) => {
console.log(ret);
@@ -62,6 +63,7 @@ const PublicData = () => {
const showModal = () => {
form.resetFields();
setDialogTitle('新建模型');
setUuid(Date.now());
setIsModalOpen(true);
};
const getAssetIconList = (params) => {
@@ -314,31 +316,27 @@ const PublicData = () => {
<Form.Item
label="模型名称"
name="name"
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
rules={[
{
required: true,
message: '请输入模型名称!',
},
]}
>
<Input placeholder="请输入模型名称" />
<Input placeholder="请输入模型名称" showCount maxLength={64} />
</Form.Item>

<Form.Item
label="模型描述"
name="description"
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
rules={[
{
required: true,
message: '请输入模型描述!',
},
]}
>
<Input placeholder="请输入模型描述" />
<Input placeholder="请输入模型描述" showCount maxLength={256} />
</Form.Item>
<Form.Item label="可见范围" name="available_range">
<Radio.Group>
@@ -375,7 +373,7 @@ const PublicData = () => {
<Select allowClear placeholder="请选择模型标签" options={[]} />
</Form.Item>
<Form.Item label="模型文件" name="dataset_version_vos">
<Upload {...props}>
<Upload {...props} data={{ uuid: uuid }}>
<Button icon={<UploadOutlined style={{ color: '#1664ff' }} />}>上传文件</Button>
</Upload>
</Form.Item>


+ 1
- 0
react-ui/src/pages/Pipeline/editPipeline/modelMenus.jsx View File

@@ -42,6 +42,7 @@ const modelMenus = ({ onParDragEnd }) => {
const { Panel } = Collapse;
return (
<div style={{ width: '250px', height: '99%' }} className={Styles.collapse}>
<div className={Styles.modelMenusTitle}>组件库</div>
<Collapse collapsible="header" defaultActiveKey={['1']} expandIconPosition="end">
{modelMenusList && modelMenusList.length > 0
? modelMenusList.map((item) => (


+ 11
- 1
react-ui/src/pages/Pipeline/editPipeline/modelMenus.less View File

@@ -12,6 +12,7 @@
}
.collapseItem:hover {
background: rgba(22, 100, 255, 0.08);
color:#1664ff;
}
.collapse {
:global {
@@ -23,10 +24,12 @@
margin-bottom: 5px;
background-color: #fff;
border-color: transparent;
padding: 20px 16px 15px 16px;
}

.ant-collapse > .ant-collapse-item {
margin: 0 10px;
border-color: rgba(20, 49, 179, 0.12);
border-bottom:0.5px dashed rgba(20, 49, 179, 0.12);
border-radius: 0px;
}
.ant-collapse .ant-collapse-content {
@@ -38,3 +41,10 @@
}
}
}
.modelMenusTitle{
padding: 12px 25px;
margin-bottom: 10px;
color:#111111;
font-size:16px;
font-family: 'Alibaba';
}

+ 18
- 20
react-ui/src/pages/Pipeline/index.jsx View File

@@ -111,7 +111,8 @@ const Pipeline = () => {
title: '序号',
dataIndex: 'index',
key: 'index',
width: 80,
width: 140,
align: 'center',
render(text, record, index) {
return <span>{(pageOption.current.page - 1) * 10 + index + 1}</span>;
},
@@ -143,6 +144,7 @@ const Pipeline = () => {
{
title: '操作',
key: 'action',
width: 320,

render: (_, record) => (
<Space size="small">
@@ -241,7 +243,7 @@ const Pipeline = () => {
新建流水线
</Button>
</div>
<Table columns={columns} dataSource={pipeList} pagination={paginationProps} />
<Table columns={columns} dataSource={pipeList} pagination={paginationProps} rowKey="id" />
<Modal
title={
<div style={{ display: 'flex', alignItems: 'center', fontWeight: 500 }}>
@@ -275,30 +277,26 @@ const Pipeline = () => {
<Form.Item
label="流水线名称"
name="name"
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
rules={[
{
required: true,
message: '请输入流水线名称',
},
]}
>
<Input />
<Input showCount maxLength={64} />
</Form.Item>
<Form.Item
label="流水线描述"
name="description"
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
rules={[
{
required: true,
message: '请输入流水线描述',
},
]}
>
<Input />
<Input showCount maxLength={128} />
</Form.Item>
</Form>
</Modal>


+ 4
- 1
react-ui/src/pages/Pipeline/index.less View File

@@ -29,7 +29,10 @@
.ant-modal-content {
width: 825px;
padding: 20px 67px;
background: linear-gradient(180deg, #cfdfff 0%, #d4e2ff 9.77%, #ffffff 40%, #ffffff 100%);
background-image: url(/assets/images/modal-back.png);
background-repeat:no-repeat;
background-size:100%;
background-position: top center;
border-radius: 21px;
}
.ant-modal-header {


+ 16
- 0
react-ui/src/services/experiment/index.js View File

@@ -100,3 +100,19 @@ export function putExperiment(data) {
data,
});
}

// 启动tensorBoard
export function runTensorBoardReq(data) {
return request(`/api/mmp/tensorBoard/run`, {
method: 'POST',
data,
});
}

// 启动tensorBoard
export function getTensorBoardStatusReq(data) {
return request(`/api/mmp/tensorBoard/getStatus`, {
method: 'POST',
data,
});
}

Loading…
Cancel
Save