Browse Source

Merge pull request '合并dev' (#127) from dev into master

dev-lhz
cp3hnu 1 year ago
parent
commit
0044971a74
26 changed files with 596 additions and 68 deletions
  1. +10
    -0
      react-ui/config/routes.ts
  2. +2
    -2
      react-ui/src/pages/CodeConfig/List/index.tsx
  3. +38
    -12
      react-ui/src/pages/CodeConfig/components/AddCodeConfigModal/index.tsx
  4. +8
    -1
      react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.less
  5. +33
    -6
      react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.tsx
  6. +61
    -0
      react-ui/src/pages/Dataset/components/ResourceItem/index.less
  7. +54
    -0
      react-ui/src/pages/Dataset/components/ResourceItem/index.tsx
  8. +1
    -1
      react-ui/src/pages/Monitor/JobLog/detail.tsx
  9. +4
    -1
      react-ui/src/pages/Pipeline/Info/utils.tsx
  10. +68
    -0
      react-ui/src/pages/Pipeline/components/CodeConfigItem/index.less
  11. +39
    -0
      react-ui/src/pages/Pipeline/components/CodeConfigItem/index.tsx
  12. +29
    -0
      react-ui/src/pages/Pipeline/components/CodeSelectorModal/index.less
  13. +114
    -0
      react-ui/src/pages/Pipeline/components/CodeSelectorModal/index.tsx
  14. +50
    -6
      react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx
  15. +10
    -3
      react-ui/src/pages/System/Config/edit.tsx
  16. +1
    -1
      react-ui/src/pages/System/Config/index.tsx
  17. +12
    -7
      react-ui/src/pages/System/DictData/edit.tsx
  18. +15
    -3
      react-ui/src/pages/System/Logininfor/edit.tsx
  19. +10
    -3
      react-ui/src/pages/System/Notice/edit.tsx
  20. +1
    -1
      react-ui/src/pages/System/Operlog/detail.tsx
  21. +11
    -11
      react-ui/src/pages/System/Operlog/index.tsx
  22. +9
    -1
      react-ui/src/pages/System/Role/components/DataScope.tsx
  23. +5
    -4
      react-ui/src/pages/System/User/edit.tsx
  24. +3
    -4
      react-ui/src/pages/User/Login/index.tsx
  25. +1
    -1
      react-ui/src/services/session.ts
  26. +7
    -0
      react-ui/src/utils/menuRender.tsx

+ 10
- 0
react-ui/config/routes.ts View File

@@ -360,6 +360,16 @@ export default [
path: 'role-auth/user/:id', path: 'role-auth/user/:id',
component: './System/Role/authUser', component: './System/Role/authUser',
}, },
{
name: '日志',
path: 'log',
routes: [
{
path: '',
redirect: '/system/log/operlog',
},
],
},
], ],
}, },
{ {


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

@@ -84,7 +84,7 @@ function CodeConfigList() {
}; };


// 修改 // 修改
const handleClick = (record: CodeConfigData) => {
const handleEdit = (record: CodeConfigData) => {
const { close } = openAntdModal(AddCodeConfigModal, { const { close } = openAntdModal(AddCodeConfigModal, {
opType: OperationType.Update, opType: OperationType.Update,
codeConfigData: record, codeConfigData: record,
@@ -147,7 +147,7 @@ function CodeConfigList() {
item={item} item={item}
key={item.id} key={item.id}
onRemove={handleRemove} onRemove={handleRemove}
onClick={handleClick}
onEdit={handleEdit}
/> />
))} ))}
</div> </div>


+ 38
- 12
react-ui/src/pages/CodeConfig/components/AddCodeConfigModal/index.tsx View File

@@ -3,8 +3,9 @@ import { AvailableRange } from '@/enums';
import { type CodeConfigData } from '@/pages/CodeConfig/List'; import { type CodeConfigData } from '@/pages/CodeConfig/List';
import { addCodeConfigReq, updateCodeConfigReq } from '@/services/codeConfig'; import { addCodeConfigReq, updateCodeConfigReq } from '@/services/codeConfig';
import { to } from '@/utils/promise'; import { to } from '@/utils/promise';
import { Form, Input, Radio, message, type ModalProps } from 'antd';
import { Form, Input, Radio, message, type FormRule, type ModalProps } from 'antd';
import { omit } from 'lodash'; import { omit } from 'lodash';
import { useMemo } from 'react';


export enum VerifyMode { export enum VerifyMode {
Password = 0, // 用户名密码 Password = 0, // 用户名密码
@@ -25,7 +26,32 @@ interface AddCodeConfigModalProps extends Omit<ModalProps, 'onOk'> {
} }


function AddCodeConfigModal({ opType, codeConfigData, onOk, ...rest }: AddCodeConfigModalProps) { function AddCodeConfigModal({ opType, codeConfigData, onOk, ...rest }: AddCodeConfigModalProps) {
// 上传请求
const [form] = Form.useForm();
const isPublic = Form.useWatch('code_repo_vis', form) === AvailableRange.Public;

const urlExample = useMemo(
() =>
isPublic
? 'https://gitlink.org.cn/ci4s/ci4sManagement-cloud.git'
: 'git@code.gitlink.org.cn:ci4s/ci4sManagement-cloud.git',
[isPublic],
);

// /^(git@[\w.-]+:[\w./-]+\.git)$/
const urlRules: FormRule[] = useMemo(
() =>
isPublic
? [
{
type: 'url',
message: '请输入正确的 Git 地址',
},
]
: ([] as FormRule[]),
[isPublic],
);

// 创建
const createCodeConfig = async (formData: FormData) => { const createCodeConfig = async (formData: FormData) => {
const params: FormData & { id?: number } = { const params: FormData & { id?: number } = {
...formData, ...formData,
@@ -78,14 +104,12 @@ function AddCodeConfigModal({ opType, codeConfigData, onOk, ...rest }: AddCodeCo
> >
<Form <Form
name="form" name="form"
form={form}
layout="vertical" layout="vertical"
onFinish={onFinish} onFinish={onFinish}
initialValues={initialValues} initialValues={initialValues}
autoComplete="off" autoComplete="off"
> >
{/* 禁止 Chrome 自动填充 */}
{/* <Input type="text" style={{ display: 'none' }} />
<Input type="password" style={{ display: 'none' }} /> */}
<Form.Item <Form.Item
label="代码仓库名称" label="代码仓库名称"
name="code_repo_name" name="code_repo_name"
@@ -122,13 +146,15 @@ function AddCodeConfigModal({ opType, codeConfigData, onOk, ...rest }: AddCodeCo
required: true, required: true,
message: '请输入 Git 地址', message: '请输入 Git 地址',
}, },
{
type: 'url',
message: '请输入正确的 Git 地址',
},
...urlRules,
]} ]}
> >
<Input placeholder="请输入 Git 地址" showCount allowClear maxLength={256} />
<Input
placeholder={`请输入 Git 地址,如: ${urlExample}`}
showCount
allowClear
maxLength={256}
/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="代码分支/Tag" label="代码分支/Tag"
@@ -224,8 +250,8 @@ function AddCodeConfigModal({ opType, codeConfigData, onOk, ...rest }: AddCodeCo
<Input.TextArea <Input.TextArea
placeholder="请输入 SSH Key" placeholder="请输入 SSH Key"
showCount showCount
maxLength={1024}
autoSize={{ minRows: 3, maxRows: 6 }}
maxLength={4096}
autoSize={{ minRows: 4, maxRows: 8 }}
allowClear allowClear
/> />
</Form.Item> </Form.Item>


+ 8
- 1
react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.less View File

@@ -22,8 +22,15 @@
font-size: 16px; font-size: 16px;
} }


&__tag {
padding: 4px;
color: @primary-color;
font-size: 12px;
background-color: .addAlpha(@primary-color, 0.1) [];
border-radius: 4px;
}

&__url { &__url {
margin-bottom: 10px;
color: @text-color-secondary; color: @text-color-secondary;
font-size: 14px; font-size: 14px;
} }


+ 33
- 6
react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.tsx View File

@@ -1,6 +1,7 @@
import clock from '@/assets/img/clock.png'; import clock from '@/assets/img/clock.png';
import creatByImg from '@/assets/img/creatBy.png'; import creatByImg from '@/assets/img/creatBy.png';
import KFIcon from '@/components/KFIcon'; import KFIcon from '@/components/KFIcon';
import { AvailableRange } from '@/enums';
import { type CodeConfigData } from '@/pages/CodeConfig/List'; import { type CodeConfigData } from '@/pages/CodeConfig/List';
import { formatDate } from '@/utils/date'; import { formatDate } from '@/utils/date';
import { Button, Flex, Typography } from 'antd'; import { Button, Flex, Typography } from 'antd';
@@ -8,13 +9,14 @@ import styles from './index.less';


type CodeConfigItemProps = { type CodeConfigItemProps = {
item: CodeConfigData; item: CodeConfigData;
onClick: (item: CodeConfigData) => void;
onRemove: (item: CodeConfigData) => void;
onClick?: (item: CodeConfigData) => void;
onEdit?: (item: CodeConfigData) => void;
onRemove?: (item: CodeConfigData) => void;
}; };


function CodeConfigItem({ item, onClick, onRemove }: CodeConfigItemProps) {
function CodeConfigItem({ item, onClick, onEdit, onRemove }: CodeConfigItemProps) {
return ( return (
<div className={styles['code-config-item']} onClick={() => onClick(item)}>
<div className={styles['code-config-item']} onClick={() => onClick?.(item)}>
<Flex justify="space-between" align="center" style={{ marginBottom: '20px', height: '32px' }}> <Flex justify="space-between" align="center" style={{ marginBottom: '20px', height: '32px' }}>
<Typography.Paragraph <Typography.Paragraph
className={styles['code-config-item__name']} className={styles['code-config-item__name']}
@@ -22,18 +24,43 @@ function CodeConfigItem({ item, onClick, onRemove }: CodeConfigItemProps) {
> >
{item.code_repo_name} {item.code_repo_name}
</Typography.Paragraph> </Typography.Paragraph>
<div className={styles['code-config-item__tag']}>
{item.code_repo_vis === AvailableRange.Public ? '公开' : '私有'}
</div>

<Button
type="text"
shape="circle"
style={{ marginLeft: 'auto', marginRight: '4px' }}
onClick={(e) => {
e.stopPropagation();
onEdit?.(item);
}}
>
<KFIcon type="icon-bianji" font={17} />
</Button>
<Button <Button
type="text" type="text"
shape="circle" shape="circle"
style={{ marginRight: '-4px' }}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
onRemove(item);
onRemove?.(item);
}} }}
> >
<KFIcon type="icon-shanchu" font={17} /> <KFIcon type="icon-shanchu" font={17} />
</Button> </Button>
</Flex> </Flex>
<div className={styles['code-config-item__description']}>{item.git_url}</div>
<Typography.Paragraph
className={styles['code-config-item__url']}
ellipsis={{ tooltip: item.git_url }}
style={{ marginBottom: '8px' }}
>
{item.git_url}
</Typography.Paragraph>
<div className={styles['code-config-item__url']} style={{ marginBottom: '20px' }}>
{item.git_branch}
</div>
<Flex justify="space-between"> <Flex justify="space-between">
<div className={styles['code-config-item__time']}> <div className={styles['code-config-item__time']}>
<img style={{ width: '17px', marginRight: '6px' }} src={creatByImg} alt="" /> <img style={{ width: '17px', marginRight: '6px' }} src={creatByImg} alt="" />


+ 61
- 0
react-ui/src/pages/Dataset/components/ResourceItem/index.less View File

@@ -0,0 +1,61 @@
.resource-item {
position: relative;
width: calc(25% - 15px);
padding: 20px;
background: white;
border: 1px solid #eaeaea;
border-radius: 4px;
cursor: pointer;

@media screen and (max-width: 1860px) {
& {
width: calc(33.33% - 13.33px);
}
}

&__name {
position: relative;
display: inline-block;
height: 24px;
margin: 0 10px 0 0 !important;
color: @text-color;
font-size: 16px;
}

&__description {
height: 44px;
margin-bottom: 20px;
color: @text-color-secondary;
font-size: 14px;
.multiLine(2);
}
&__time {
display: flex;
flex: 0 1 content;
align-items: center;
width: 100%;
color: #808080;
font-size: 13px;
}

&:hover {
border-color: @primary-color;
box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1);

.resource-item__name {
color: @primary-color;
}
}
}

.resource-item__name {
&::after {
position: absolute;
top: 14px;
left: 0;
width: 100%;
height: 6px;
background: linear-gradient(to right, rgba(22, 100, 255, 0.3) 0, rgba(22, 100, 255, 0) 100%);
content: '';
}
}

+ 54
- 0
react-ui/src/pages/Dataset/components/ResourceItem/index.tsx View File

@@ -0,0 +1,54 @@
import clock from '@/assets/img/clock.png';
import creatByImg from '@/assets/img/creatBy.png';
import KFIcon from '@/components/KFIcon';
import { formatDate } from '@/utils/date';
import { Button, Flex, Typography } from 'antd';
import { ResourceData } from '../../config';
import styles from './index.less';

type ResourceItemProps = {
item: ResourceData;
isPublic: boolean;
onRemove: (item: ResourceData) => void;
onClick: (item: ResourceData) => void;
};

function ResourceItem({ item, isPublic, onClick, onRemove }: ResourceItemProps) {
return (
<div className={styles['resource-item']} onClick={() => onClick(item)}>
<Flex justify="space-between" align="center" style={{ marginBottom: '20px', height: '32px' }}>
<Typography.Paragraph
className={styles['resource-item__name']}
ellipsis={{ tooltip: item.name }}
>
{item.name}
</Typography.Paragraph>
{!isPublic && (
<Button
type="text"
shape="circle"
onClick={(e) => {
e.stopPropagation();
onRemove(item);
}}
>
<KFIcon type="icon-shanchu" font={17} />
</Button>
)}
</Flex>
<div className={styles['resource-item__description']}>{item.description}</div>
<Flex justify="space-between">
<div className={styles['resource-item__time']}>
<img style={{ width: '17px', marginRight: '6px' }} src={creatByImg} alt="" />
<span>{item.create_by}</span>
</div>
<div className={styles['resource-item__time']}>
<img style={{ width: '12px', marginRight: '5px' }} src={clock} alt="" />
<span>最近更新: {formatDate(item.update_time, 'YYYY-MM-DD')}</span>
</div>
</Flex>
</div>
);
}

export default ResourceItem;

+ 1
- 1
react-ui/src/pages/Monitor/JobLog/detail.tsx View File

@@ -28,7 +28,7 @@ const JobLogDetailForm: React.FC<JobLogFormProps> = (props) => {


return ( return (
<KFModal <KFModal
width={640}
width={680}
title={intl.formatMessage({ title={intl.formatMessage({
id: 'monitor.job.log.title', id: 'monitor.job.log.title',
defaultMessage: '定时任务调度日志', defaultMessage: '定时任务调度日志',


+ 4
- 1
react-ui/src/pages/Pipeline/Info/utils.tsx View File

@@ -86,6 +86,9 @@ export function canInput(parameter: PipelineNodeModelParameter) {
const { type, item_type } = parameter; const { type, item_type } = parameter;
return !( return !(
type === 'ref' && type === 'ref' &&
(item_type === 'dataset' || item_type === 'model' || item_type === 'image')
(item_type === 'dataset' ||
item_type === 'model' ||
item_type === 'image' ||
item_type === 'code')
); );
} }

+ 68
- 0
react-ui/src/pages/Pipeline/components/CodeConfigItem/index.less View File

@@ -0,0 +1,68 @@
.code-config-item {
position: relative;
padding: 20px;
background: white;
border: 1px solid #eaeaea;
border-radius: 4px;
cursor: pointer;

&__name {
position: relative;
display: inline-block;
height: 24px;
margin: 0 10px 0 0 !important;
color: @text-color;
font-size: 16px;
}

&__tag {
padding: 4px;
color: @primary-color;
font-size: 12px;
background-color: .addAlpha(@primary-color, 0.1) [];
border-radius: 4px;
}

&__url {
color: @text-color-secondary;
font-size: 14px;
}

&__description {
height: 44px;
margin-bottom: 20px;
color: @text-color-secondary;
font-size: 14px;
.multiLine(2);
}

&__time {
display: flex;
flex: 0 1 content;
align-items: center;
width: 100%;
color: #808080;
font-size: 13px;
}

&:hover {
border-color: @primary-color;
box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1);

.resource-item__name {
color: @primary-color;
}
}
}

.resource-item__name {
&::after {
position: absolute;
top: 14px;
left: 0;
width: 100%;
height: 6px;
background: linear-gradient(to right, rgba(22, 100, 255, 0.3) 0, rgba(22, 100, 255, 0) 100%);
content: '';
}
}

+ 39
- 0
react-ui/src/pages/Pipeline/components/CodeConfigItem/index.tsx View File

@@ -0,0 +1,39 @@
import { AvailableRange } from '@/enums';
import { type CodeConfigData } from '@/pages/CodeConfig/List';
import { Flex, Typography } from 'antd';
import styles from './index.less';

type CodeConfigItemProps = {
item: CodeConfigData;
onClick?: (item: CodeConfigData) => void;
};

function CodeConfigItem({ item, onClick }: CodeConfigItemProps) {
return (
<div className={styles['code-config-item']} onClick={() => onClick?.(item)}>
<Flex justify="space-between" align="center" style={{ marginBottom: '20px', height: '32px' }}>
<Typography.Paragraph
className={styles['code-config-item__name']}
ellipsis={{ tooltip: item.code_repo_name }}
>
{item.code_repo_name}
</Typography.Paragraph>
<div className={styles['code-config-item__tag']}>
{item.code_repo_vis === AvailableRange.Public ? '公开' : '私有'}
</div>
</Flex>
<Typography.Paragraph
className={styles['code-config-item__url']}
ellipsis={{ tooltip: item.git_url }}
style={{ marginBottom: '8px' }}
>
{item.git_url}
</Typography.Paragraph>
<div className={styles['code-config-item__url']} style={{ marginBottom: '20px' }}>
{item.git_branch}
</div>
</div>
);
}

export default CodeConfigItem;

+ 29
- 0
react-ui/src/pages/Pipeline/components/CodeSelectorModal/index.less View File

@@ -0,0 +1,29 @@
.code-selector {
width: 100%;
height: 100%;

:global {
.ant-input-affix-wrapper .ant-input-prefix {
margin-inline-end: 12px;
}

.ant-pagination {
text-align: right;
}

.ant-input-group-addon {
display: none;
}
}

&__content {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 20px;
width: 100%;
margin-top: 30px;
margin-bottom: 30px;
overflow-x: hidden;
overflow-y: auto;
}
}

+ 114
- 0
react-ui/src/pages/Pipeline/components/CodeSelectorModal/index.tsx View File

@@ -0,0 +1,114 @@
/*
* @Author: 赵伟
* @Date: 2024-04-11 16:31:18
* @Description: 选择代码
*/

import KFModal from '@/components/KFModal';
import { type CodeConfigData } from '@/pages/CodeConfig/List';
import { getCodeConfigListReq } from '@/services/codeConfig';
import { to } from '@/utils/promise';
import type { ModalProps, PaginationProps } from 'antd';
import { Empty, Input, Pagination } from 'antd';
import { useEffect, useState } from 'react';
import CodeConfigItem from '../CodeConfigItem';
import styles from './index.less';

export interface CodeSelectorModalProps extends Omit<ModalProps, 'onOk'> {
onOk?: (params: CodeConfigData | undefined) => void;
}

function CodeSelectorModal({ onOk, ...rest }: CodeSelectorModalProps) {
const [dataList, setDataList] = useState<CodeConfigData[]>([]);
const [total, setTotal] = useState(0);
const [pagination, setPagination] = useState<PaginationProps>({
current: 1,
pageSize: 20,
});
const [searchText, setSearchText] = useState<string | undefined>(undefined);
const [inputText, setInputText] = useState<string | undefined>(undefined);

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

// 获取数据请求
const getDataList = async () => {
const params = {
page: pagination.current! - 1,
size: pagination.pageSize,
code_repo_name: searchText !== '' ? searchText : undefined,
};
const [res] = await to(getCodeConfigListReq(params));
if (res && res.data && res.data.content) {
setDataList(res.data.content);
setTotal(res.data.totalElements);
}
};

// 搜索
const handleSearch = (value: string) => {
setSearchText(value);
};

const handleClick = (item: CodeConfigData) => {
onOk?.(item);
};

// 分页切换
const handlePageChange: PaginationProps['onChange'] = (page, pageSize) => {
setPagination({
current: page,
pageSize: pageSize,
});
};

return (
<KFModal
{...rest}
title="选择代码配置"
image={require('@/assets/img/edit-experiment.png')}
width={920}
footer={null}
destroyOnClose
>
<div className={styles['code-selector']}>
<Input.Search
placeholder="按代码仓库名称筛选"
allowClear
onSearch={handleSearch}
style={{
width: '100%',
}}
onChange={(e) => setInputText(e.target.value)}
suffix={null}
value={inputText}
/>
{dataList?.length !== 0 ? (
<>
<div className={styles['code-selector__content']}>
{dataList?.map((item) => (
<CodeConfigItem item={item} key={item.id} onClick={handleClick} />
))}
</div>
<Pagination
total={total}
showSizeChanger
defaultPageSize={20}
pageSizeOptions={[20, 40, 60, 80, 100]}
showQuickJumper
onChange={handlePageChange}
{...pagination}
/>
</>
) : (
<div className={styles['code-selector__empty']}>
<Empty></Empty>
</div>
)}
</div>
</KFModal>
);
}

export default CodeSelectorModal;

+ 50
- 6
react-ui/src/pages/Pipeline/components/PipelineNodeDrawer/index.tsx View File

@@ -17,6 +17,7 @@ import { INode } from '@antv/g6';
import { Button, Drawer, Form, Input, MenuProps, Select } from 'antd'; import { Button, Drawer, Form, Input, MenuProps, Select } from 'antd';
import { NamePath } from 'antd/es/form/interface'; import { NamePath } from 'antd/es/form/interface';
import { forwardRef, useImperativeHandle, useState } from 'react'; import { forwardRef, useImperativeHandle, useState } from 'react';
import CodeSelectorModal from '../CodeSelectorModal';
import PropsLabel from '../PropsLabel'; import PropsLabel from '../PropsLabel';
import ResourceSelectorModal, { import ResourceSelectorModal, {
ResourceSelectorType, ResourceSelectorType,
@@ -57,7 +58,7 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete
formError: !!error, formError: !!error,
}; };


// console.log('res', res);
console.log('res', res);
onFormChange(res); onFormChange(res);
} }
}; };
@@ -79,7 +80,7 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete
out_parameters: JSON.parse(model.out_parameters), out_parameters: JSON.parse(model.out_parameters),
control_strategy: JSON.parse(model.control_strategy), control_strategy: JSON.parse(model.control_strategy),
}; };
// console.log('model', nodeData);
console.log('model', nodeData);
setStagingItem({ setStagingItem({
...nodeData, ...nodeData,
}); });
@@ -115,6 +116,48 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete
}, },
})); }));


