mirror of
https://github.com/whyour/qinglong.git
synced 2025-05-23 06:46:09 +08:00
完善定时任务视图
This commit is contained in:
parent
bc5a3a2028
commit
2f05c95422
|
@ -28,8 +28,8 @@ export default (app: Router) => {
|
||||||
celebrate({
|
celebrate({
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
name: Joi.string().required(),
|
name: Joi.string().required(),
|
||||||
sorts: Joi.string().optional(),
|
sorts: Joi.array().optional(),
|
||||||
filters: Joi.string().optional(),
|
filters: Joi.array().optional(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
@ -49,8 +49,8 @@ export default (app: Router) => {
|
||||||
body: Joi.object({
|
body: Joi.object({
|
||||||
name: Joi.string().required(),
|
name: Joi.string().required(),
|
||||||
id: Joi.number().required(),
|
id: Joi.number().required(),
|
||||||
sorts: Joi.string().optional(),
|
sorts: Joi.array().optional(),
|
||||||
filters: Joi.string().optional(),
|
filters: Joi.array().optional(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
|
|
@ -14,7 +14,7 @@ import dayjs from 'dayjs';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class CronService {
|
export default class CronService {
|
||||||
constructor(@Inject('logger') private logger: winston.Logger) {}
|
constructor(@Inject('logger') private logger: winston.Logger) { }
|
||||||
|
|
||||||
private isSixCron(cron: Crontab) {
|
private isSixCron(cron: Crontab) {
|
||||||
const { schedule } = cron;
|
const { schedule } = cron;
|
||||||
|
@ -113,20 +113,34 @@ export default class CronService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async crontabs(params?: {
|
private formatViewQuery(query: any, viewQuery: any) {
|
||||||
searchValue: string;
|
if (viewQuery.filters) {
|
||||||
page: string;
|
for (const col of viewQuery.filters) {
|
||||||
size: string;
|
const { property, value, operation } = col;
|
||||||
sortField: string;
|
let operate = null;
|
||||||
sortType: string;
|
switch (operation) {
|
||||||
}): Promise<{ data: Crontab[]; total: number }> {
|
case 'Reg':
|
||||||
const searchText = params?.searchValue;
|
operate = Op.like;
|
||||||
const page = Number(params?.page || '0');
|
break;
|
||||||
const size = Number(params?.size || '0');
|
case 'Reg':
|
||||||
const sortField = params?.sortField || '';
|
operate = Op.notLike;
|
||||||
const sortType = params?.sortType || '';
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (operate) {
|
||||||
|
query[property] = {
|
||||||
|
[Op.or]: [
|
||||||
|
{ [operate]: `%${value}%` },
|
||||||
|
{ [operate]: `%${encodeURIComponent(value)}%` },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let query = {};
|
private formatSearchText(query: any, searchText: string | undefined) {
|
||||||
if (searchText) {
|
if (searchText) {
|
||||||
const textArray = searchText.split(':');
|
const textArray = searchText.split(':');
|
||||||
switch (textArray[0]) {
|
switch (textArray[0]) {
|
||||||
|
@ -170,12 +184,43 @@ export default class CronService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatViewSort(order: string[][], viewQuery: any) {
|
||||||
|
if (viewQuery.sorts) {
|
||||||
|
for (const [col, sortType] of viewQuery.sorts) {
|
||||||
|
order.unshift([col, sortType]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async crontabs(params?: {
|
||||||
|
searchValue: string;
|
||||||
|
page: string;
|
||||||
|
size: string;
|
||||||
|
sortField: string;
|
||||||
|
sortType: string;
|
||||||
|
queryString: string;
|
||||||
|
}): Promise<{ data: Crontab[]; total: number }> {
|
||||||
|
const searchText = params?.searchValue;
|
||||||
|
const page = Number(params?.page || '0');
|
||||||
|
const size = Number(params?.size || '0');
|
||||||
|
const sortField = params?.sortField || '';
|
||||||
|
const sortType = params?.sortType || '';
|
||||||
|
const viewQuery = JSON.parse(params?.queryString || '{}');
|
||||||
|
|
||||||
|
let query: any = {};
|
||||||
let order = [
|
let order = [
|
||||||
['isPinned', 'DESC'],
|
['isPinned', 'DESC'],
|
||||||
['isDisabled', 'ASC'],
|
['isDisabled', 'ASC'],
|
||||||
['status', 'ASC'],
|
['status', 'ASC'],
|
||||||
['createdAt', 'DESC'],
|
['createdAt', 'DESC'],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
this.formatViewQuery(query, viewQuery);
|
||||||
|
this.formatSearchText(query, searchText);
|
||||||
|
this.formatViewSort(order, viewQuery);
|
||||||
|
|
||||||
if (sortType && sortField) {
|
if (sortType && sortField) {
|
||||||
order.unshift([sortField, sortType]);
|
order.unshift([sortField, sortType]);
|
||||||
}
|
}
|
||||||
|
@ -229,9 +274,9 @@ export default class CronService {
|
||||||
const endTime = dayjs();
|
const endTime = dayjs();
|
||||||
const diffTimeStr = doc.last_execution_time
|
const diffTimeStr = doc.last_execution_time
|
||||||
? `,耗时 ${endTime.diff(
|
? `,耗时 ${endTime.diff(
|
||||||
dayjs(doc.last_execution_time * 1000),
|
dayjs(doc.last_execution_time * 1000),
|
||||||
'second',
|
'second',
|
||||||
)}`
|
)}`
|
||||||
: '';
|
: '';
|
||||||
if (logFileExist) {
|
if (logFileExist) {
|
||||||
const str = err ? `\n${err}` : '';
|
const str = err ? `\n${err}` : '';
|
||||||
|
|
|
@ -186,9 +186,8 @@ export default function (props: any) {
|
||||||
if (
|
if (
|
||||||
['/login', '/initialization', '/error'].includes(props.location.pathname)
|
['/login', '/initialization', '/error'].includes(props.location.pathname)
|
||||||
) {
|
) {
|
||||||
document.title = `${
|
document.title = `${(config.documentTitleMap as any)[props.location.pathname]
|
||||||
(config.documentTitleMap as any)[props.location.pathname]
|
} - 控制面板`;
|
||||||
} - 控制面板`;
|
|
||||||
if (
|
if (
|
||||||
systemInfo?.isInitialized &&
|
systemInfo?.isInitialized &&
|
||||||
props.location.pathname === '/initialization'
|
props.location.pathname === '/initialization'
|
||||||
|
@ -282,7 +281,7 @@ export default function (props: any) {
|
||||||
shape="square"
|
shape="square"
|
||||||
size="small"
|
size="small"
|
||||||
icon={<UserOutlined />}
|
icon={<UserOutlined />}
|
||||||
src={`/api/static/${user.avatar}`}
|
src={user.avatar ? `/api/static/${user.avatar}` : ''}
|
||||||
/>
|
/>
|
||||||
<span style={{ marginLeft: 5 }}>{user.username}</span>
|
<span style={{ marginLeft: 5 }}>{user.username}</span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -304,7 +303,7 @@ export default function (props: any) {
|
||||||
shape="square"
|
shape="square"
|
||||||
size="small"
|
size="small"
|
||||||
icon={<UserOutlined />}
|
icon={<UserOutlined />}
|
||||||
src={`/api/static/${user.avatar}`}
|
src={user.avatar ? `/api/static/${user.avatar}` : ''}
|
||||||
/>
|
/>
|
||||||
<span style={{ marginLeft: 5 }}>{user.username}</span>
|
<span style={{ marginLeft: 5 }}>{user.username}</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -108,7 +108,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-more {
|
.view-more {
|
||||||
margin-left: 20px;
|
margin-left: 32px;
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
|
|
@ -358,6 +358,7 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
||||||
size: number;
|
size: number;
|
||||||
sorter: any;
|
sorter: any;
|
||||||
}>({} as any);
|
}>({} as any);
|
||||||
|
const [viewConf, setViewConf] = useState<any>();
|
||||||
const [tableScrollHeight, setTableScrollHeight] = useState<number>();
|
const [tableScrollHeight, setTableScrollHeight] = useState<number>();
|
||||||
const [isDetailModalVisible, setIsDetailModalVisible] = useState(false);
|
const [isDetailModalVisible, setIsDetailModalVisible] = useState(false);
|
||||||
const [detailCron, setDetailCron] = useState<any>();
|
const [detailCron, setDetailCron] = useState<any>();
|
||||||
|
@ -396,6 +397,9 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
||||||
sorter.order === 'ascend' ? 'ASC' : 'DESC'
|
sorter.order === 'ascend' ? 'ASC' : 'DESC'
|
||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
|
if (viewConf) {
|
||||||
|
url += `&queryString=${JSON.stringify({ filters: viewConf.filters })}`;
|
||||||
|
}
|
||||||
request
|
request
|
||||||
.get(url)
|
.get(url)
|
||||||
.then((_data: any) => {
|
.then((_data: any) => {
|
||||||
|
@ -828,7 +832,7 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
||||||
if (pageConf.page && pageConf.size) {
|
if (pageConf.page && pageConf.size) {
|
||||||
getCrons();
|
getCrons();
|
||||||
}
|
}
|
||||||
}, [pageConf]);
|
}, [pageConf, viewConf]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPageConf({
|
setPageConf({
|
||||||
|
@ -944,6 +948,7 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
tabClick(key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -955,7 +960,7 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
||||||
viewAction(key);
|
viewAction(key);
|
||||||
}}
|
}}
|
||||||
items={[
|
items={[
|
||||||
...[...cronViews].slice(5).map((x) => ({
|
...[...cronViews].slice(2).map((x) => ({
|
||||||
label: x.name,
|
label: x.name,
|
||||||
key: x.id,
|
key: x.id,
|
||||||
icon: <UnorderedListOutlined />,
|
icon: <UnorderedListOutlined />,
|
||||||
|
@ -989,6 +994,11 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const tabClick = (key: string) => {
|
||||||
|
const view = cronViews.find(x => x.id == key);
|
||||||
|
setViewConf(view ? view : null);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer
|
<PageContainer
|
||||||
className="ql-container-wrapper crontab-wrapper ql-container-wrapper-has-tab"
|
className="ql-container-wrapper crontab-wrapper ql-container-wrapper-has-tab"
|
||||||
|
@ -1018,7 +1028,7 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
||||||
tabPosition="top"
|
tabPosition="top"
|
||||||
className="crontab-view"
|
className="crontab-view"
|
||||||
tabBarExtraContent={
|
tabBarExtraContent={
|
||||||
<Dropdown overlay={menu} trigger={['click']}>
|
<Dropdown overlay={menu} trigger={['click']} overlayStyle={{minWidth: 200}}>
|
||||||
<div className="view-more">
|
<div className="view-more">
|
||||||
<Space>
|
<Space>
|
||||||
更多
|
更多
|
||||||
|
@ -1028,11 +1038,12 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
||||||
</div>
|
</div>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
}
|
}
|
||||||
|
onTabClick={tabClick}
|
||||||
>
|
>
|
||||||
<Tabs.TabPane tab="全部任务" key="all">
|
<Tabs.TabPane tab="全部任务" key="all">
|
||||||
{panelContent}
|
{panelContent}
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
{[...cronViews].slice(0, 5).map((x) => (
|
{[...cronViews].slice(0, 2).map((x) => (
|
||||||
<Tabs.TabPane tab={x.name} key={x.id}>
|
<Tabs.TabPane tab={x.name} key={x.id}>
|
||||||
{panelContent}
|
{panelContent}
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
|
@ -1073,14 +1084,19 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
||||||
<ViewCreateModal
|
<ViewCreateModal
|
||||||
visible={isCreateViewModalVisible}
|
visible={isCreateViewModalVisible}
|
||||||
handleCancel={() => {
|
handleCancel={() => {
|
||||||
|
getCronViews();
|
||||||
setIsCreateViewModalVisible(false);
|
setIsCreateViewModalVisible(false);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ViewManageModal
|
<ViewManageModal
|
||||||
|
cronViews={cronViews}
|
||||||
visible={isViewManageModalVisible}
|
visible={isViewManageModalVisible}
|
||||||
handleCancel={() => {
|
handleCancel={() => {
|
||||||
setIsViewManageModalVisible(false);
|
setIsViewManageModalVisible(false);
|
||||||
}}
|
}}
|
||||||
|
cronViewChange={() => {
|
||||||
|
getCronViews();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
|
|
|
@ -20,10 +20,14 @@ const PROPERTIES = [
|
||||||
];
|
];
|
||||||
|
|
||||||
const OPERATIONS = [
|
const OPERATIONS = [
|
||||||
{ name: '包含', value: 'contains' },
|
{ name: '包含', value: 'Reg' },
|
||||||
{ name: '不包含', value: 'noncontains' },
|
{ name: '不包含', value: 'NotReg' },
|
||||||
// { name: '属于', value: 'belong' },
|
// { name: '属于', value: 'In' },
|
||||||
// { name: '不属于', value: 'nonbelong' },
|
// { name: '不属于', value: 'Nin' },
|
||||||
|
// { name: '等于', value: 'Eq' },
|
||||||
|
// { name: '不等于', value: 'Ne' },
|
||||||
|
// { name: '为空', value: 'IsNull' },
|
||||||
|
// { name: '不为空', value: 'NotNull' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const ViewCreateModal = ({
|
const ViewCreateModal = ({
|
||||||
|
@ -61,7 +65,7 @@ const ViewCreateModal = ({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
filters: [{ property: 'command', operation: 'contains' }],
|
filters: [{ property: 'command', operation: 'Reg' }],
|
||||||
});
|
});
|
||||||
}, [view, visible]);
|
}, [view, visible]);
|
||||||
|
|
||||||
|
@ -154,9 +158,9 @@ const ViewCreateModal = ({
|
||||||
))}
|
))}
|
||||||
<Form.Item>
|
<Form.Item>
|
||||||
<a
|
<a
|
||||||
href=""
|
href="#"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
add({ property: 'command', operation: 'contains' })
|
add({ property: 'command', operation: 'Reg' })
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<PlusOutlined />
|
<PlusOutlined />
|
||||||
|
|
|
@ -3,8 +3,6 @@ import { Modal, message, Space, Table, Tag, Typography, Button } from 'antd';
|
||||||
import { request } from '@/utils/http';
|
import { request } from '@/utils/http';
|
||||||
import config from '@/utils/config';
|
import config from '@/utils/config';
|
||||||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
|
import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
|
||||||
import { PageLoading } from '@ant-design/pro-layout';
|
|
||||||
import Paragraph from 'antd/lib/skeleton/Paragraph';
|
|
||||||
import { DndProvider, useDrag, useDrop } from 'react-dnd';
|
import { DndProvider, useDrag, useDrop } from 'react-dnd';
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
import ViewCreateModal from './viewCreateModal';
|
import ViewCreateModal from './viewCreateModal';
|
||||||
|
@ -58,11 +56,15 @@ const DragableBodyRow = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
const ViewManageModal = ({
|
const ViewManageModal = ({
|
||||||
|
cronViews,
|
||||||
handleCancel,
|
handleCancel,
|
||||||
visible,
|
visible,
|
||||||
|
cronViewChange
|
||||||
}: {
|
}: {
|
||||||
|
cronViews: any[];
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
handleCancel: () => void;
|
handleCancel: () => void;
|
||||||
|
cronViewChange: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const columns: any = [
|
const columns: any = [
|
||||||
{
|
{
|
||||||
|
@ -72,16 +74,16 @@ const ViewManageModal = ({
|
||||||
align: 'center' as const,
|
align: 'center' as const,
|
||||||
width: 70,
|
width: 70,
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
title: '显示',
|
// title: '显示',
|
||||||
key: 'status',
|
// key: 'isDisabled',
|
||||||
dataIndex: 'status',
|
// dataIndex: 'isDisabled',
|
||||||
align: 'center' as const,
|
// align: 'center' as const,
|
||||||
width: 70,
|
// width: 70,
|
||||||
render: (text: string, record: any, index: number) => {
|
// render: (text: string, record: any, index: number) => {
|
||||||
return <Space size="middle" style={{ cursor: 'text' }}></Space>;
|
// return <Space size="middle" style={{ cursor: 'text' }}></Space>;
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
|
@ -102,7 +104,6 @@ const ViewManageModal = ({
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const [list, setList] = useState<any[]>([]);
|
const [list, setList] = useState<any[]>([]);
|
||||||
const [loading, setLoading] = useState<any>(true);
|
|
||||||
const [isCreateViewModalVisible, setIsCreateViewModalVisible] =
|
const [isCreateViewModalVisible, setIsCreateViewModalVisible] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
|
|
||||||
|
@ -129,9 +130,7 @@ const ViewManageModal = ({
|
||||||
.then((data: any) => {
|
.then((data: any) => {
|
||||||
if (data.code === 200) {
|
if (data.code === 200) {
|
||||||
message.success('删除成功');
|
message.success('删除成功');
|
||||||
const result = [...list];
|
cronViewChange();
|
||||||
result.splice(index, 1);
|
|
||||||
setList(result);
|
|
||||||
} else {
|
} else {
|
||||||
message.error(data);
|
message.error(data);
|
||||||
}
|
}
|
||||||
|
@ -143,18 +142,6 @@ const ViewManageModal = ({
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCronViews = () => {
|
|
||||||
setLoading(true);
|
|
||||||
request
|
|
||||||
.get(`${config.apiPrefix}crons/views`)
|
|
||||||
.then((data: any) => {
|
|
||||||
console.log(data);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const components = {
|
const components = {
|
||||||
body: {
|
body: {
|
||||||
row: DragableBodyRow,
|
row: DragableBodyRow,
|
||||||
|
@ -186,8 +173,8 @@ const ViewManageModal = ({
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// getCronViews();
|
setList(cronViews);
|
||||||
}, []);
|
}, [cronViews]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -201,7 +188,7 @@ const ViewManageModal = ({
|
||||||
footer={false}
|
footer={false}
|
||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
>
|
>
|
||||||
<Space style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
<Space style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 10 }}>
|
||||||
<Button
|
<Button
|
||||||
key="2"
|
key="2"
|
||||||
type="primary"
|
type="primary"
|
||||||
|
@ -210,30 +197,28 @@ const ViewManageModal = ({
|
||||||
新建视图
|
新建视图
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
{loading ? (
|
<DndProvider backend={HTML5Backend}>
|
||||||
<PageLoading />
|
<Table
|
||||||
) : (
|
bordered
|
||||||
<DndProvider backend={HTML5Backend}>
|
columns={columns}
|
||||||
<Table
|
pagination={false}
|
||||||
columns={columns}
|
dataSource={list}
|
||||||
pagination={false}
|
rowKey="id"
|
||||||
dataSource={list}
|
size="middle"
|
||||||
rowKey="id"
|
style={{ marginBottom: 20 }}
|
||||||
size="middle"
|
components={components}
|
||||||
components={components}
|
onRow={(record: any, index: number) => {
|
||||||
loading={loading}
|
return {
|
||||||
onRow={(record: any, index: number) => {
|
index,
|
||||||
return {
|
moveRow,
|
||||||
index,
|
} as any;
|
||||||
moveRow,
|
}}
|
||||||
} as any;
|
/>
|
||||||
}}
|
</DndProvider>
|
||||||
/>
|
|
||||||
</DndProvider>
|
|
||||||
)}
|
|
||||||
<ViewCreateModal
|
<ViewCreateModal
|
||||||
visible={isCreateViewModalVisible}
|
visible={isCreateViewModalVisible}
|
||||||
handleCancel={() => {
|
handleCancel={() => {
|
||||||
|
cronViewChange();
|
||||||
setIsCreateViewModalVisible(false);
|
setIsCreateViewModalVisible(false);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user