feat: 添加删除全部modal的方法
This commit is contained in:
parent
b138b3f241
commit
e2cfc94482
|
@ -17,6 +17,7 @@ export enum ModelDeploymentStatus {
|
|||
Running = 'Running', // 运行中
|
||||
Stopped = 'Stopped', // 已停止
|
||||
Failed = 'Failed', // 失败
|
||||
Pending = 'Pending', // 挂起中
|
||||
}
|
||||
|
||||
export const modelDeploymentStatusOptions = [
|
||||
|
@ -25,4 +26,5 @@ export const modelDeploymentStatusOptions = [
|
|||
{ label: '运行中', value: ModelDeploymentStatus.Running },
|
||||
{ label: '已停止', value: ModelDeploymentStatus.Stopped },
|
||||
{ label: '失败', value: ModelDeploymentStatus.Failed },
|
||||
{ label: '挂起中', value: ModelDeploymentStatus.Pending },
|
||||
];
|
||||
|
|
|
@ -126,13 +126,3 @@ export const useResetFormOnCloseModal = (form: FormInstance, open: boolean) => {
|
|||
}
|
||||
}, [form, prevOpen, open]);
|
||||
};
|
||||
|
||||
export const useInputModel = <T>(initialValue: T) => {
|
||||
const [value, setValue] = useState<T>(initialValue);
|
||||
|
||||
const updateValue = useCallback((e: any) => {
|
||||
setValue(e.target?.value);
|
||||
}, []);
|
||||
|
||||
return [value, updateValue];
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@ import { to } from '@/utils/promise';
|
|||
import { type SelectProps } from 'antd';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
// 获取资源规格
|
||||
export function useComputingResource() {
|
||||
const [resourceStandardList, setResourceStandardList] = useState<ComputingResource[]>([]);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { getSessionStorageItem, removeSessionStorageItem } from '@/utils/sessionStorage';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
// 获取缓存数据
|
||||
export function useSessionStorage<T>(key: string, isObject: boolean, initialValue: T) {
|
||||
const [storage, setStorage] = useState<T>(initialValue);
|
||||
|
||||
|
|
|
@ -97,6 +97,11 @@ function AddExperimentModal({
|
|||
wrapperCol: { span: 20 },
|
||||
};
|
||||
|
||||
const paramLayout = {
|
||||
labelCol: { span: 8 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
|
||||
// 除了流水线选择发生变化
|
||||
const handleWorkflowChange = (id: string | number) => {
|
||||
const pipeline: Workflow | undefined = workflowList.find((v) => v.id === id);
|
||||
|
@ -187,7 +192,7 @@ function AddExperimentModal({
|
|||
fields.map(({ key, name, ...restField }) => (
|
||||
<Form.Item
|
||||
{...restField}
|
||||
{...layout}
|
||||
{...paramLayout}
|
||||
key={key}
|
||||
label={getParamType(globalParam[name])}
|
||||
name={[name, 'param_value']}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import SubAreaTitle from '@/components/SubAreaTitle';
|
||||
import { getComputingResourceReq } from '@/services/pipeline';
|
||||
import { useComputingResource } from '@/hooks/resource';
|
||||
import { PipelineNodeModelSerialize } from '@/types';
|
||||
import { to } from '@/utils/promise';
|
||||
import { Form, Input, Select, type FormProps } from 'antd';
|
||||
import { useEffect, useState } from 'react';
|
||||
import styles from './index.less';
|
||||
const { TextArea } = Input;
|
||||
|
||||
|
@ -13,24 +11,7 @@ type ExperimentParameterProps = {
|
|||
};
|
||||
|
||||
function ExperimentParameter({ form, nodeData }: ExperimentParameterProps) {
|
||||
const [resourceStandardList, setResourceStandardList] = useState([]); // 资源规模列表
|
||||
|
||||
useEffect(() => {
|
||||
getComputingResource();
|
||||
}, []);
|
||||
|
||||
// 获取资源规格列表数据
|
||||
const getComputingResource = async () => {
|
||||
const params = {
|
||||
page: 0,
|
||||
size: 1000,
|
||||
resource_type: '',
|
||||
};
|
||||
const [res] = await to(getComputingResourceReq(params));
|
||||
if (res && res.data && res.data.content) {
|
||||
setResourceStandardList(res.data.content);
|
||||
}
|
||||
};
|
||||
const [resourceStandardList] = useComputingResource(); // 资源规模
|
||||
|
||||
// 控制策略
|
||||
const controlStrategyList = Object.entries(nodeData.control_strategy ?? {}).map(
|
||||
|
|
|
@ -18,7 +18,7 @@ export enum ExperimentStatus {
|
|||
export const experimentStatusInfo: Record<ExperimentStatus, StatusInfo | undefined> = {
|
||||
Running: {
|
||||
label: '运行中',
|
||||
color: '#165bff',
|
||||
color: '#1664ff',
|
||||
icon: '/assets/images/running-icon.png',
|
||||
},
|
||||
Succeeded: {
|
||||
|
@ -53,7 +53,7 @@ export const experimentStatusInfo: Record<ExperimentStatus, StatusInfo | undefin
|
|||
},
|
||||
Omitted: {
|
||||
label: '未执行',
|
||||
color: '#8a8a8ae',
|
||||
color: '#8a8a8a',
|
||||
icon: '/assets/images/omitted-icon.png',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -174,13 +174,14 @@ function MirrorList() {
|
|||
title: '版本数据',
|
||||
dataIndex: 'version_count',
|
||||
key: 'version_count',
|
||||
width: 100,
|
||||
width: '15%',
|
||||
render: CommonTableCell(),
|
||||
},
|
||||
{
|
||||
title: '镜像描述',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
width: '35%',
|
||||
render: CommonTableCell(true),
|
||||
ellipsis: { showTitle: false },
|
||||
},
|
||||
|
@ -188,7 +189,7 @@ function MirrorList() {
|
|||
title: '创建时间',
|
||||
dataIndex: 'create_time',
|
||||
key: 'create_time',
|
||||
width: 200,
|
||||
width: '20%',
|
||||
render: DateTableCell,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @Author: 赵伟
|
||||
* @Date: 2024-04-18 18:35:41
|
||||
* @Description:
|
||||
* @Description: 镜像状态组件
|
||||
*/
|
||||
import { MirrorVersionStatus } from '@/enums';
|
||||
import styles from './index.less';
|
||||
|
@ -26,7 +26,7 @@ const statusInfo: Record<MirrorVersionStatus, MirrorVersionStatusInfo> = {
|
|||
},
|
||||
};
|
||||
|
||||
function MirrorStatusCell(status: MirrorVersionStatus) {
|
||||
function MirrorStatusCell(status?: MirrorVersionStatus | null) {
|
||||
if (status === null || status === undefined || !statusInfo[status]) {
|
||||
return <span>--</span>;
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ function ModelDeploymentInfo() {
|
|||
</Col>
|
||||
<Col span={10}>
|
||||
<div className={styles['model-deployment-info__basic__item']}>
|
||||
<div className={styles['label']}>资源规格</div>
|
||||
<div className={styles['label']}>资源规格:</div>
|
||||
<div className={styles['value']}>
|
||||
{modelDeployementInfo?.resource
|
||||
? getResourceDescription(modelDeployementInfo.resource)
|
||||
|
@ -174,7 +174,7 @@ function ModelDeploymentInfo() {
|
|||
</Col>
|
||||
</Row>
|
||||
<Row gutter={40}>
|
||||
<Col span={24}>
|
||||
<Col span={18}>
|
||||
<div className={styles['model-deployment-info__basic__item']}>
|
||||
<div className={styles['label']}>描 述:</div>
|
||||
<div className={styles['value']}>{modelDeployementInfo?.description ?? '--'}</div>
|
||||
|
|
|
@ -249,7 +249,8 @@ function ModelDeployment() {
|
|||
</Button>
|
||||
)}
|
||||
{(record.status === ModelDeploymentStatus.Running ||
|
||||
record.status === ModelDeploymentStatus.Init) && (
|
||||
record.status === ModelDeploymentStatus.Init ||
|
||||
record.status === ModelDeploymentStatus.Pending) && (
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
|
|
|
@ -6,10 +6,14 @@
|
|||
}
|
||||
|
||||
&--stopped {
|
||||
color: @warning-color;
|
||||
color: @abort-color;
|
||||
}
|
||||
|
||||
&--error {
|
||||
color: @error-color;
|
||||
}
|
||||
|
||||
&--pending {
|
||||
color: @warning-color;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,9 +28,13 @@ export const statusInfo: Record<ModelDeploymentStatus, ModelDeploymentStatusInfo
|
|||
classname: styles['model-deployment-status-cell--error'],
|
||||
text: '失败',
|
||||
},
|
||||
[ModelDeploymentStatus.Pending]: {
|
||||
classname: styles['model-deployment-status-cell--pending'],
|
||||
text: '挂起中',
|
||||
},
|
||||
};
|
||||
|
||||
function ModelDeploymentStatusCell(status: ModelDeploymentStatus | undefined) {
|
||||
function ModelDeploymentStatusCell(status?: ModelDeploymentStatus | null) {
|
||||
if (status === null || status === undefined || !statusInfo[status]) {
|
||||
return <span>--</span>;
|
||||
}
|
||||
|
|
|
@ -26,13 +26,7 @@ export type ModelDeploymentData = {
|
|||
|
||||
// 操作类型
|
||||
export enum ModelDeploymentOperationType {
|
||||
Create = 'create',
|
||||
Update = 'update',
|
||||
Restart = 'restart',
|
||||
Create = 'Create',
|
||||
Update = 'Update',
|
||||
Restart = 'Restart',
|
||||
}
|
||||
|
||||
// 状态
|
||||
export type ModelDeploymentStatusInfo = {
|
||||
text: string;
|
||||
classname: string;
|
||||
};
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import KFIcon from '@/components/KFIcon';
|
||||
import ParameterInput from '@/components/ParameterInput';
|
||||
import SubAreaTitle from '@/components/SubAreaTitle';
|
||||
import { getComputingResourceReq } from '@/services/pipeline';
|
||||
import { useComputingResource } from '@/hooks/resource';
|
||||
import { openAntdModal } from '@/utils/modal';
|
||||
import { to } from '@/utils/promise';
|
||||
import { Button, Drawer, Form, Input, Select } from 'antd';
|
||||
import { pick } from 'lodash';
|
||||
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
||||
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||
import PropsLabel from '../components/PropsLabel';
|
||||
import ResourceSelectorModal, { ResourceSelectorType } from '../components/ResourceSelectorModal';
|
||||
import ResourceSelectorModal, {
|
||||
ResourceSelectorType,
|
||||
selectorTypeConfig,
|
||||
} from '../components/ResourceSelectorModal';
|
||||
import styles from './props.less';
|
||||
import { canInput, createMenuItems } from './utils';
|
||||
const { TextArea } = Input;
|
||||
|
@ -19,26 +22,9 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
const [open, setOpen] = useState(false);
|
||||
const [selectedModel, setSelectedModel] = useState(undefined); // 选择的模型,为了再次打开时恢复原来的选择
|
||||
const [selectedDataset, setSelectedDataset] = useState(undefined); // 选择的数据集,为了再次打开时恢复原来的选择
|
||||
const [resourceStandardList, setResourceStandardList] = useState([]); // 资源规模列表
|
||||
const [resourceStandardList, filterResourceStandard] = useComputingResource(); // 资源规模
|
||||
const [menuItems, setMenuItems] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
getComputingResource();
|
||||
}, []);
|
||||
|
||||
// 获取资源规格列表数据
|
||||
const getComputingResource = async () => {
|
||||
const params = {
|
||||
page: 0,
|
||||
size: 1000,
|
||||
resource_type: '',
|
||||
};
|
||||
const [res] = await to(getComputingResourceReq(params));
|
||||
if (res && res.data && res.data.content) {
|
||||
setResourceStandardList(res.data.content);
|
||||
}
|
||||
};
|
||||
|
||||
const afterOpenChange = () => {
|
||||
if (!open) {
|
||||
console.log('zzzzz', form.getFieldsValue());
|
||||
|
@ -57,6 +43,7 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
const onClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
getFieldsValue: async () => {
|
||||
const [propsRes, propsError] = await to(form.validateFields());
|
||||
|
@ -155,18 +142,16 @@ const Props = forwardRef(({ onParentChange }, ref) => {
|
|||
// 获取选择数据集、模型后面按钮 icon
|
||||
const getSelectBtnIcon = (item) => {
|
||||
const type = item.item_type;
|
||||
let selectorType;
|
||||
if (type === 'dataset') {
|
||||
return <KFIcon type="icon-xuanzeshujuji" />;
|
||||
selectorType = ResourceSelectorType.Dataset;
|
||||
} else if (type === 'model') {
|
||||
return <KFIcon type="icon-xuanzemoxing" />;
|
||||
selectorType = ResourceSelectorType.Model;
|
||||
} else {
|
||||
return <KFIcon type="icon-xuanzejingxiang" />;
|
||||
selectorType = ResourceSelectorType.Mirror;
|
||||
}
|
||||
};
|
||||
|
||||
// 筛选资源规格
|
||||
const filterResourceStandard = (input, { computing_resource = '' }) => {
|
||||
return computing_resource.toLocaleLowerCase().includes(input.toLocaleLowerCase());
|
||||
return <KFIcon type={selectorTypeConfig[selectorType].buttonIcon} />;
|
||||
};
|
||||
|
||||
// 参数回填
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* @Date: 2024-03-25 13:52:54
|
||||
* @Description: 网络请求配置,详情请参考 https://umijs.org/docs/max/request
|
||||
*/
|
||||
import type { RequestConfig } from '@umijs/max';
|
||||
import type { AxiosRequestConfig, AxiosResponse, RequestConfig } from '@umijs/max';
|
||||
import { message } from 'antd';
|
||||
import { clearSessionToken, getAccessToken } from './access';
|
||||
import { setRemoteMenu } from './services/session';
|
||||
|
@ -16,8 +16,8 @@ import { gotoLoginPage } from './utils/ui';
|
|||
export const requestConfig: RequestConfig = {
|
||||
errorConfig: {},
|
||||
requestInterceptors: [
|
||||
(url: any, options: { headers: any }) => {
|
||||
const headers = options.headers ? options.headers : [];
|
||||
(url: string, options: AxiosRequestConfig) => {
|
||||
const headers = options.headers ?? {};
|
||||
const authHeader = headers['Authorization'];
|
||||
const isToken = headers['isToken'];
|
||||
if (!authHeader && isToken !== false) {
|
||||
|
@ -30,7 +30,7 @@ export const requestConfig: RequestConfig = {
|
|||
},
|
||||
],
|
||||
responseInterceptors: [
|
||||
(response: any) => {
|
||||
(response: AxiosResponse) => {
|
||||
const { status, data } = response || {};
|
||||
if (status >= 200 && status < 300) {
|
||||
if (data && (data instanceof Blob || data.code === 200)) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
@success-color: #1ace62;
|
||||
@error-color: #c73131;
|
||||
@warning-color: #f98e1b;
|
||||
@abort-color: #8a8a8a;
|
||||
|
||||
@border-color: rgba(22, 100, 255, 0.3);
|
||||
@border-color-secondary: rgba(22, 100, 255, 0.1);
|
||||
|
|
|
@ -29,7 +29,7 @@ export function parseJsonText(text?: string | null): any | null {
|
|||
}
|
||||
}
|
||||
|
||||
// Underscore-to-camelCase
|
||||
// underscore-to-camelCase
|
||||
export function underscoreToCamelCase(obj: Record<string, any>) {
|
||||
const newObj: Record<string, any> = {};
|
||||
for (const key in obj) {
|
||||
|
@ -47,6 +47,7 @@ export function underscoreToCamelCase(obj: Record<string, any>) {
|
|||
return newObj;
|
||||
}
|
||||
|
||||
// camelCase-to-underscore
|
||||
export function camelCaseToUnderscore(obj: Record<string, any>) {
|
||||
const newObj: Record<string, any> = {};
|
||||
for (const key in obj) {
|
||||
|
@ -61,3 +62,21 @@ export function camelCaseToUnderscore(obj: Record<string, any>) {
|
|||
}
|
||||
return newObj;
|
||||
}
|
||||
|
||||
// null 转 undefined
|
||||
export function nullToUndefined(obj: Record<string, any>) {
|
||||
const newObj: Record<string, any> = {};
|
||||
for (const key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
const value = obj[key];
|
||||
if (value === null) {
|
||||
newObj[key] = undefined;
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
newObj[key] = nullToUndefined(value);
|
||||
} else {
|
||||
newObj[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newObj;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import zhCN from 'antd/locale/zh_CN';
|
|||
import React, { useState } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
const destroyFns: (() => void)[] = [];
|
||||
|
||||
/**
|
||||
* Function to open an Ant Design modal.
|
||||
*
|
||||
|
@ -16,7 +18,6 @@ import { createRoot } from 'react-dom/client';
|
|||
* @param modalProps - The modal properties.
|
||||
* @return An object with a destroy method to close the modal.
|
||||
*/
|
||||
|
||||
export const openAntdModal = <T extends Omit<ModalProps, 'onOk'>>(
|
||||
modal: (props: T) => React.ReactNode,
|
||||
modalProps: T,
|
||||
|
@ -29,6 +30,11 @@ export const openAntdModal = <T extends Omit<ModalProps, 'onOk'>>(
|
|||
let timeoutId: ReturnType<typeof setTimeout>;
|
||||
|
||||
function destroy() {
|
||||
const index = destroyFns.indexOf(close);
|
||||
if (index !== -1) {
|
||||
destroyFns.splice(index, 1);
|
||||
}
|
||||
|
||||
root.unmount();
|
||||
}
|
||||
|
||||
|
@ -79,6 +85,8 @@ export const openAntdModal = <T extends Omit<ModalProps, 'onOk'>>(
|
|||
|
||||
render({ ...modalProps, open: true });
|
||||
|
||||
destroyFns.push(close);
|
||||
|
||||
return {
|
||||
close,
|
||||
};
|
||||
|
@ -88,19 +96,23 @@ export const openAntdModal = <T extends Omit<ModalProps, 'onOk'>>(
|
|||
* Generates a custom hook for managing an Ant Design modal.
|
||||
*
|
||||
* @param modal - The function that renders the modal content.
|
||||
* @param key - The key for the modal.
|
||||
* @param defaultProps - The default modal properties.
|
||||
* @return The modal component, open function, and close function.
|
||||
*/
|
||||
export const useAntdModal = <T extends ModalProps>(
|
||||
|
||||
export const useModal = <T extends ModalProps>(
|
||||
modal: (props: T) => React.ReactNode,
|
||||
key: React.Key,
|
||||
defaultProps?: T,
|
||||
) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [props, setProps] = useState<T>({} as T);
|
||||
const [props, setProps] = useState<T>(defaultProps || ({} as T));
|
||||
const CustomModel = modal;
|
||||
|
||||
const open = (props: T) => {
|
||||
setProps(props);
|
||||
setProps((prev) => ({
|
||||
...prev,
|
||||
...props,
|
||||
}));
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
|
@ -108,5 +120,14 @@ export const useAntdModal = <T extends ModalProps>(
|
|||
setVisible(false);
|
||||
};
|
||||
|
||||
return [<CustomModel key={key} open={visible} {...props} />, open, close] as const;
|
||||
return [<CustomModel key="modal" open={visible} {...props} />, open, close] as const;
|
||||
};
|
||||
|
||||
// 关闭没有手动关闭的 Modal
|
||||
export const closeAllModals = () => {
|
||||
let close = destroyFns.pop();
|
||||
while (close) {
|
||||
close();
|
||||
close = destroyFns.pop();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@ import { PageEnum } from '@/enums/pagesEnums';
|
|||
import themes from '@/styles/theme.less';
|
||||
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) {
|
||||
|
@ -58,6 +59,7 @@ export const gotoLoginPage = (toHome: boolean = true) => {
|
|||
console.log('pathname', pathname);
|
||||
console.log('search', search);
|
||||
if (window.location.pathname !== PageEnum.LOGIN) {
|
||||
closeAllModals();
|
||||
history.replace({
|
||||
pathname: PageEnum.LOGIN,
|
||||
search: newSearch,
|
||||
|
|
Loading…
Reference in New Issue