// ref 类型选择
const selectRefData = (
formItemName: NamePath,
item: PipelineNodeModelParameter | Pick<PipelineNodeModelParameter, 'item_type'>,
) => {
if (item.item_type === 'code') {
selectCodeConfig(formItemName, item);
} else {
selectResource(formItemName, item);
}
};

// 选择代码配置
const selectCodeConfig = (
formItemName: NamePath,
item: PipelineNodeModelParameter | Pick<PipelineNodeModelParameter, 'item_type'>,
) => {
const { close } = openAntdModal(CodeSelectorModal, {
onOk: (res) => {
if (res) {
console.log('res', res);
const value = JSON.stringify({
id: res.id,
name: res.code_repo_name,
code_path: res.git_url,
branch: res.git_branch,
username: res.git_user_name,
password: res.git_password,
ssh_private_key: res.ssh_key,
});
form.setFieldValue(formItemName, {
...item,
value,
showValue: res.code_repo_name,
fromSelect: true,
});
}
close();
},
});
};

// 选择数据集、模型、镜像 // 选择数据集、模型、镜像
const selectResource = ( const selectResource = (
formItemName: NamePath, formItemName: NamePath,
@@ -146,8 +189,10 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete
if (type === ResourceSelectorType.Mirror) { if (type === ResourceSelectorType.Mirror) {
const { activeTab, id, version, path } = res; const { activeTab, id, version, path } = res;
if (formItemName === 'image') { if (formItemName === 'image') {
// 单独的选择镜像
form.setFieldValue(formItemName, path); form.setFieldValue(formItemName, path);
} else { } else {
// 输入参数选择镜像
form.setFieldValue(formItemName, { form.setFieldValue(formItemName, {
...item, ...item,
value: path, value: path,
@@ -160,12 +205,11 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete
} }
} else { } else {
const { activeTab, id, name, version, path } = res; const { activeTab, id, name, version, path } = res;
const jsonObj = {
const value = JSON.stringify({
id, id,
version, version,
path, path,
};
const value = JSON.stringify(jsonObj);
});
const showValue = `${name}:${version}`; const showValue = `${name}:${version}`;
form.setFieldValue(formItemName, { form.setFieldValue(formItemName, {
...item, ...item,
@@ -467,7 +511,7 @@ const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParamete
size="small" size="small"
type="link" type="link"
icon={getSelectBtnIcon(item.value)} icon={getSelectBtnIcon(item.value)}
onClick={() => selectResource(['in_parameters', item.key], item.value)}
onClick={() => selectRefData(['in_parameters', item.key], item.value)}
className={styles['pipeline-drawer__ref-row__select-button']} className={styles['pipeline-drawer__ref-row__select-button']}
> >
{item.value.label} {item.value.label}


+ 10
- 3
react-ui/src/pages/System/Config/edit.tsx View File

@@ -22,8 +22,11 @@ export type ConfigFormProps = {


const ConfigForm: React.FC<ConfigFormProps> = (props) => { const ConfigForm: React.FC<ConfigFormProps> = (props) => {
const [form] = Form.useForm(); const [form] = Form.useForm();

const { configTypeOptions } = props; const { configTypeOptions } = props;
const formLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 20 },
};


useEffect(() => { useEffect(() => {
form.resetFields(); form.resetFields();
@@ -32,7 +35,7 @@ const ConfigForm: React.FC<ConfigFormProps> = (props) => {
configName: props.values.configName, configName: props.values.configName,
configKey: props.values.configKey, configKey: props.values.configKey,
configValue: props.values.configValue, configValue: props.values.configValue,
configType: props.values.configType,
configType: props.values.configType || Object.keys(configTypeOptions)[0],
createBy: props.values.createBy, createBy: props.values.createBy,
createTime: props.values.createTime, createTime: props.values.createTime,
updateBy: props.values.updateBy, updateBy: props.values.updateBy,
@@ -54,7 +57,7 @@ const ConfigForm: React.FC<ConfigFormProps> = (props) => {


return ( return (
<KFModal <KFModal
width={640}
width={680}
title={intl.formatMessage({ title={intl.formatMessage({
id: 'system.config.title', id: 'system.config.title',
defaultMessage: '编辑参数配置', defaultMessage: '编辑参数配置',
@@ -71,6 +74,10 @@ const ConfigForm: React.FC<ConfigFormProps> = (props) => {
submitter={false} submitter={false}
layout="horizontal" layout="horizontal"
onFinish={handleFinish} onFinish={handleFinish}
{...formLayout}
size="large"
labelAlign="right"
autoComplete="off"
> >
<ProFormDigit <ProFormDigit
name="configId" name="configId"


+ 1
- 1
react-ui/src/pages/System/Config/index.tsx View File

@@ -331,7 +331,7 @@ const ConfigTableList: React.FC = () => {
handleRefreshCache(); handleRefreshCache();
}} }}
> >
<ReloadOutlined />
<ReloadOutlined />{' '}
<FormattedMessage id="system.config.refreshCache" defaultMessage="刷新缓存" /> <FormattedMessage id="system.config.refreshCache" defaultMessage="刷新缓存" />
</Button>, </Button>,
]} ]}


+ 12
- 7
react-ui/src/pages/System/DictData/edit.tsx View File

@@ -23,8 +23,11 @@ export type DataFormProps = {


const DictDataForm: React.FC<DataFormProps> = (props) => { const DictDataForm: React.FC<DataFormProps> = (props) => {
const [form] = Form.useForm(); const [form] = Form.useForm();

const { statusOptions } = props; const { statusOptions } = props;
const formLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 20 },
};


useEffect(() => { useEffect(() => {
form.resetFields(); form.resetFields();
@@ -36,8 +39,8 @@ const DictDataForm: React.FC<DataFormProps> = (props) => {
dictType: props.values.dictType, dictType: props.values.dictType,
cssClass: props.values.cssClass, cssClass: props.values.cssClass,
listClass: props.values.listClass, listClass: props.values.listClass,
isDefault: props.values.isDefault,
status: props.values.status,
isDefault: props.values.isDefault || 'N',
status: props.values.status || Object.keys(statusOptions)[0],
createBy: props.values.createBy, createBy: props.values.createBy,
createTime: props.values.createTime, createTime: props.values.createTime,
updateBy: props.values.updateBy, updateBy: props.values.updateBy,
@@ -59,7 +62,7 @@ const DictDataForm: React.FC<DataFormProps> = (props) => {


return ( return (
<KFModal <KFModal
width={640}
width={680}
title={intl.formatMessage({ title={intl.formatMessage({
id: 'system.dict.data.title', id: 'system.dict.data.title',
defaultMessage: '编辑字典数据', defaultMessage: '编辑字典数据',
@@ -76,6 +79,10 @@ const DictDataForm: React.FC<DataFormProps> = (props) => {
submitter={false} submitter={false}
layout="horizontal" layout="horizontal"
onFinish={handleFinish} onFinish={handleFinish}
{...formLayout}
size="large"
labelAlign="right"
autoComplete="off"
> >
<ProFormDigit <ProFormDigit
name="dictCode" name="dictCode"
@@ -184,7 +191,7 @@ const DictDataForm: React.FC<DataFormProps> = (props) => {
id: 'system.dict.data.dict_sort', id: 'system.dict.data.dict_sort',
defaultMessage: '字典排序', defaultMessage: '字典排序',
})} })}
colProps={{ md: 12, xl: 12 }}
colProps={{ md: 12, xl: 24 }}
placeholder="请输入字典排序" placeholder="请输入字典排序"
rules={[ rules={[
{ {
@@ -203,7 +210,6 @@ const DictDataForm: React.FC<DataFormProps> = (props) => {
Y: '是', Y: '是',
N: '否', N: '否',
}} }}
initialValue={'N'}
colProps={{ md: 12, xl: 24 }} colProps={{ md: 12, xl: 24 }}
placeholder="请输入是否默认" placeholder="请输入是否默认"
rules={[ rules={[
@@ -220,7 +226,6 @@ const DictDataForm: React.FC<DataFormProps> = (props) => {
id: 'system.dict.data.status', id: 'system.dict.data.status',
defaultMessage: '状态', defaultMessage: '状态',
})} })}
initialValue={'0'}
colProps={{ md: 12, xl: 24 }} colProps={{ md: 12, xl: 24 }}
placeholder="请输入状态" placeholder="请输入状态"
rules={[ rules={[


+ 15
- 3
react-ui/src/pages/System/Logininfor/edit.tsx View File

@@ -22,8 +22,11 @@ export type LogininforFormProps = {


const LogininforForm: React.FC<LogininforFormProps> = (props) => { const LogininforForm: React.FC<LogininforFormProps> = (props) => {
const [form] = Form.useForm(); const [form] = Form.useForm();

const { statusOptions } = props; const { statusOptions } = props;
const formLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 20 },
};


useEffect(() => { useEffect(() => {
form.resetFields(); form.resetFields();
@@ -54,7 +57,7 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => {


return ( return (
<KFModal <KFModal
width={640}
width={680}
title={intl.formatMessage({ title={intl.formatMessage({
id: 'system.logininfor.title', id: 'system.logininfor.title',
defaultMessage: '编辑系统访问记录', defaultMessage: '编辑系统访问记录',
@@ -65,7 +68,16 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => {
onOk={handleOk} onOk={handleOk}
onCancel={handleCancel} onCancel={handleCancel}
> >
<ProForm form={form} grid={true} layout="horizontal" onFinish={handleFinish}>
<ProForm
form={form}
grid={true}
layout="horizontal"
onFinish={handleFinish}
{...formLayout}
size="large"
labelAlign="right"
autoComplete="off"
>
<ProFormDigit <ProFormDigit
name="infoId" name="infoId"
label={intl.formatMessage({ label={intl.formatMessage({


+ 10
- 3
react-ui/src/pages/System/Notice/edit.tsx View File

@@ -24,8 +24,11 @@ export type NoticeFormProps = {


const NoticeForm: React.FC<NoticeFormProps> = (props) => { const NoticeForm: React.FC<NoticeFormProps> = (props) => {
const [form] = Form.useForm(); const [form] = Form.useForm();

const { noticeTypeOptions, statusOptions } = props; const { noticeTypeOptions, statusOptions } = props;
const formLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 20 },
};


useEffect(() => { useEffect(() => {
form.resetFields(); form.resetFields();
@@ -34,7 +37,7 @@ const NoticeForm: React.FC<NoticeFormProps> = (props) => {
noticeTitle: props.values.noticeTitle, noticeTitle: props.values.noticeTitle,
noticeType: props.values.noticeType, noticeType: props.values.noticeType,
noticeContent: props.values.noticeContent, noticeContent: props.values.noticeContent,
status: props.values.status,
status: props.values.status || Object.keys(statusOptions)[0],
createBy: props.values.createBy, createBy: props.values.createBy,
createTime: props.values.createTime, createTime: props.values.createTime,
updateBy: props.values.updateBy, updateBy: props.values.updateBy,
@@ -56,7 +59,7 @@ const NoticeForm: React.FC<NoticeFormProps> = (props) => {


return ( return (
<KFModal <KFModal
width={640}
width={680}
title={intl.formatMessage({ title={intl.formatMessage({
id: 'system.notice.title', id: 'system.notice.title',
defaultMessage: '编辑通知公告', defaultMessage: '编辑通知公告',
@@ -73,6 +76,10 @@ const NoticeForm: React.FC<NoticeFormProps> = (props) => {
submitter={false} submitter={false}
layout="horizontal" layout="horizontal"
onFinish={handleFinish} onFinish={handleFinish}
{...formLayout}
size="large"
labelAlign="right"
autoComplete="off"
> >
<ProFormDigit <ProFormDigit
name="noticeId" name="noticeId"


+ 1
- 1
react-ui/src/pages/System/Operlog/detail.tsx View File

@@ -29,7 +29,7 @@ const OperlogDetailForm: React.FC<OperlogFormProps> = (props) => {


return ( return (
<KFModal <KFModal
width={640}
width={680}
title={intl.formatMessage({ title={intl.formatMessage({
id: 'monitor.operlog.title', id: 'monitor.operlog.title',
defaultMessage: '编辑操作日志记录', defaultMessage: '编辑操作日志记录',


+ 11
- 11
react-ui/src/pages/System/Operlog/index.tsx View File

@@ -245,17 +245,17 @@ const OperlogTableList: React.FC = () => {
tableAlertRender={false} tableAlertRender={false}
tableAlertOptionRender={false} tableAlertOptionRender={false}
toolBarRender={() => [ toolBarRender={() => [
<Button
type="primary"
key="add"
hidden={!access.hasPerms('system:operlog:add')}
onClick={async () => {
setCurrentRow(undefined);
setModalVisible(true);
}}
>
<PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="新建" />
</Button>,
// <Button
// type="primary"
// key="add"
// hidden={!access.hasPerms('system:operlog:add')}
// onClick={async () => {
// setCurrentRow(undefined);
// setModalVisible(true);
// }}
// >
// <PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="新建" />
// </Button>,
<Button <Button
type="primary" type="primary"
key="remove" key="remove"


+ 9
- 1
react-ui/src/pages/System/Role/components/DataScope.tsx View File

@@ -33,6 +33,10 @@ const DataScopeForm: React.FC<DataScopeFormProps> = (props) => {
); );
const [deptTreeExpandKey, setDeptTreeExpandKey] = useState<Key[]>([]); const [deptTreeExpandKey, setDeptTreeExpandKey] = useState<Key[]>([]);
const [checkStrictly, setCheckStrictly] = useState<boolean>(true); const [checkStrictly, setCheckStrictly] = useState<boolean>(true);
const formLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 20 },
};


useEffect(() => { useEffect(() => {
setDeptIds(deptCheckedKeys); setDeptIds(deptCheckedKeys);
@@ -91,7 +95,7 @@ const DataScopeForm: React.FC<DataScopeFormProps> = (props) => {


return ( return (
<KFModal <KFModal
width={640}
width={680}
title={intl.formatMessage({ title={intl.formatMessage({
id: 'system.user.auth.role', id: 'system.user.auth.role',
defaultMessage: '分配角色', defaultMessage: '分配角色',
@@ -111,6 +115,10 @@ const DataScopeForm: React.FC<DataScopeFormProps> = (props) => {
login_password: '', login_password: '',
confirm_password: '', confirm_password: '',
}} }}
{...formLayout}
size="large"
labelAlign="right"
autoComplete="off"
> >
<ProFormDigit <ProFormDigit
name="roleId" name="roleId"


+ 5
- 4
react-ui/src/pages/System/User/edit.tsx View File

@@ -73,7 +73,11 @@ const UserForm: React.FC<UserFormProps> = (props) => {
props.onCancel(); props.onCancel();
}; };
const handleFinish = async (values: Record<string, any>) => { const handleFinish = async (values: Record<string, any>) => {
props.onSubmit(values as UserFormData);
const params = {
...values,
userId: props.values.userId,
};
props.onSubmit(params as UserFormData);
}; };


return ( return (
@@ -189,9 +193,6 @@ const UserForm: React.FC<UserFormProps> = (props) => {
hidden={userId} hidden={userId}
placeholder="请输入用户账号" placeholder="请输入用户账号"
colProps={{ md: 12, xl: 12 }} colProps={{ md: 12, xl: 12 }}
fieldProps={{
autoComplete: 'off',
}}
rules={[ rules={[
{ {
required: true, required: true,


+ 3
- 4
react-ui/src/pages/User/Login/index.tsx View File

@@ -22,7 +22,6 @@ const Login = () => {
const [captchaCode, setCaptchaCode] = useState<string>(''); const [captchaCode, setCaptchaCode] = useState<string>('');
const [uuid, setUuid] = useState<string>(''); const [uuid, setUuid] = useState<string>('');
const [form] = Form.useForm(); const [form] = Form.useForm();
const [usernameReadOnly, setUsernameReadOnly] = useState<boolean>(true);
const captchaInputRef = useRef<InputRef>(null); const captchaInputRef = useRef<InputRef>(null);


useEffect(() => { useEffect(() => {
@@ -82,7 +81,9 @@ const Login = () => {
history.push(urlParams.get('redirect') || '/'); history.push(urlParams.get('redirect') || '/');
} else { } else {
if (error?.data?.code === 500 && error?.data?.msg === '验证码错误') { if (error?.data?.code === 500 && error?.data?.msg === '验证码错误') {
captchaInputRef.current?.focus();
captchaInputRef.current?.focus({
cursor: 'all',
});
} }


clearSessionToken(); clearSessionToken();
@@ -140,8 +141,6 @@ const Login = () => {
placeholder="请输入用户名" placeholder="请输入用户名"
prefix={<LoginInputPrefix icon={require('@/assets/img/login-user.png')} />} prefix={<LoginInputPrefix icon={require('@/assets/img/login-user.png')} />}
allowClear allowClear
readOnly={usernameReadOnly}
onFocus={() => setUsernameReadOnly(false)}
/> />
</Form.Item> </Form.Item>




+ 1
- 1
react-ui/src/services/session.ts View File

@@ -39,7 +39,7 @@ function patchRouteItems(route: any, menu: any, parentPath: string) {
} }
} else { } else {
if (getLocalRoute(route, menuItem)) { if (getLocalRoute(route, menuItem)) {
return;
continue;
} }
const names: string[] = menuItem.component.split('/'); const names: string[] = menuItem.component.split('/');
let path = ''; let path = '';


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

@@ -24,8 +24,15 @@ export const menuItemRender = (isSubMenu: boolean) => {
<span className="kf-menu-item__name">{item.name}</span> <span className="kf-menu-item__name">{item.name}</span>
</> </>
); );

if (isSubMenu) { if (isSubMenu) {
return <div className="kf-menu-item">{childen}</div>; return <div className="kf-menu-item">{childen}</div>;
} else if (item.isUrl) {
return (
<a href={item.path || ''} target="_blank" className="kf-menu-item" rel="noreferrer">
{childen}
</a>
);
} else { } else {
return ( return (
<Link to={item.path || ''} className="kf-menu-item"> <Link to={item.path || ''} className="kf-menu-item">


Loading…
Cancel
Save