Browse Source

Merge pull request '合并dev-zw' (#135) from dev-zw into dev

dev-lhz
cp3hnu 1 year ago
parent
commit
c6c48a5bae
22 changed files with 216 additions and 41 deletions
  1. BIN
      react-ui/src/assets/img/comfirm-icon.png
  2. +7
    -0
      react-ui/src/components/KFConfirmModal/index.less
  3. +37
    -0
      react-ui/src/components/KFConfirmModal/index.tsx
  4. +1
    -1
      react-ui/src/enums/index.ts
  5. +9
    -0
      react-ui/src/pages/CodeConfig/List/index.tsx
  6. +1
    -1
      react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx
  7. +1
    -1
      react-ui/src/pages/Dataset/components/AddModelModal/index.tsx
  8. +1
    -1
      react-ui/src/pages/Dataset/components/AddVersionModal/index.tsx
  9. +2
    -3
      react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx
  10. +2
    -4
      react-ui/src/pages/Model/components/NodeTooltips/index.tsx
  11. +5
    -2
      react-ui/src/pages/ModelDeployment/CreateService/index.tsx
  12. +22
    -6
      react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx
  13. +47
    -2
      react-ui/src/pages/ModelDeployment/List/index.tsx
  14. +8
    -2
      react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx
  15. +6
    -0
      react-ui/src/pages/ModelDeployment/components/BasicInfo/index.less
  16. +6
    -3
      react-ui/src/pages/ModelDeployment/components/BasicInfo/index.tsx
  17. +1
    -1
      react-ui/src/pages/ModelDeployment/components/ModelDeployStatusCell/index.tsx
  18. +1
    -1
      react-ui/src/pages/ModelDeployment/components/ServerLog/index.tsx
  19. +1
    -1
      react-ui/src/pages/ModelDeployment/components/UserGuide/index.tsx
  20. +9
    -0
      react-ui/src/pages/ModelDeployment/types.ts
  21. +28
    -7
      react-ui/src/utils/index.ts
  22. +21
    -5
      react-ui/src/utils/ui.tsx

BIN
react-ui/src/assets/img/comfirm-icon.png View File

Before After
Width: 432  |  Height: 287  |  Size: 22 kB

+ 7
- 0
react-ui/src/components/KFConfirmModal/index.less View File

@@ -0,0 +1,7 @@
.kf-confirm-modal {
&__content {
width: 100%;
font-size: 18px;
text-align: center;
}
}

+ 37
- 0
react-ui/src/components/KFConfirmModal/index.tsx View File

@@ -0,0 +1,37 @@
/*
* @Author: 赵伟
* @Date: 2024-10-10 10:54:25
* @Description: 自定义 Confirm Modal
*/

import classNames from 'classnames';
import KFModal, { KFModalProps } from '../KFModal';
import './index.less';

export interface KFConfirmModalProps extends KFModalProps {
content: string;
}
function KFConfirmModal({
title,
image,
className = '',
centered,
maskClosable,
content,
...rest
}: KFConfirmModalProps) {
return (
<KFModal
className={classNames(['kf-confirm-modal', className])}
{...rest}
centered={centered ?? true}
maskClosable={maskClosable ?? false}
title={title}
image={image ?? require('@/assets/img/edit-experiment.png')}
>
<div className="kf-confirm-modal__content">{content}</div>
</KFModal>
);
}

export default KFConfirmModal;

+ 1
- 1
react-ui/src/enums/index.ts View File

@@ -80,7 +80,7 @@ export enum ServiceType {

export const serviceTypeOptions = [
{ label: '视频', value: ServiceType.Video },
{ label: '图', value: ServiceType.Image },
{ label: '图', value: ServiceType.Image },
{ label: '音频', value: ServiceType.Audio },
{ label: '文本', value: ServiceType.Text },
];

+ 9
- 0
react-ui/src/pages/CodeConfig/List/index.tsx View File

@@ -1,6 +1,7 @@
import KFEmpty, { EmptyType } from '@/components/KFEmpty';
import KFIcon from '@/components/KFIcon';
import { deleteCodeConfigReq, getCodeConfigListReq } from '@/services/codeConfig';
import { getGitUrl } from '@/utils';
import { openAntdModal } from '@/utils/modal';
import { to } from '@/utils/promise';
import { modalConfirm } from '@/utils/ui';
@@ -99,6 +100,13 @@ function CodeConfigList() {
});
};

