Browse Source

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

pull/52/head
西大锐 1 year ago
parent
commit
844d66410a
32 changed files with 133 additions and 108 deletions
  1. +2
    -0
      react-ui/src/enums/index.ts
  2. +0
    -10
      react-ui/src/hooks/index.ts
  3. +1
    -0
      react-ui/src/hooks/resource.ts
  4. +1
    -0
      react-ui/src/hooks/sessionStorage.ts
  5. +2
    -1
      react-ui/src/pages/Dataset/components/AddDatasetModal/index.tsx
  6. +3
    -1
      react-ui/src/pages/Dataset/components/AddModelModal/index.tsx
  7. +2
    -1
      react-ui/src/pages/Dataset/components/AddVersionModal/index.tsx
  8. +2
    -1
      react-ui/src/pages/Dataset/components/ResourceList/index.tsx
  9. +2
    -1
      react-ui/src/pages/Dataset/intro.jsx
  10. +6
    -1
      react-ui/src/pages/Experiment/components/AddExperimentModal/index.tsx
  11. +2
    -21
      react-ui/src/pages/Experiment/components/ExperimentParameter/index.tsx
  12. +2
    -1
      react-ui/src/pages/Experiment/index.jsx
  13. +2
    -2
      react-ui/src/pages/Experiment/status.ts
  14. +2
    -1
      react-ui/src/pages/Mirror/Create/index.tsx
  15. +3
    -1
      react-ui/src/pages/Mirror/Info/index.tsx
  16. +5
    -3
      react-ui/src/pages/Mirror/List/index.tsx
  17. +2
    -2
      react-ui/src/pages/Mirror/components/MirrorStatusCell/index.tsx
  18. +2
    -1
      react-ui/src/pages/Model/intro.jsx
  19. +2
    -2
      react-ui/src/pages/ModelDeployment/Info/index.tsx
  20. +2
    -1
      react-ui/src/pages/ModelDeployment/List/index.tsx
  21. +5
    -1
      react-ui/src/pages/ModelDeployment/components/ModelDeployStatusCell/index.less
  22. +5
    -1
      react-ui/src/pages/ModelDeployment/components/ModelDeployStatusCell/index.tsx
  23. +3
    -9
      react-ui/src/pages/ModelDeployment/types.ts
  24. +2
    -2
      react-ui/src/pages/Monitor/Job/edit.tsx
  25. +2
    -2
      react-ui/src/pages/Pipeline/editPipeline/index.jsx
  26. +13
    -28
      react-ui/src/pages/Pipeline/editPipeline/props.jsx
  27. +3
    -2
      react-ui/src/pages/Pipeline/index.jsx
  28. +4
    -4
      react-ui/src/requestConfig.ts
  29. +1
    -0
      react-ui/src/styles/theme.less
  30. +20
    -1
      react-ui/src/utils/index.ts
  31. +28
    -7
      react-ui/src/utils/modal.tsx
  32. +2
    -0
      react-ui/src/utils/ui.tsx

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

@@ -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 },
];

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

@@ -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];
};

+ 1
- 0
react-ui/src/hooks/resource.ts View File

@@ -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
- 0
react-ui/src/hooks/sessionStorage.ts View File

@@ -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);



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

