You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@inlong.apache.org by he...@apache.org on 2022/05/16 08:32:21 UTC
[incubator-inlong] branch master updated: [INLONG-4218][Dashboard] Unified group page (#4219)
This is an automated email from the ASF dual-hosted git repository.
healchow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-inlong.git
The following commit(s) were added to refs/heads/master by this push:
new ff35db420 [INLONG-4218][Dashboard] Unified group page (#4219)
ff35db420 is described below
commit ff35db420cc6c032693f057d6dc66e4414dbf24a
Author: Daniel <le...@outlook.com>
AuthorDate: Mon May 16 16:32:16 2022 +0800
[INLONG-4218][Dashboard] Unified group page (#4219)
---
.../src/components/FormGenerator/FormGenerator.tsx | 3 +-
inlong-dashboard/src/configs/routes/index.tsx | 4 +-
inlong-dashboard/src/locales/cn.json | 2 -
inlong-dashboard/src/locales/en.json | 2 -
.../src/pages/AccessCreate/DataStream/config.tsx | 16 +-
.../src/pages/AccessDashboard/config.tsx | 2 +-
.../src/pages/AccessDetail/DataSources/index.tsx | 6 +-
.../src/pages/AccessDetail/DataStorage/index.tsx | 6 +-
.../AccessDetail/DataStream/StreamItemModal.tsx | 8 -
.../src/pages/AccessDetail/DataStream/config.tsx | 40 ++---
.../src/pages/AccessDetail/DataStream/index.tsx | 29 ++--
.../src/pages/AccessDetail/Info/config.tsx | 85 +++++-----
.../src/pages/AccessDetail/Info/index.tsx | 105 ++++++++-----
.../src/pages/AccessDetail/common.d.ts | 5 +-
inlong-dashboard/src/pages/AccessDetail/index.tsx | 174 +++++++++++++++++----
15 files changed, 315 insertions(+), 172 deletions(-)
diff --git a/inlong-dashboard/src/components/FormGenerator/FormGenerator.tsx b/inlong-dashboard/src/components/FormGenerator/FormGenerator.tsx
index f43c6939c..99634b69d 100644
--- a/inlong-dashboard/src/components/FormGenerator/FormGenerator.tsx
+++ b/inlong-dashboard/src/components/FormGenerator/FormGenerator.tsx
@@ -129,11 +129,12 @@ const FormGenerator: React.FC<FormGeneratorProps> = props => {
if (props.allValues) {
setRealTimeValues(props.allValues);
} else if (form) {
- setTimeout(() => {
+ const timmer = setTimeout(() => {
const { getFieldsValue } = form;
const values = getFieldsValue(true);
setRealTimeValues(prev => ({ ...prev, ...values }));
}, 0);
+ return () => clearTimeout(timmer);
}
}, [form, props.allValues]);
diff --git a/inlong-dashboard/src/configs/routes/index.tsx b/inlong-dashboard/src/configs/routes/index.tsx
index cf7634fd6..f885bae6f 100644
--- a/inlong-dashboard/src/configs/routes/index.tsx
+++ b/inlong-dashboard/src/configs/routes/index.tsx
@@ -42,8 +42,8 @@ const routes: RouteProps[] = [
exact: true,
childRoutes: [
{
- path: '/create',
- component: () => import('@/pages/AccessCreate'),
+ path: '/create/:id?',
+ component: () => import('@/pages/AccessDetail'),
exact: true,
},
{
diff --git a/inlong-dashboard/src/locales/cn.json b/inlong-dashboard/src/locales/cn.json
index a6db70428..99e5576c4 100644
--- a/inlong-dashboard/src/locales/cn.json
+++ b/inlong-dashboard/src/locales/cn.json
@@ -178,13 +178,11 @@
"pages.AccessCreate.Business.config.AccessRequirements": "接入要求",
"pages.AccessCreate.Business.config.AccessScale": "接入规模",
"pages.AccessCreate.DataStream.config.Basic": "基础信息",
- "pages.AccessCreate.DataStream.config.DataSources": "数据来源",
"pages.AccessCreate.DataStream.config.DataInfo": "数据信息",
"pages.AccessCreate.DataStream.config.DataStorages": "数据流向",
"pages.AccessCreate.Back": "返回",
"pages.AccessCreate.NextStep": "下一步",
"pages.AccessCreate.DataStreams": "数据流",
- "pages.AccessCreate.CheckFormIntegrity": "请检查表单完整性",
"pages.AccessCreate.Submit": "提交审批",
"pages.AccessCreate.SubmittedSuccessfully": "提交成功",
"pages.AccessCreate.BusinessInfo": "分组信息",
diff --git a/inlong-dashboard/src/locales/en.json b/inlong-dashboard/src/locales/en.json
index 469cd3bae..8c2d2b322 100644
--- a/inlong-dashboard/src/locales/en.json
+++ b/inlong-dashboard/src/locales/en.json
@@ -178,13 +178,11 @@
"pages.AccessCreate.Business.config.AccessRequirements": "Access requirements",
"pages.AccessCreate.Business.config.AccessScale": "Access scale",
"pages.AccessCreate.DataStream.config.Basic": "Basic Info",
- "pages.AccessCreate.DataStream.config.DataSources": "Data Sources",
"pages.AccessCreate.DataStream.config.DataInfo": "Data Info",
"pages.AccessCreate.DataStream.config.DataStorages": "Data Storages",
"pages.AccessCreate.Back": "Back",
"pages.AccessCreate.NextStep": "Next",
"pages.AccessCreate.DataStreams": "Data streams",
- "pages.AccessCreate.CheckFormIntegrity": "Check form integrity",
"pages.AccessCreate.Submit": "Submit",
"pages.AccessCreate.SubmittedSuccessfully": "Submitted successfully",
"pages.AccessCreate.BusinessInfo": "Group information",
diff --git a/inlong-dashboard/src/pages/AccessCreate/DataStream/config.tsx b/inlong-dashboard/src/pages/AccessCreate/DataStream/config.tsx
index d7a980a87..f3dc20a11 100644
--- a/inlong-dashboard/src/pages/AccessCreate/DataStream/config.tsx
+++ b/inlong-dashboard/src/pages/AccessCreate/DataStream/config.tsx
@@ -41,14 +41,14 @@ export const genFormContent = (currentValues, inlongGroupId, middlewareType) =>
'inlongStreamId',
'name',
'description',
- {
- type: (
- <Divider orientation="left">
- {i18n.t('pages.AccessCreate.DataStream.config.DataSources')}
- </Divider>
- ),
- },
- 'dataSourceType',
+ // {
+ // type: (
+ // <Divider orientation="left">
+ // {i18n.t('pages.AccessCreate.DataStream.config.DataSources')}
+ // </Divider>
+ // ),
+ // },
+ // 'dataSourceType',
// 'hasHigher',
// 'isHybridSource',
// 'isTableMapping',
diff --git a/inlong-dashboard/src/pages/AccessDashboard/config.tsx b/inlong-dashboard/src/pages/AccessDashboard/config.tsx
index 2a6cc38e4..4f836b4af 100644
--- a/inlong-dashboard/src/pages/AccessDashboard/config.tsx
+++ b/inlong-dashboard/src/pages/AccessDashboard/config.tsx
@@ -70,7 +70,7 @@ export const getFilterFormContent = defaultValues => [
];
export const getColumns = ({ onDelete, openModal }) => {
- const genCreateUrl = record => `/access/create?inlongGroupId=${record.inlongGroupId}`;
+ const genCreateUrl = record => `/access/create/${record.inlongGroupId}`;
const genDetailUrl = record =>
[0, 100].includes(record.status)
? genCreateUrl(record)
diff --git a/inlong-dashboard/src/pages/AccessDetail/DataSources/index.tsx b/inlong-dashboard/src/pages/AccessDetail/DataSources/index.tsx
index 9e73f98cc..96f99013b 100644
--- a/inlong-dashboard/src/pages/AccessDetail/DataSources/index.tsx
+++ b/inlong-dashboard/src/pages/AccessDetail/DataSources/index.tsx
@@ -17,7 +17,7 @@
* under the License.
*/
-import React, { useState } from 'react';
+import React, { useState, forwardRef } from 'react';
import { Button, Modal, message } from 'antd';
import HighTable from '@/components/HighTable';
import { defaultSize } from '@/configs/pagination';
@@ -58,7 +58,7 @@ const getFilterFormContent = defaultValues => [
},
];
-const Comp: React.FC<Props> = ({ inlongGroupId }) => {
+const Comp = ({ inlongGroupId }: Props, ref) => {
const [options, setOptions] = useState({
// keyword: '',
pageSize: defaultSize,
@@ -245,4 +245,4 @@ const Comp: React.FC<Props> = ({ inlongGroupId }) => {
);
};
-export default Comp;
+export default forwardRef(Comp);
diff --git a/inlong-dashboard/src/pages/AccessDetail/DataStorage/index.tsx b/inlong-dashboard/src/pages/AccessDetail/DataStorage/index.tsx
index 94a831279..aa04f4b18 100644
--- a/inlong-dashboard/src/pages/AccessDetail/DataStorage/index.tsx
+++ b/inlong-dashboard/src/pages/AccessDetail/DataStorage/index.tsx
@@ -17,7 +17,7 @@
* under the License.
*/
-import React, { useState, useMemo } from 'react';
+import React, { useState, useMemo, forwardRef } from 'react';
import { Button, Modal, message } from 'antd';
import HighTable from '@/components/HighTable';
import { defaultSize } from '@/configs/pagination';
@@ -51,7 +51,7 @@ const getFilterFormContent = defaultValues => [
},
];
-const Comp: React.FC<Props> = ({ inlongGroupId }) => {
+const Comp = ({ inlongGroupId }: Props, ref) => {
const [options, setOptions] = useState({
keyword: '',
pageSize: defaultSize,
@@ -261,4 +261,4 @@ const Comp: React.FC<Props> = ({ inlongGroupId }) => {
);
};
-export default Comp;
+export default forwardRef(Comp);
diff --git a/inlong-dashboard/src/pages/AccessDetail/DataStream/StreamItemModal.tsx b/inlong-dashboard/src/pages/AccessDetail/DataStream/StreamItemModal.tsx
index 328c6a322..ccc38ee33 100644
--- a/inlong-dashboard/src/pages/AccessDetail/DataStream/StreamItemModal.tsx
+++ b/inlong-dashboard/src/pages/AccessDetail/DataStream/StreamItemModal.tsx
@@ -52,14 +52,6 @@ export const genFormContent = (currentValues, inlongGroupId, middlewareType) =>
'inlongStreamId',
'name',
'description',
- {
- type: (
- <Divider orientation="left">
- {i18n.t('pages.AccessCreate.DataStream.config.DataSources')}
- </Divider>
- ),
- },
- 'dataSourceType',
{
type: (
<Divider orientation="left">
diff --git a/inlong-dashboard/src/pages/AccessDetail/DataStream/config.tsx b/inlong-dashboard/src/pages/AccessDetail/DataStream/config.tsx
index 16e2db191..dbc1ac69b 100644
--- a/inlong-dashboard/src/pages/AccessDetail/DataStream/config.tsx
+++ b/inlong-dashboard/src/pages/AccessDetail/DataStream/config.tsx
@@ -21,7 +21,6 @@ import React from 'react';
import { Divider } from 'antd';
import i18n from '@/i18n';
import { genBusinessFields, genDataFields } from '@/components/AccessHelper';
-import { Storages } from '@/components/MetaData';
export const getFilterFormContent = (defaultValues = {} as any) => [
{
@@ -101,15 +100,6 @@ export const genFormContent = (
},
'name',
'description',
- {
- type: (
- <Divider orientation="left">
- {i18n.t('pages.AccessCreate.DataStream.config.DataSources')}
- </Divider>
- ),
- },
- 'dataSourceType',
- 'dataSourcesConfig',
{
type: (
<Divider orientation="left">
@@ -139,21 +129,21 @@ export const genFormContent = (
visible: middlewareType === 'PULSAR',
}),
),
- ...genDataFields(
- [
- {
- type: (
- <Divider orientation="left">
- {i18n.t('pages.AccessCreate.DataStream.config.DataStorages')}
- </Divider>
- ),
- },
- 'streamSink',
- ...Storages.map(item => `streamSink${item.value}`),
- ],
- currentValues,
- extraParams,
- ),
+ // ...genDataFields(
+ // [
+ // {
+ // type: (
+ // <Divider orientation="left">
+ // {i18n.t('pages.AccessCreate.DataStream.config.DataStorages')}
+ // </Divider>
+ // ),
+ // },
+ // 'streamSink',
+ // ...Storages.map(item => `streamSink${item.value}`),
+ // ],
+ // currentValues,
+ // extraParams,
+ // ),
].map(item => {
if (
(editingId === true && currentValues?.id === undefined) ||
diff --git a/inlong-dashboard/src/pages/AccessDetail/DataStream/index.tsx b/inlong-dashboard/src/pages/AccessDetail/DataStream/index.tsx
index d39044807..de16f4ce3 100644
--- a/inlong-dashboard/src/pages/AccessDetail/DataStream/index.tsx
+++ b/inlong-dashboard/src/pages/AccessDetail/DataStream/index.tsx
@@ -17,7 +17,7 @@
* under the License.
*/
-import React, { useState, useRef } from 'react';
+import React, { useState, useRef, useImperativeHandle, forwardRef } from 'react';
import ReactDom from 'react-dom';
import { Form, Collapse, Button, Empty, Modal, Space, message } from 'antd';
import FormGenerator, { FormItemContent } from '@/components/FormGenerator';
@@ -26,7 +26,6 @@ import { useRequest } from '@/hooks';
import request from '@/utils/request';
import { useTranslation } from 'react-i18next';
import { dataToValues, valuesToData } from '@/pages/AccessCreate/DataStream/helper';
-import { pickObject } from '@/utils';
import { CommonInterface } from '../common';
import StreamItemModal from './StreamItemModal';
import { getFilterFormContent, genExtraContent, genFormContent } from './config';
@@ -35,7 +34,7 @@ import styles from './index.module.less';
type Props = CommonInterface;
-const Comp: React.FC<Props> = ({ inlongGroupId, readonly, middlewareType }) => {
+const Comp = ({ inlongGroupId, readonly, middlewareType }: Props, ref) => {
const { t } = useTranslation();
const [form] = Form.useForm();
@@ -118,13 +117,10 @@ const Comp: React.FC<Props> = ({ inlongGroupId, readonly, middlewareType }) => {
const { list } = await getTouchedValues();
const values = list.find(item => item.id === record.id);
const data = valuesToData(values ? [values] : [], inlongGroupId);
- const submitData = data.map(item =>
- pickObject(['dbBasicInfo', 'fileBasicInfo', 'streamInfo'], item),
- );
await request({
url: '/stream/update',
method: 'POST',
- data: submitData?.[0]?.streamInfo,
+ data: data?.[0]?.streamInfo,
});
} else {
// create
@@ -132,9 +128,9 @@ const Comp: React.FC<Props> = ({ inlongGroupId, readonly, middlewareType }) => {
const values = list?.[0];
const data = valuesToData(values ? [values] : [], inlongGroupId);
await request({
- url: '/stream/saveAll',
+ url: '/stream/save',
method: 'POST',
- data: data?.[0],
+ data: data?.[0]?.streamInfo,
});
}
await getList();
@@ -142,6 +138,18 @@ const Comp: React.FC<Props> = ({ inlongGroupId, readonly, middlewareType }) => {
message.success(t('basic.OperatingSuccess'));
};
+ const onOk = () => {
+ if (editingId) {
+ return Promise.reject('Please save the data');
+ } else {
+ return Promise.resolve();
+ }
+ };
+
+ useImperativeHandle(ref, () => ({
+ onOk,
+ }));
+
const onEdit = record => {
// setEditingId(record.id);
// setActiveKey(index.toString());
@@ -149,6 +157,7 @@ const Comp: React.FC<Props> = ({ inlongGroupId, readonly, middlewareType }) => {
};
const onCancel = async () => {
+ setEditingId(false);
await getList();
};
@@ -324,4 +333,4 @@ const Comp: React.FC<Props> = ({ inlongGroupId, readonly, middlewareType }) => {
);
};
-export default Comp;
+export default forwardRef(Comp);
diff --git a/inlong-dashboard/src/pages/AccessDetail/Info/config.tsx b/inlong-dashboard/src/pages/AccessDetail/Info/config.tsx
index e339ccc51..190d7e54c 100644
--- a/inlong-dashboard/src/pages/AccessDetail/Info/config.tsx
+++ b/inlong-dashboard/src/pages/AccessDetail/Info/config.tsx
@@ -20,42 +20,55 @@
// import React from 'react';
import { genBusinessFields } from '@/components/AccessHelper';
-export const getFormContent = ({ editing, initialValues }) =>
- genBusinessFields(
- [
- 'middlewareType',
- 'inlongGroupId',
- 'mqResourceObj',
- 'name',
- 'cnName',
- 'inCharges',
- 'description',
- 'queueModule',
- 'topicPartitionNum',
- 'dailyRecords',
- 'dailyStorage',
- 'peakRecords',
- 'maxLength',
- // 'mqExtInfo.ensemble',
- 'mqExtInfo.writeQuorum',
- 'mqExtInfo.ackQuorum',
- 'mqExtInfo.retentionTime',
- 'mqExtInfo.ttl',
- 'mqExtInfo.retentionSize',
- ],
- initialValues,
- ).map(item => ({
- ...item,
- type: transType(editing, item, initialValues),
- suffix:
- typeof item.suffix === 'object' && !editing
- ? {
- ...item.suffix,
- type: 'text',
- }
- : item.suffix,
- extra: null,
- }));
+export const getFormContent = ({ editing, initialValues, isCreate, isUpdate }) => {
+ const keys = [
+ 'middlewareType',
+ !isCreate && 'inlongGroupId',
+ !isCreate && 'mqResourceObj',
+ 'name',
+ 'cnName',
+ 'inCharges',
+ 'description',
+ 'queueModule',
+ 'topicPartitionNum',
+ 'dailyRecords',
+ 'dailyStorage',
+ 'peakRecords',
+ 'maxLength',
+ // 'mqExtInfo.ensemble',
+ 'mqExtInfo.writeQuorum',
+ 'mqExtInfo.ackQuorum',
+ 'mqExtInfo.retentionTime',
+ 'mqExtInfo.ttl',
+ 'mqExtInfo.retentionSize',
+ ].filter(Boolean);
+
+ return isCreate
+ ? genBusinessFields(keys, initialValues).map(item => {
+ if (item.name === 'name' && isUpdate) {
+ return {
+ ...item,
+ props: {
+ ...item.props,
+ disabled: true,
+ },
+ };
+ }
+ return item;
+ })
+ : genBusinessFields(keys, initialValues).map(item => ({
+ ...item,
+ type: transType(editing, item, initialValues),
+ suffix:
+ typeof item.suffix === 'object' && !editing
+ ? {
+ ...item.suffix,
+ type: 'text',
+ }
+ : item.suffix,
+ extra: null,
+ }));
+};
function transType(editing: boolean, conf, initialValues) {
const arr = [
diff --git a/inlong-dashboard/src/pages/AccessDetail/Info/index.tsx b/inlong-dashboard/src/pages/AccessDetail/Info/index.tsx
index b0b1fc6c2..4cf602b7d 100644
--- a/inlong-dashboard/src/pages/AccessDetail/Info/index.tsx
+++ b/inlong-dashboard/src/pages/AccessDetail/Info/index.tsx
@@ -17,25 +17,33 @@
* under the License.
*/
-import React from 'react';
-import ReactDom from 'react-dom';
+import React, { useEffect, useMemo, useImperativeHandle, forwardRef } from 'react';
import { Button, Space, message } from 'antd';
import FormGenerator, { useForm } from '@/components/FormGenerator';
-import { useRequest, useBoolean } from '@/hooks';
+import { useRequest, useBoolean, useSelector } from '@/hooks';
import { useTranslation } from 'react-i18next';
import request from '@/utils/request';
+import { State } from '@/models';
import { CommonInterface } from '../common';
import { getFormContent } from './config';
type Props = CommonInterface;
-const Comp: React.FC<Props> = ({ inlongGroupId, isActive, readonly, extraRef }) => {
+const Comp = ({ inlongGroupId, readonly, isCreate }: Props, ref) => {
const { t } = useTranslation();
- const [editing, { setTrue, setFalse }] = useBoolean(false);
+ const [editing, { setTrue, setFalse }] = useBoolean(isCreate);
+
+ const { userName } = useSelector<State, State>(state => state);
const [form] = useForm();
+ const isUpdate = useMemo(() => {
+ return !!inlongGroupId;
+ }, [inlongGroupId]);
+
const { data, run: getData } = useRequest(`/group/get/${inlongGroupId}`, {
+ ready: isUpdate,
+ refreshDeps: [inlongGroupId],
formatResult: data => ({
...data,
inCharges: data.inCharges.split(','),
@@ -44,26 +52,50 @@ const Comp: React.FC<Props> = ({ inlongGroupId, isActive, readonly, extraRef })
onSuccess: data => form.setFieldsValue(data),
});
- const onSave = async () => {
+ const onOk = async () => {
const values = await form.validateFields();
const submitData = {
...values,
- inCharges: values.inCharges.join(','),
- followers: values.inCharges.join(','),
+ inCharges: values.inCharges?.join(','),
+ followers: values.followers?.join(','),
mqExtInfo: {
- ...data.mqExtInfo,
+ ...data?.mqExtInfo,
...values.mqExtInfo,
+ middlewareType: values.middlewareType,
},
};
- await request({
- url: '/group/update',
+
+ if (isUpdate) {
+ submitData.inlongGroupId = inlongGroupId;
+ }
+
+ const result = await request({
+ url: isUpdate ? '/group/update' : '/group/save',
method: 'POST',
- data: {
- ...data,
- ...submitData,
- },
+ data: submitData,
});
+
+ return {
+ ...values,
+ inlongGroupId: result,
+ };
+ };
+
+ useEffect(() => {
+ const values = {} as Record<string, unknown>;
+ if (!isUpdate) {
+ if (userName) values.inCharges = [userName];
+ form.setFieldsValue(values);
+ }
+ }, [isUpdate, form, userName]);
+
+ useImperativeHandle(ref, () => ({
+ onOk,
+ }));
+
+ const onSave = async () => {
+ await onOk();
await getData();
setFalse();
message.success(t('basic.OperatingSuccess'));
@@ -74,39 +106,38 @@ const Comp: React.FC<Props> = ({ inlongGroupId, isActive, readonly, extraRef })
setFalse();
};
- const Extra = () => {
- return editing ? (
- <Space>
- <Button type="primary" onClick={onSave}>
- {t('basic.Save')}
- </Button>
- <Button onClick={onCancel}>{t('basic.Cancel')}</Button>
- </Space>
- ) : (
- <Button type="primary" onClick={setTrue}>
- {t('basic.Edit')}
- </Button>
- );
- };
-
return (
- <>
+ <div style={{ position: 'relative' }}>
<FormGenerator
form={form}
content={getFormContent({
editing,
initialValues: data,
+ isCreate,
+ isUpdate,
})}
allValues={data}
useMaxWidth={600}
/>
- {isActive &&
- !readonly &&
- extraRef?.current &&
- ReactDom.createPortal(<Extra />, extraRef.current)}
- </>
+ {!isCreate && !readonly && (
+ <div style={{ position: 'absolute', top: 0, right: 0 }}>
+ {editing ? (
+ <Space>
+ <Button type="primary" onClick={onSave}>
+ {t('basic.Save')}
+ </Button>
+ <Button onClick={onCancel}>{t('basic.Cancel')}</Button>
+ </Space>
+ ) : (
+ <Button type="primary" onClick={setTrue}>
+ {t('basic.Edit')}
+ </Button>
+ )}
+ </div>
+ )}
+ </div>
);
};
-export default Comp;
+export default forwardRef(Comp);
diff --git a/inlong-dashboard/src/pages/AccessDetail/common.d.ts b/inlong-dashboard/src/pages/AccessDetail/common.d.ts
index 43a86dd86..50cc69c59 100644
--- a/inlong-dashboard/src/pages/AccessDetail/common.d.ts
+++ b/inlong-dashboard/src/pages/AccessDetail/common.d.ts
@@ -21,7 +21,6 @@ export interface CommonInterface {
inlongGroupId: string;
middlewareType: 'TUBE' | 'PULSAR';
readonly?: boolean;
- isActive?: boolean;
- // extraRef of Tab
- extraRef?: React.RefObject<HTMLDivElement>;
+ isCreate?: boolean;
+ ref?: React.RefObject<unknown>;
}
diff --git a/inlong-dashboard/src/pages/AccessDetail/index.tsx b/inlong-dashboard/src/pages/AccessDetail/index.tsx
index 0fe95453c..ab9b5e14f 100644
--- a/inlong-dashboard/src/pages/AccessDetail/index.tsx
+++ b/inlong-dashboard/src/pages/AccessDetail/index.tsx
@@ -17,11 +17,13 @@
* under the License.
*/
-import React, { useMemo, useState, useRef } from 'react';
-import { Tabs } from 'antd';
-import { PageContainer } from '@/components/PageContainer';
-import { useParams, useRequest } from '@/hooks';
+import React, { useMemo, useState, useRef, useEffect } from 'react';
+import { Tabs, Button, Card, message, Steps, Space } from 'antd';
+import { PageContainer, FooterToolbar } from '@/components/PageContainer';
+import { parse } from 'qs';
+import { useParams, useRequest, useSet, useHistory, useLocation } from '@/hooks';
import { useTranslation } from 'react-i18next';
+import request from '@/utils/request';
import Info from './Info';
import DataSources from './DataSources';
import DataStream from './DataStream';
@@ -30,16 +32,33 @@ import Audit from './Audit';
const Comp: React.FC = () => {
const { t } = useTranslation();
- const { id } = useParams<{ id: string }>();
+ const location = useLocation();
+ const history = useHistory();
+ const { id: groupId } = useParams<{ id: string }>();
+
+ const qs = parse(location.search.slice(1));
+
+ const [current, setCurrent] = useState(+qs.step || 0);
+ const [, { add: addOpened, has: hasOpened }] = useSet([current]);
+ const [confirmLoading, setConfirmLoading] = useState(false);
+ const [id, setId] = useState(groupId || '');
+
+ const childRef = useRef(null);
+ const [middlewareType, setMiddlewareType] = useState();
+
+ const [isCreate] = useState(location.pathname.indexOf('/access/create') === 0);
+
+ useEffect(() => {
+ if (!hasOpened(current)) addOpened(current);
+ }, [current, addOpened, hasOpened]);
const { data } = useRequest(`/group/get/${id}`, {
+ ready: !!id && !middlewareType,
refreshDeps: [id],
+ onSuccess: result => setMiddlewareType(result.middlewareType),
});
- const extraRef = useRef<HTMLDivElement>();
-
const isReadonly = useMemo(() => [0, 101, 102].includes(data?.status), [data]);
- const middlewareType = data?.middlewareType;
const list = useMemo(
() =>
@@ -58,45 +77,138 @@ const Comp: React.FC = () => {
label: t('pages.AccessDetail.DataSources'),
value: 'dataSources',
content: DataSources,
- hidden: isReadonly,
},
{
label: t('pages.AccessDetail.DataStorages'),
value: 'streamSink',
content: DataStorage,
- hidden: isReadonly,
},
{
label: t('pages.AccessDetail.Audit'),
value: 'audit',
content: Audit,
- hidden: isReadonly,
+ hidden: isReadonly || isCreate,
},
].filter(item => !item.hidden),
- [isReadonly, t],
+ [isReadonly, isCreate, t],
);
- const [actived, setActived] = useState(list[0].value);
+ const onOk = async current => {
+ const onOk = childRef?.current?.onOk;
+
+ setConfirmLoading(true);
+ try {
+ const result = onOk && (await onOk());
+ if (current === 0) {
+ setMiddlewareType(result.middlewareType);
+ setId(result.inlongGroupId);
+ }
+ history.push({
+ pathname: `/access/create/${result?.inlongGroupId || id}`,
+ search: `?step=${current + 1}`,
+ });
+ } finally {
+ setConfirmLoading(false);
+ }
+ };
+
+ const onSubmit = async () => {
+ await request({
+ url: `/group/startProcess/${id}`,
+ method: 'POST',
+ });
+ message.success(t('pages.AccessCreate.SubmittedSuccessfully'));
+ history.push('/access');
+ };
+
+ const Footer = () => (
+ <Space style={{ display: 'flex', justifyContent: 'center' }}>
+ {current > 0 && (
+ <Button disabled={confirmLoading} onClick={() => setCurrent(current - 1)}>
+ {t('pages.AccessCreate.Previous')}
+ </Button>
+ )}
+ {current !== list.length - 1 && (
+ <Button
+ type="primary"
+ loading={confirmLoading}
+ onClick={async () => {
+ await onOk(current).catch(err => {
+ if (err?.errorFields?.length) {
+ message.error(t('pages.AccessCreate.CheckFormIntegrity'));
+ }
+ return Promise.reject(err);
+ });
+
+ const newCurrent = current + 1;
+ setCurrent(newCurrent);
+ }}
+ >
+ {t('pages.AccessCreate.NextStep')}
+ </Button>
+ )}
+ {current === list.length - 1 && (
+ <Button type="primary" onClick={onSubmit}>
+ {t('pages.AccessCreate.Submit')}
+ </Button>
+ )}
+ <Button onClick={() => history.push('/access')}>{t('pages.AccessCreate.Back')}</Button>
+ </Space>
+ );
+
+ const Div = isCreate ? Card : Tabs;
return (
- <PageContainer breadcrumb={[{ name: `${t('pages.AccessDetail.BusinessDetail')}${id}` }]}>
- <Tabs
- activeKey={actived}
- onChange={val => setActived(val)}
- tabBarExtraContent={<div ref={extraRef} />}
- >
- {list.map(({ content: Content, ...item }) => (
- <Tabs.TabPane tab={item.label} key={item.value}>
- <Content
- inlongGroupId={id}
- isActive={actived === item.value}
- readonly={isReadonly}
- extraRef={extraRef}
- middlewareType={middlewareType}
- />
- </Tabs.TabPane>
- ))}
- </Tabs>
+ <PageContainer
+ breadcrumb={[
+ {
+ name: isCreate
+ ? t('pages.AccessCreate.NewAccess')
+ : `${t('pages.AccessDetail.BusinessDetail')}${id}`,
+ },
+ ]}
+ useDefaultContainer={!isCreate}
+ >
+ {isCreate && (
+ <Steps
+ current={current}
+ size="small"
+ style={{ marginBottom: 20, width: 600 }}
+ onChange={c => setCurrent(c)}
+ >
+ {list.map(item => (
+ <Steps.Step key={item.label} title={item.label} />
+ ))}
+ </Steps>
+ )}
+
+ <Div>
+ {list.map(({ content: Content, ...item }, index) => {
+ // Lazy load the content of the step, and at the same time make the loaded useCache content not destroy
+ const child =
+ !isCreate || hasOpened(index) ? (
+ <Content
+ inlongGroupId={id}
+ readonly={isReadonly}
+ middlewareType={middlewareType}
+ isCreate={isCreate}
+ ref={index === current ? childRef : null}
+ />
+ ) : null;
+
+ return isCreate ? (
+ <div key={item.label} style={{ display: `${index === current ? 'block' : 'none'}` }}>
+ {child}
+ </div>
+ ) : (
+ <Tabs.TabPane tab={item.label} key={item.value}>
+ {child}
+ </Tabs.TabPane>
+ );
+ })}
+ </Div>
+
+ {isCreate && <FooterToolbar extra={<Footer />} />}
</PageContainer>
);
};