// 查看
const handleClick = (record: CodeConfigData) => {
const { git_url, git_branch } = record;
const url = getGitUrl(git_url, git_branch);
window.open(url, '_blank');
};

// 新建
const createCodeConfig = () => {
const { close } = openAntdModal(AddCodeConfigModal, {
@@ -152,6 +160,7 @@ function CodeConfigList() {
key={item.id}
onRemove={handleRemove}
onEdit={handleEdit}
onClick={handleClick}
/>
))}
</div>


+ 1
- 1
react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx View File

@@ -123,7 +123,7 @@ function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalPr
},
{
pattern: /^[a-zA-Z0-9._-]+$/,
message: '版本只支持字母、数字、下划线、点、横杠',
message: '版本只支持字母、数字、点、下划线、中横线',
},
{
validator: (_rule, value) => {


+ 1
- 1
react-ui/src/pages/Dataset/components/AddModelModal/index.tsx View File

@@ -108,7 +108,7 @@ function AddModelModal({ typeList, tagList, onOk, ...rest }: AddModelModalProps)
},
{
pattern: /^[a-zA-Z0-9._-]+$/,
message: '版本只支持字母、数字、下划线、点、横杠',
message: '版本只支持字母、数字、点、下划线、中横线',
},
{
validator: (_rule, value) => {


+ 1
- 1
react-ui/src/pages/Dataset/components/AddVersionModal/index.tsx View File

@@ -123,7 +123,7 @@ function AddVersionModal({
},
{
pattern: /^[a-zA-Z0-9._-]+$/,
message: '版本只支持字母、数字、下划线、点、横杠',
message: '版本只支持字母、数字、点、下划线、中横线',
},
{
validator: (_rule, value) => {


+ 2
- 3
react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx View File

@@ -9,6 +9,7 @@ import {
ResourceType,
TrainTask,
} from '@/pages/Dataset/config';
import { getGitUrl } from '@/utils';
import styles from './index.less';

type ResourceIntroProps = {
@@ -54,9 +55,7 @@ const getProjectUrl = (project?: ProjectDependency) => {
return undefined;
}
const { url, branch } = project;
if (url.endsWith('.git')) {
return `${url.substring(0, url.length - 4)}/tree/${branch}`;
}
return getGitUrl(url, branch);
};

const formatProject = (project?: ProjectDependency) => {


+ 2
- 4
react-ui/src/pages/Model/components/NodeTooltips/index.tsx View File

@@ -1,4 +1,5 @@
import { ResourceInfoTabKeys } from '@/pages/Dataset/components/ResourceInfo';
import { getGitUrl } from '@/utils';
import { formatDate } from '@/utils/date';
import { useNavigate } from '@umijs/max';
import { ModelDepsData, NodeType, ProjectDependency, TrainDataset } from '../ModelEvolution/utils';
@@ -127,10 +128,7 @@ function DatasetInfo({ data }: { data: TrainDataset }) {
function ProjectInfo({ data }: { data: ProjectDependency }) {
const gotoProjectPage = () => {
const { url, branch } = data;
let projectUrl = url;
if (url.endsWith('.git')) {
projectUrl = `${url.substring(0, url.length - 4)}/tree/${branch}`;
}
const projectUrl = getGitUrl(url, branch);
window.open(projectUrl, '_blank');
};



+ 5
- 2
react-ui/src/pages/ModelDeployment/CreateService/index.tsx View File

@@ -18,7 +18,7 @@ import { useNavigate } from '@umijs/max';
import { App, Button, Col, Form, Input, Row, Select } from 'antd';
import { pick } from 'lodash';
import { useEffect, useState } from 'react';
import { ServiceData, ServiceOperationType } from '../types';
import { ServiceData, ServiceOperationType, createServiceVersionMessage } from '../types';
import styles from './index.less';

// 表单数据
@@ -59,9 +59,12 @@ function CreateService() {
...formData,
};
const [res] = await to(request(params));
if (res) {
if (res && res.data) {
message.success('操作成功');
navigate(-1);
setTimeout(() => {
window.postMessage({ type: createServiceVersionMessage, payload: res.data.id });
}, 500);
}
};



+ 22
- 6
react-ui/src/pages/ModelDeployment/CreateVersion/index.tsx View File

@@ -31,7 +31,12 @@ import { useNavigate, useParams } from '@umijs/max';
import { App, Button, Col, Flex, Form, Input, Row, Select } from 'antd';
import { omit, pick } from 'lodash';
import { useEffect, useState } from 'react';
import { ServiceData, ServiceOperationType, ServiceVersionData } from '../types';
import {
CreateServiceVersionFrom,
ServiceData,
ServiceOperationType,
ServiceVersionData,
} from '../types';
import styles from './index.less';

// 表单数据
@@ -53,6 +58,7 @@ function CreateServiceVersion() {
const [form] = Form.useForm();
const [resourceStandardList, filterResourceStandard] = useComputingResource();
const [operationType, setOperationType] = useState(ServiceOperationType.Create);
const [lastPage, setLastPage] = useState(CreateServiceVersionFrom.ServiceInfo);
const { message } = App.useApp();
const [serviceInfo, setServiceInfo] = useState<ServiceData | undefined>(undefined);
const [versionInfo, setVersionInfo] = useState<ServiceVersionData | undefined>(undefined);
@@ -60,10 +66,15 @@ function CreateServiceVersion() {
const id = params.id;

useEffect(() => {
const res: (ServiceVersionData & { operationType: ServiceOperationType }) | undefined =
getSessionStorageItem(serviceVersionInfoKey, true);
const res:
| (ServiceVersionData & {
operationType: ServiceOperationType;
lastPage: CreateServiceVersionFrom;
})
| undefined = getSessionStorageItem(serviceVersionInfoKey, true);
if (res) {
setOperationType(res.operationType);
setLastPage(res.lastPage);
setVersionInfo(res);
let model, codeConfig, envVariables;
if (res.model && typeof res.model === 'object') {
@@ -156,7 +167,11 @@ function CreateServiceVersion() {
const [res] = await to(request(params));
if (res) {
message.success('操作成功');
navigate(-1);
if (lastPage === CreateServiceVersionFrom.ServiceInfo) {
navigate(-1);
} else {
navigate(`/modelDeployment/serviceInfo/${serviceInfo?.id}`, { replace: true });
}
}
};

@@ -234,7 +249,7 @@ function CreateServiceVersion() {
},
{
pattern: /^[a-zA-Z0-9._-]+$/,
message: '版本只支持字母、数字、下划线、点、横杠',
message: '版本只支持字母、数字、点、下划线、中横线',
},
]}
>
@@ -401,7 +416,8 @@ function CreateServiceVersion() {
},
{
pattern: /^\/[a-zA-Z0-9._/-]+$/,
message: '请输入正确的挂载绝对路径',
message:
'请输入正确的挂载路径,以 / 开头,只支持字母、数字、点、下划线、中横线、斜杠',
},
]}
>


+ 47
- 2
react-ui/src/pages/ModelDeployment/List/index.tsx View File

@@ -12,7 +12,11 @@ import { useCacheState } from '@/hooks/pageCacheState';
import { deleteServiceReq, getServiceListReq } from '@/services/modelDeployment';
import themes from '@/styles/theme.less';
import { to } from '@/utils/promise';
import { serviceInfoKey, setSessionStorageItem } from '@/utils/sessionStorage';
import {
serviceInfoKey,
serviceVersionInfoKey,
setSessionStorageItem,
} from '@/utils/sessionStorage';
import { modalConfirm } from '@/utils/ui';
import { useNavigate } from '@umijs/max';
import {
@@ -28,7 +32,12 @@ import {
import { type SearchProps } from 'antd/es/input';
import classNames from 'classnames';
import { useEffect, useState } from 'react';
import { ServiceData, ServiceOperationType } from '../types';
import {
CreateServiceVersionFrom,
ServiceData,
ServiceOperationType,
createServiceVersionMessage,
} from '../types';
import styles from './index.less';

const allServiceTypeOptions = [{ label: '全部', value: '' }, ...serviceTypeOptions];
@@ -49,6 +58,13 @@ function ModelDeployment() {
},
);

useEffect(() => {
window.addEventListener('message', handleMessage);
return () => {
window.removeEventListener('message', handleMessage);
};
}, []);

useEffect(() => {
getServiceList();
}, [pagination, searchText, serviceType]);
@@ -137,6 +153,35 @@ function ModelDeployment() {
navigate(`/modelDeployment/serviceInfo/${record.id}`);
};

const handleMessage = (e: MessageEvent) => {
const { type, payload } = e.data;
if (type === createServiceVersionMessage) {
modalConfirm({
title: '创建服务成功',
content: '是否创建服务版本?',
isDelete: false,
cancelText: '稍后创建',
onOk: () => {
gotoCreateServiceVersion(payload);
},
});
}
};

// 去创建服务版本
const gotoCreateServiceVersion = (serviceId: number) => {
setSessionStorageItem(
serviceVersionInfoKey,
{
operationType: ServiceOperationType.Create,
lastPage: CreateServiceVersionFrom.CreateService,
},
true,
);

navigate(`/modelDeployment/addVersion/${serviceId}`);
};

// 分页切换
const handleTableChange: TableProps['onChange'] = (pagination, _filters, _sorter, { action }) => {
if (action === 'paginate') {


+ 8
- 2
react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx View File

@@ -38,7 +38,12 @@ import { type SearchProps } from 'antd/es/input';
import classNames from 'classnames';
import { useEffect, useState } from 'react';
import ServiceRunStatusCell from '../components/ModelDeployStatusCell';
import { ServiceData, ServiceOperationType, ServiceVersionData } from '../types';
import {
CreateServiceVersionFrom,
ServiceData,
ServiceOperationType,
ServiceVersionData,
} from '../types';
import styles from './index.less';

const allServiceStatusOptions = [{ label: '全部', value: '' }, ...serviceStatusOptions];
@@ -171,13 +176,14 @@ function ServiceInfo() {
});
};

// 创建、更新、重启模型部署
// 创建、更新、重启服务版本
const createServiceVersion = (type: ServiceOperationType, record?: ServiceVersionData) => {
setSessionStorageItem(
serviceVersionInfoKey,
{
...record,
operationType: type,
lastPage: CreateServiceVersionFrom.ServiceInfo,
},
true,
);


+ 6
- 0
react-ui/src/pages/ModelDeployment/components/BasicInfo/index.less View File

@@ -0,0 +1,6 @@
.basic-info {
a:hover {
text-decoration: underline @underline-color;
text-underline-offset: 3px;
}
}

+ 6
- 3
react-ui/src/pages/ModelDeployment/components/BasicInfo/index.tsx View File

@@ -1,10 +1,12 @@
import LabelValue from '@/components/LabelValue';
import { useComputingResource } from '@/hooks/resource';
import { ServiceVersionData } from '@/pages/ModelDeployment/types';
import { getGitUrl } from '@/utils';
import { formatDate } from '@/utils/date';
import { Link } from '@umijs/max';
import { Col, Row } from 'antd';
import ServiceRunStatusCell from '../ModelDeployStatusCell';
import styles from './index.less';

type BasicInfoProps = {
info?: ServiceVersionData;
@@ -15,7 +17,7 @@ function BasicInfo({ info }: BasicInfoProps) {

// 格式化环境变量
const formatEnvText = () => {
if (!info?.env_variables) {
if (!info?.env_variables || Object.keys(info.env_variables).length === 0) {
return '--';
}
const env = info.env_variables;
@@ -26,7 +28,8 @@ function BasicInfo({ info }: BasicInfoProps) {

const formatCodeConfig = () => {
if (info && info.code_config) {
const url = `${info.code_config.code_path}/tree/${info.code_config.branch}`;
const { code_path, branch } = info.code_config;
const url = getGitUrl(code_path, branch);
return (
<a href={url} target="_blank" rel="noreferrer">
{info?.code_config?.show_value}
@@ -53,7 +56,7 @@ function BasicInfo({ info }: BasicInfoProps) {
};

return (
<div>
<div className={styles['basic-info']}>
<Row gutter={40} style={{ marginBottom: '20px' }}>
<Col span={10}>
<LabelValue label="服务名称:" value={info?.service_name}></LabelValue>


+ 1
- 1
react-ui/src/pages/ModelDeployment/components/ModelDeployStatusCell/index.tsx View File

@@ -1,7 +1,7 @@
/*
* @Author: 赵伟
* @Date: 2024-04-18 18:35:41
* @Description: 模型部署状态
* @Description: 服务运行状态
*/
import { ServiceRunStatus } from '@/enums';
import styles from './index.less';


+ 1
- 1
react-ui/src/pages/ModelDeployment/components/ServerLog/index.tsx View File

@@ -57,7 +57,7 @@ function ServerLog({ info }: ServerLogProps) {
getModelDeploymentLog();
}, [info, logTime]);

// 获取模型部署日志
// 获取服务日志
const getModelDeploymentLog = async () => {
if (info && logTime && logTime.length === 2) {
const params = {


+ 1
- 1
react-ui/src/pages/ModelDeployment/components/UserGuide/index.tsx View File

@@ -14,7 +14,7 @@ function UserGuide({ info }: UserGuideProps) {
getModelDeploymentDocs();
}, [info]);

// 获取模型部署文档
// 获取服务文档
const getModelDeploymentDocs = async () => {
if (info) {
const [res] = await to(getServiceVersionDocsReq(info.id));


+ 9
- 0
react-ui/src/pages/ModelDeployment/types.ts View File

@@ -57,3 +57,12 @@ export enum ServiceOperationType {
Update = 'Update', // 更新
Restart = 'Restart', // 重启
}

// 操作类型
export enum CreateServiceVersionFrom {
CreateService = 'CreateService', // 来自创建服务
ServiceInfo = 'ServiceInfo', // 来自服务详情
}

// 去创建服务版本消息
export const createServiceVersionMessage = 'createServiceVersion';

+ 28
- 7
react-ui/src/utils/index.ts View File

@@ -31,7 +31,7 @@ export function parseJsonText(text?: string | null): any | null {
}
}

// 判断是否为对象
// 判断是否为一般对象
function isPlainObject(value: any) {
if (value === null || typeof value !== 'object') return false;
let proto = Object.getPrototypeOf(value);
@@ -160,13 +160,13 @@ export function changePropertyName(obj: Record<string, any>, mapping: Record<str
}

/**
* 计算显示的字符串
* @param tr 要裁剪的字符串
* @param maxWidth 最大宽度
* @param fontSize 字体大小
* @return 处理后的字符串
* 计算显示的字符串
* @param {string} str 要裁剪的字符串
* @param {number} maxWidth 最大宽度
* @param {number} fontSize 字体大小
* @return {string} 处理后的字符串
*/
export const fittingString = (str: string, maxWidth: number, fontSize: number) => {
export const fittingString = (str: string, maxWidth: number, fontSize: number): string => {
if (!str) {
return '';
}
@@ -200,3 +200,24 @@ export const fittingString = (str: string, maxWidth: number, fontSize: number) =
export const isEmptyString = (str: any): boolean => {
return str === '' || str === undefined || str === null;
};

/**
* 获取 git 仓库的 url
*
* @param {string} url - the url of the git repository
* @param {string} branch - the branch of the repository
* @return {string} the url of the repository
*
* If `branch` is given, the url will be in the format of 'http://gitlab.com/user/repo/tree/branch'.
* Otherwise, the url will be in the format of 'http://gitlab.com/user/repo'.
*/
export const getGitUrl = (url: string, branch: string): string => {
if (!url) {
return '';
}
const gitUrl = url.replace(/\.git$/, '');
if (branch) {
return `${gitUrl}/tree/${branch}`;
}
return gitUrl;
};

+ 21
- 5
react-ui/src/utils/ui.tsx View File

@@ -10,8 +10,20 @@ import { history } from '@umijs/max';
import { Modal, message, type ModalFuncProps, type UploadFile } from 'antd';
import { closeAllModals } from './modal';

// 自定义 Confirm 弹框
export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps) {
type ModalConfirmProps = ModalFuncProps & {
isDelete?: boolean;
};

// 自定义删除 Confirm 弹框
export function modalConfirm({
title,
content,
okText = '确认',
cancelText = '取消',
isDelete = true,
onOk,
...rest
}: ModalConfirmProps) {
Modal.confirm({
...rest,
width: 600,
@@ -19,7 +31,11 @@ export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps)
title: (
<div>
<img
src={require('@/assets/img/delete-icon.png')}
src={
isDelete
? require('@/assets/img/delete-icon.png')
: require('@/assets/img/comfirm-icon.png')
}
style={{ width: '120px', marginBottom: '24px' }}
draggable={false}
alt=""
@@ -28,8 +44,8 @@ export function modalConfirm({ title, content, onOk, ...rest }: ModalFuncProps)
</div>
),
content: content && <div style={{ color: themes.textColor, fontSize: '15px' }}>{content}</div>,
okText: '确认',
cancelText: '取消',
okText: okText,
cancelText: cancelText,
onOk: onOk,
});
}


Loading…
Cancel
Save