@@ -7,6 +7,7 @@ import { getDictSelectOption } from '@/services/system/dict';
import { to } from '@/utils/promise';
import { getFileListFromEvent, validateUploadFiles } from '@/utils/ui';
import {
App,
Button,
Form,
Input,
@@ -14,7 +15,6 @@ import {
Select,
Upload,
UploadFile,
message,
type ModalProps,
type UploadProps,
} from 'antd';
@@ -32,6 +32,7 @@ interface AddDatasetModalProps extends Omit<ModalProps, 'onOk'> {
function AddDatasetModal({ typeList, tagList, onOk, ...rest }: AddDatasetModalProps) {
const [uuid] = useState(Date.now());
const [clusterOptions, setClusterOptions] = useState<DictValueEnumObj[]>([]);
const { message } = App.useApp();

useEffect(() => {
getClusterOptions();


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

@@ -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,6 +28,8 @@ interface AddModelModalProps extends Omit<ModalProps, 'onOk'> {

function AddModelModal({ typeList, tagList, onOk, ...rest }: AddModelModalProps) {
const [uuid] = useState(Date.now());
const { message } = App.useApp();

// 上传组件参数
const uploadProps: UploadProps = {
action: '/api/mmp/models/upload',


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

@@ -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,6 +33,7 @@ function AddVersionModal({
...rest
}: AddVersionModalProps) {
const [uuid] = useState(Date.now());
const { message } = App.useApp();

// 上传组件参数
const uploadProps: UploadProps = {


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

@@ -5,7 +5,7 @@ import { openAntdModal } from '@/utils/modal';
import { to } from '@/utils/promise';
import { modalConfirm } from '@/utils/ui';
import { useNavigate } from '@umijs/max';
import { Button, Input, Pagination, PaginationProps, message } from 'antd';
import { App, Button, Input, Pagination, PaginationProps } from 'antd';
import { Ref, forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { CategoryData, ResourceData, ResourceType, resourceConfig } from '../../types';
import AddDatasetModal from '../AddDatasetModal';
@@ -53,6 +53,7 @@ function ResourceList(
);
const [searchText, setSearchText] = useState(initialSearchText);
const [inputText, setInputText] = useState(initialSearchText);
const { message } = App.useApp();

useEffect(() => {
getDataList();


+ 2
- 1
react-ui/src/pages/Dataset/intro.jsx View File

@@ -11,7 +11,7 @@ import { downLoadZip } from '@/utils/downloadfile';
import { openAntdModal } from '@/utils/modal';
import { modalConfirm } from '@/utils/ui';
import { useParams, useSearchParams } from '@umijs/max';
import { Button, Input, Select, Table, Tabs, message } from 'antd';
import { App, Button, Input, Select, Table, Tabs } from 'antd';
import { useEffect, useRef, useState } from 'react';
import AddVersionModal from './components/AddVersionModal';
import Styles from './intro.less';
@@ -19,6 +19,7 @@ const { Search } = Input;
const { TabPane } = Tabs;

const Dataset = () => {
const { message } = App.useApp();
const [formList, setFormList] = useState([]);
const [datasetDetailObj, setDatasetDetailObj] = useState({});
const [version, setVersion] = useState(null);


+ 6
- 1
react-ui/src/pages/Experiment/components/AddExperimentModal/index.tsx View File

@@ -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']}


+ 2
- 21
react-ui/src/pages/Experiment/components/ExperimentParameter/index.tsx View File

@@ -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(


+ 2
- 1
react-ui/src/pages/Experiment/index.jsx View File

@@ -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 { Button, ConfigProvider, Space, Table, message } from 'antd';
import { App, Button, ConfigProvider, Space, Table } from 'antd';
import classNames from 'classnames';
import { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
@@ -47,6 +47,7 @@ function Experiment() {
const [isAdd, setIsAdd] = useState(true);
const [isModalOpen, setIsModalOpen] = useState(false);
const [addFormData, setAddFormData] = useState({});
const { message } = App.useApp();

useEffect(() => {
getList();


+ 2
- 2
react-ui/src/pages/Experiment/status.ts View File

@@ -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',
},
};

+ 2
- 1
react-ui/src/pages/Mirror/Create/index.tsx View File

@@ -18,7 +18,7 @@ import {
} from '@/utils/sessionStorage';
import { getFileListFromEvent, validateUploadFiles } from '@/utils/ui';
import { useNavigate } from '@umijs/max';
import { Button, Col, Form, Input, Row, Upload, UploadFile, message, type UploadProps } from 'antd';
import { App, Button, Col, Form, Input, Row, Upload, UploadFile, type UploadProps } from 'antd';
import { omit } from 'lodash';
import { useEffect, useState } from 'react';
import styles from './index.less';
@@ -49,6 +49,7 @@ function MirrorCreate() {
const navgite = useNavigate();
const [form] = Form.useForm();
const [nameDisabled, setNameDisabled] = useState(false);
const { message } = App.useApp();

const uploadProps: UploadProps = {
action: '/api/mmp/image/upload',


+ 3
- 1
react-ui/src/pages/Mirror/Info/index.tsx View File

@@ -68,11 +68,13 @@ function MirrorInfo() {
pageSize: 10,
},
);
const isPublic = searchParams.get('isPublic') === 'true';
const { message } = App.useApp();
const isPublic = searchParams.get('isPublic') === 'true';

useEffect(() => {
getMirrorInfo();
}, []);

useEffect(() => {
getMirrorVersionList();
}, [pagination]);


+ 5
- 3
react-ui/src/pages/Mirror/List/index.tsx View File

@@ -15,12 +15,12 @@ import { mirrorNameKey, setSessionStorageItem } from '@/utils/sessionStorage';
import { modalConfirm } from '@/utils/ui';
import { useNavigate } from '@umijs/max';
import {
App,
Button,
ConfigProvider,
Input,
Table,
Tabs,
message,
type TablePaginationConfig,
type TableProps,
type TabsProps,
@@ -64,6 +64,7 @@ function MirrorList() {
pageSize: 10,
},
);
const { message } = App.useApp();

useEffect(() => {
getMirrorList();
@@ -174,13 +175,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 +190,7 @@ function MirrorList() {
title: '创建时间',
dataIndex: 'create_time',
key: 'create_time',
width: 200,
width: '20%',
render: DateTableCell,
},
{


+ 2
- 2
react-ui/src/pages/Mirror/components/MirrorStatusCell/index.tsx View File

@@ -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>;
}


+ 2
- 1
react-ui/src/pages/Model/intro.jsx View File

@@ -12,7 +12,7 @@ import { downLoadZip } from '@/utils/downloadfile';
import { openAntdModal } from '@/utils/modal';
import { modalConfirm } from '@/utils/ui';
import { useParams, useSearchParams } from '@umijs/max';
import { Button, Input, Select, Table, Tabs, message } from 'antd';
import { App, Button, Input, Select, Table, Tabs } from 'antd';
import { useEffect, useRef, useState } from 'react';
import Styles from './intro.less';
const { Search } = Input;
@@ -26,6 +26,7 @@ const Dataset = () => {
const locationParams = useParams(); //新版本获取路由参数接口
const [searchParams] = useSearchParams();
const [wordList, setWordList] = useState([]);
const { message } = App.useApp();
const isPublic = searchParams.get('isPublic') === 'true';

const getModelByDetail = () => {


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

@@ -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>


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

@@ -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"


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

@@ -6,10 +6,14 @@
}

&--stopped {
color: @warning-color;
color: @abort-color;
}

&--error {
color: @error-color;
}

&--pending {
color: @warning-color;
}
}

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

@@ -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>;
}


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

@@ -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;
};

+ 2
- 2
react-ui/src/pages/Monitor/Job/edit.tsx View File

@@ -1,4 +1,5 @@
import { DictOptionType, DictValueEnumObj } from '@/components/DictTag';
import KFModal from '@/components/KFModal';
import {
ProForm,
ProFormCaptcha,
@@ -9,9 +10,8 @@ import {
ProFormTextArea,
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import { Form } from 'antd';
import React, { useEffect } from 'react';
import KFModal from '@/components/KFModal';
/**
* 定时任务调度 Edit Form
*


+ 2
- 2
react-ui/src/pages/Pipeline/editPipeline/index.jsx View File

@@ -3,7 +3,7 @@ import { useStateRef, useVisible } from '@/hooks';
import { getWorkflowById, saveWorkflow } from '@/services/pipeline/index.js';
import { to } from '@/utils/promise';
import G6 from '@antv/g6';
import { Button, message } from 'antd';
import { App, Button } from 'antd';
import { useEffect, useRef } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { s8 } from '../../../utils';
@@ -24,7 +24,7 @@ const EditPipeline = () => {
const propsRef = useRef();
const [paramsDrawerOpen, openParamsDrawer, closeParamsDrawer] = useVisible(false);
const [globalParam, setGlobalParam, globalParamRef] = useStateRef([]);
const { message } = App.useApp();
let sourceAnchorIdx, targetAnchorIdx;

const onDragEnd = (val) => {


+ 13
- 28
react-ui/src/pages/Pipeline/editPipeline/props.jsx View File

@@ -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
- 2
react-ui/src/pages/Pipeline/index.jsx View File

@@ -12,7 +12,7 @@ import {
} from '@/services/pipeline/index.js';
import themes from '@/styles/theme.less';
import { modalConfirm } from '@/utils/ui';
import { Button, ConfigProvider, Form, Input, Space, Table, message } from 'antd';
import { App, Button, ConfigProvider, Form, Input, Space, Table } from 'antd';
import classNames from 'classnames';
import { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
@@ -28,6 +28,7 @@ const Pipeline = () => {
const [pipeList, setPipeList] = useState([]);
const [total, setTotal] = useState(0);
const [isModalOpen, setIsModalOpen] = useState(false);
const { message } = App.useApp();
const editTable = (e, record) => {
e.stopPropagation();
getWorkflowById(record.id).then((ret) => {
@@ -66,7 +67,7 @@ const Pipeline = () => {
} else {
addWorkflow(values).then((ret) => {
console.log(ret);
if (ret.code == 200) {
if (ret.code === 200) {
navgite({ pathname: `/pipeline/template/${ret.data.id}/${ret.data.name}` });
}
});


+ 4
- 4
react-ui/src/requestConfig.ts View File

@@ -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)) {


+ 1
- 0
react-ui/src/styles/theme.less View File

@@ -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);


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

@@ -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;
}

+ 28
- 7
react-ui/src/utils/modal.tsx View File

@@ -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();
}
};

+ 2
- 0
react-ui/src/utils/ui.tsx View File

@@ -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…
Cancel
Save