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 2021/11/27 08:57:20 UTC

[incubator-inlong] branch master updated: [INLONG-1834] Access support pulsar (#1843)

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 b2cdb1a  [INLONG-1834] Access support pulsar (#1843)
b2cdb1a is described below

commit b2cdb1a756b4f1f6fb01712da0ec8d3a47d569f3
Author: Daniel <le...@outlook.com>
AuthorDate: Sat Nov 27 16:57:13 2021 +0800

    [INLONG-1834] Access support pulsar (#1843)
---
 .../AccessHelper/FieldsConfig/businessFields.tsx   | 228 ++++++++++++++++++++-
 .../AccessHelper/FieldsConfig/dataFields.tsx       |  35 ++--
 .../src/pages/AccessCreate/Business/config.tsx     |  89 +++++---
 .../src/pages/AccessCreate/Business/index.tsx      |  12 +-
 .../src/pages/AccessCreate/DataStream/config.tsx   |  99 ++++++---
 .../src/pages/AccessCreate/DataStream/helper.ts    |   1 +
 .../src/pages/AccessCreate/DataStream/index.tsx    |   4 +-
 inlong-website/src/pages/AccessCreate/index.tsx    |  22 +-
 .../pages/AccessDashboard/ExecutionLogModal.tsx    |   2 +-
 .../AccessDetail/DataStream/StreamItemModal.tsx    |  75 ++++---
 .../src/pages/AccessDetail/DataStream/config.tsx   | 115 ++++++++---
 .../src/pages/AccessDetail/DataStream/index.tsx    |  14 +-
 .../src/pages/AccessDetail/Info/config.tsx         |  86 +++++---
 .../src/pages/AccessDetail/Info/index.tsx          |   4 +
 inlong-website/src/pages/AccessDetail/common.d.ts  |   1 +
 inlong-website/src/pages/AccessDetail/index.tsx    |   6 +-
 16 files changed, 618 insertions(+), 175 deletions(-)

diff --git a/inlong-website/src/components/AccessHelper/FieldsConfig/businessFields.tsx b/inlong-website/src/components/AccessHelper/FieldsConfig/businessFields.tsx
index 0f73f01..a51bf75 100644
--- a/inlong-website/src/components/AccessHelper/FieldsConfig/businessFields.tsx
+++ b/inlong-website/src/components/AccessHelper/FieldsConfig/businessFields.tsx
@@ -23,7 +23,10 @@ import { FormItemProps } from '@/components/FormGenerator';
 import { pickObjectArray } from '@/utils';
 import i18n from '@/i18n';
 
-export default (names: string[], currentValues: Record<string, unknown> = {}): FormItemProps[] => {
+export default (
+  names: (string | FormItemProps)[],
+  currentValues: Record<string, any> = {},
+): FormItemProps[] => {
   const fields: FormItemProps[] = [
     {
       type: 'text',
@@ -96,13 +99,50 @@ export default (names: string[], currentValues: Record<string, unknown> = {}): F
       props: {
         options: [
           {
-            label: i18n.t('components.AccessHelper.FieldsConfig.businessFields.Tube'),
+            label: 'TUBE',
             value: 'TUBE',
           },
+          {
+            label: 'PULSAR',
+            value: 'PULSAR',
+          },
         ],
       },
     },
     {
+      type: 'radio',
+      label: i18n.t('components.AccessHelper.FieldsConfig.businessFields.QueueModule'),
+      name: 'queueModule',
+      initialValue: currentValues.queueModule ?? 'parallel',
+      rules: [{ required: true }],
+      props: {
+        options: [
+          {
+            label: i18n.t('components.AccessHelper.FieldsConfig.businessFields.Parallel'),
+            value: 'parallel',
+          },
+          {
+            label: i18n.t('components.AccessHelper.FieldsConfig.businessFields.Serial'),
+            value: 'serial',
+          },
+        ],
+      },
+      visible: values => values.middlewareType === 'PULSAR',
+    },
+    {
+      type: 'inputnumber',
+      label: 'Topic Partition Nums',
+      name: 'topicPartitionNum',
+      initialValue: currentValues.topicPartitionNum ?? 3,
+      rules: [{ required: true }],
+      props: {
+        min: 1,
+        max: 20,
+        precision: 0,
+      },
+      visible: values => values.middlewareType === 'PULSAR' && values.queueModule === 'parallel',
+    },
+    {
       type: 'inputnumber',
       label: i18n.t('components.AccessHelper.FieldsConfig.businessFields.NumberOfAccess'),
       name: 'dailyRecords',
@@ -113,6 +153,7 @@ export default (names: string[], currentValues: Record<string, unknown> = {}): F
         min: 1,
         precision: 0,
       },
+      visible: values => values.middlewareType === 'TUBE',
     },
     {
       type: 'inputnumber',
@@ -125,6 +166,7 @@ export default (names: string[], currentValues: Record<string, unknown> = {}): F
         min: 1,
         precision: 0,
       },
+      visible: values => values.middlewareType === 'TUBE',
     },
     {
       type: 'inputnumber',
@@ -137,6 +179,7 @@ export default (names: string[], currentValues: Record<string, unknown> = {}): F
         min: 1,
         precision: 0,
       },
+      visible: values => values.middlewareType === 'TUBE',
     },
     {
       type: 'inputnumber',
@@ -149,6 +192,187 @@ export default (names: string[], currentValues: Record<string, unknown> = {}): F
         min: 1,
         precision: 0,
       },
+      visible: values => values.middlewareType === 'TUBE',
+    },
+    {
+      type: 'inputnumber',
+      label: 'ensemble',
+      name: 'mqExtInfo.ensemble',
+      initialValue: currentValues.mqExtInfo?.ensemble ?? 3,
+      suffix: i18n.t('components.AccessHelper.FieldsConfig.businessFields.EnsembleSuffix'),
+      extra: i18n.t('components.AccessHelper.FieldsConfig.businessFields.EnsembleExtra'),
+      rules: [
+        ({ getFieldValue }) => ({
+          validator(_, val) {
+            if (val) {
+              const writeQuorum = getFieldValue(['mqExtInfo', 'writeQuorum']) || 0;
+              const ackQuorum = getFieldValue(['mqExtInfo', 'ackQuorum']) || 0;
+              const ensemble = val || 0;
+              return ackQuorum <= writeQuorum && writeQuorum <= ensemble
+                ? Promise.resolve()
+                : Promise.reject(new Error('Max match: ensemble ≥ write quorum ≥ ack quorum'));
+            }
+            return Promise.resolve();
+          },
+        }),
+      ],
+      props: {
+        min: 1,
+        max: 10,
+        precision: 0,
+      },
+      visible: values => values.middlewareType === 'PULSAR',
+    },
+    {
+      type: 'inputnumber',
+      label: 'write quorum',
+      name: 'mqExtInfo.writeQuorum',
+      initialValue: currentValues.mqExtInfo?.writeQuorum ?? 3,
+      suffix: i18n.t('components.AccessHelper.FieldsConfig.businessFields.WriteQuorumSuffix'),
+      extra: i18n.t('components.AccessHelper.FieldsConfig.businessFields.WriteQuorumExtra'),
+      props: {
+        min: 1,
+        max: 10,
+        precision: 0,
+      },
+      visible: values => values.middlewareType === 'PULSAR',
+    },
+    {
+      type: 'inputnumber',
+      label: 'ack quorum',
+      name: 'mqExtInfo.ackQuorum',
+      initialValue: currentValues.mqExtInfo?.ackQuorum ?? 2,
+      suffix: i18n.t('components.AccessHelper.FieldsConfig.businessFields.AckQuorumSuffix'),
+      extra: i18n.t('components.AccessHelper.FieldsConfig.businessFields.AckQuorumExtra'),
+      props: {
+        min: 1,
+        max: 10,
+        precision: 0,
+      },
+      visible: values => values.middlewareType === 'PULSAR',
+    },
+    {
+      type: 'inputnumber',
+      label: 'retention time',
+      name: 'mqExtInfo.retentionTime',
+      initialValue: currentValues.mqExtInfo?.retentionTime ?? 72,
+      rules: [
+        ({ getFieldValue }) => ({
+          validator(_, val) {
+            const retentionSize = getFieldValue(['mqExtInfo', 'retentionSize']);
+            if ((val === 0 && retentionSize > 0) || (val > 0 && retentionSize === 0)) {
+              return Promise.reject(
+                new Error(
+                  'Can not: retentionTime=0,retentionSize>0 | retentionTime>0,retentionSize=0',
+                ),
+              );
+            }
+            if (val) {
+              const unit = getFieldValue(['mqExtInfo', 'retentionTimeUnit']);
+              const value = unit === 'hours' ? Math.ceil(val / 24) : val;
+              return value <= 14 ? Promise.resolve() : Promise.reject(new Error('Max: 14 Days'));
+            }
+            return Promise.resolve();
+          },
+        }),
+      ],
+      suffix: {
+        type: 'select',
+        name: 'mqExtInfo.retentionTimeUnit',
+        initialValue: currentValues.rmqExtInfo?.etentionTimeUnit ?? 'hours',
+        props: {
+          options: [
+            {
+              label: 'D',
+              value: 'days',
+            },
+            {
+              label: 'H',
+              value: 'hours',
+            },
+          ],
+        },
+      },
+      extra: i18n.t('components.AccessHelper.FieldsConfig.businessFields.RetentionTimeExtra'),
+      props: {
+        min: -1,
+        precision: 0,
+      },
+      visible: values => values.middlewareType === 'PULSAR',
+    },
+    {
+      type: 'inputnumber',
+      label: 'ttl',
+      name: 'mqExtInfo.ttl',
+      initialValue: currentValues.mqExtInfo?.ttl ?? 24,
+      rules: [
+        ({ getFieldValue }) => ({
+          validator(_, val) {
+            if (val) {
+              const unit = getFieldValue(['mqExtInfo', 'ttlUnit']);
+              const value = unit === 'hours' ? Math.ceil(val / 24) : val;
+              return value <= 14 ? Promise.resolve() : Promise.reject(new Error('Max: 14 Days'));
+            }
+            return Promise.resolve();
+          },
+        }),
+      ],
+      suffix: {
+        type: 'select',
+        name: 'mqExtInfo.ttlUnit',
+        initialValue: currentValues.mqExtInfo?.ttlUnit ?? 'hours',
+        props: {
+          options: [
+            {
+              label: 'D',
+              value: 'days',
+            },
+            {
+              label: 'H',
+              value: 'hours',
+            },
+          ],
+        },
+      },
+      extra: i18n.t('components.AccessHelper.FieldsConfig.businessFields.TtlExtra'),
+      props: {
+        min: 1,
+        precision: 0,
+      },
+      visible: values => values.middlewareType === 'PULSAR',
+    },
+    {
+      type: 'inputnumber',
+      label: 'retention size',
+      name: 'mqExtInfo.retentionSize',
+      initialValue: currentValues.mqExtInfo?.retentionSize ?? -1,
+      suffix: {
+        type: 'select',
+        name: 'mqExtInfo.retentionSizeUnit',
+        initialValue: currentValues.mqExtInfo?.retentionSizeUnit ?? 'MB',
+        props: {
+          options: [
+            {
+              label: 'MB',
+              value: 'MB',
+            },
+            {
+              label: 'GB',
+              value: 'GB',
+            },
+            {
+              label: 'TB',
+              value: 'TB',
+            },
+          ],
+        },
+      },
+      extra: i18n.t('components.AccessHelper.FieldsConfig.businessFields.RetentionSizeExtra'),
+      props: {
+        min: -1,
+        precision: 0,
+      },
+      visible: values => values.middlewareType === 'PULSAR',
     },
   ] as FormItemProps[];
 
diff --git a/inlong-website/src/components/AccessHelper/FieldsConfig/dataFields.tsx b/inlong-website/src/components/AccessHelper/FieldsConfig/dataFields.tsx
index 9c2e724..5793489 100644
--- a/inlong-website/src/components/AccessHelper/FieldsConfig/dataFields.tsx
+++ b/inlong-website/src/components/AccessHelper/FieldsConfig/dataFields.tsx
@@ -39,7 +39,7 @@ type RestParams = {
 };
 
 export default (
-  names: string[],
+  names: (string | FormItemProps)[],
   currentValues: Record<string, any> = {},
   {
     inlongGroupId,
@@ -174,16 +174,12 @@ export default (
     {
       type: 'select',
       label: i18n.t('components.AccessHelper.FieldsConfig.dataFields.fileDelimiter'),
-      name: 'fileDelimiter',
-      initialValue: '9',
+      name: 'dataSeparator',
+      initialValue: '124',
       props: {
         dropdownMatchSelectWidth: false,
         options: [
           {
-            label: 'TAB',
-            value: '9',
-          },
-          {
             label: i18n.t('components.AccessHelper.FieldsConfig.dataFields.VerticalLine'),
             value: '124',
           },
@@ -208,18 +204,21 @@ export default (
             value: '59',
           },
         ],
+        useInput: true,
+        useInputProps: {
+          placeholder: 'ASCII',
+        },
+        style: { width: 100 },
       },
-      rules: [{ required: true }],
-      suffix: {
-        type: 'input',
-        name: 'fileDelimiterDetail',
-        rules: [
-          {
-            required: true,
-          },
-        ],
-        visible: values => values.fileDelimiter === 'ASCII',
-      },
+      rules: [
+        {
+          required: true,
+          type: 'number',
+          transform: val => +val,
+          min: 0,
+          max: 127,
+        },
+      ],
       visible: values => values.dataSourceType === 'FILE' || values.dataSourceType === 'AUTO_PUSH',
     },
     {
diff --git a/inlong-website/src/pages/AccessCreate/Business/config.tsx b/inlong-website/src/pages/AccessCreate/Business/config.tsx
index 3d8d372..847520f 100644
--- a/inlong-website/src/pages/AccessCreate/Business/config.tsx
+++ b/inlong-website/src/pages/AccessCreate/Business/config.tsx
@@ -23,32 +23,69 @@ import i18n from '@/i18n';
 import { genBusinessFields } from '@/components/AccessHelper';
 
 export const getFormContent = ({ changedValues, isUpdate }) =>
-  [
-    {
-      type: (
-        <Divider orientation="left">
-          {i18n.t('pages.AccessCreate.Business.config.BusinessInformation')}
-        </Divider>
-      ),
-    },
-    ...genBusinessFields(['name', 'cnName', 'inCharges', 'description'], changedValues),
-    {
-      type: (
-        <Divider orientation="left">
-          {i18n.t('pages.AccessCreate.Business.config.AccessRequirements')}
-        </Divider>
-      ),
-    },
-    ...genBusinessFields(['middlewareType']),
-    {
-      type: (
-        <Divider orientation="left">
-          {i18n.t('pages.AccessCreate.Business.config.AccessScale')}
-        </Divider>
-      ),
-    },
-    ...genBusinessFields(['dailyRecords', 'dailyStorage', 'peakRecords', 'maxLength']),
-  ].map(item => {
+  genBusinessFields(
+    [
+      {
+        type: (
+          <Divider orientation="left">
+            {i18n.t('pages.AccessCreate.Business.config.AccessRequirements')}
+          </Divider>
+        ),
+      },
+      'middlewareType',
+      'queueModule',
+      'topicPartitionNum',
+      {
+        type: (
+          <Divider orientation="left">
+            {i18n.t('pages.AccessCreate.Business.config.BusinessInformation')}
+          </Divider>
+        ),
+      },
+      'bgName',
+      'productId',
+      'name',
+      'cnName',
+      'inCharges',
+      'followers',
+      'description',
+      {
+        type: (
+          <Divider orientation="left">
+            {i18n.t('pages.AccessCreate.Business.config.AccessScale')}
+          </Divider>
+        ),
+        visible: values => values.middlewareType === 'TUBE',
+      },
+      'dailyRecords',
+      'dailyStorage',
+      'peakRecords',
+      'maxLength',
+      {
+        type: (
+          <Divider orientation="left">
+            {i18n.t('components.AccessHelper.FieldsConfig.businessFields.DataCopyTitle')}
+          </Divider>
+        ),
+        visible: values => values.middlewareType === 'PULSAR',
+      },
+      // 'mqExtInfo.ensemble',
+      'mqExtInfo.writeQuorum',
+      'mqExtInfo.ackQuorum',
+      {
+        type: (
+          <Divider orientation="left">
+            {i18n.t('components.AccessHelper.FieldsConfig.businessFields.DataStoragePeriodTitle')}
+          </Divider>
+        ),
+        visible: values => values.middlewareType === 'PULSAR',
+      },
+      'mqExtInfo.retentionTime',
+      'mqExtInfo.ttl',
+      'mqExtInfo.retentionSize',
+    ],
+    changedValues,
+  ).map(item => {
     const obj = { ...item };
     if (isUpdate && obj.name === 'name') {
       obj.props = {
diff --git a/inlong-website/src/pages/AccessCreate/Business/index.tsx b/inlong-website/src/pages/AccessCreate/Business/index.tsx
index 45079ba..1febbb2 100644
--- a/inlong-website/src/pages/AccessCreate/Business/index.tsx
+++ b/inlong-website/src/pages/AccessCreate/Business/index.tsx
@@ -34,7 +34,7 @@ const Comp = ({ inlongGroupId }: Props, ref) => {
 
   const { userName } = useSelector<State, State>(state => state);
 
-  const [changedValues, setChangedValues] = useState<Record<string, unknown>>({});
+  const [changedValues, setChangedValues] = useState<Record<string, any>>({});
 
   const isUpdate = useMemo(() => {
     return !!inlongGroupId;
@@ -61,10 +61,15 @@ const Comp = ({ inlongGroupId }: Props, ref) => {
       ...values,
       inCharges: values.inCharges?.join(','),
       followers: values.followers?.join(','),
+      mqExtInfo: {
+        ...values.mqExtInfo,
+        middlewareType: values.middlewareType,
+      },
     };
 
     if (isUpdate) {
       data.inlongGroupId = inlongGroupId;
+      if (changedValues.mqExtInfo?.id) data.mqExtInfo.id = changedValues.mqExtInfo.id;
     }
 
     const result = await request({
@@ -72,7 +77,10 @@ const Comp = ({ inlongGroupId }: Props, ref) => {
       method: 'POST',
       data,
     });
-    return result;
+    return {
+      ...values,
+      inlongGroupId: result,
+    };
   };
 
   useEffect(() => {
diff --git a/inlong-website/src/pages/AccessCreate/DataStream/config.tsx b/inlong-website/src/pages/AccessCreate/DataStream/config.tsx
index 7bf9fc1..3be4633 100644
--- a/inlong-website/src/pages/AccessCreate/DataStream/config.tsx
+++ b/inlong-website/src/pages/AccessCreate/DataStream/config.tsx
@@ -20,51 +20,86 @@
 import React from 'react';
 import { Divider } from 'antd';
 import i18n from '@/i18n';
-import { genDataFields } from '@/components/AccessHelper';
+import { genBusinessFields, genDataFields } from '@/components/AccessHelper';
 
-export const genFormContent = (currentValues, inlongGroupId) => {
+export const genFormContent = (currentValues, inlongGroupId, middlewareType) => {
   const extraParams = {
     inlongGroupId: inlongGroupId,
   };
 
   return [
-    {
-      type: (
-        <Divider orientation="left">{i18n.t('pages.AccessCreate.DataStream.config.Basic')}</Divider>
-      ),
-    },
     ...genDataFields(
-      ['inlongStreamId', 'name', 'inCharges', 'description'],
+      [
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.DataStream.config.Basic')}
+            </Divider>
+          ),
+        },
+        'inlongStreamId',
+        'name',
+        'inCharges',
+        'description',
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.DataStream.config.DataSources')}
+            </Divider>
+          ),
+        },
+        'dataSourceType',
+        // 'hasHigher',
+        // 'isHybridSource',
+        // 'isTableMapping',
+        // 'dateOffset',
+        // 'havePredefinedFields',
+        // 'predefinedFields',
+        'dataSourcesConfig',
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.DataStream.config.DataInfo')}
+            </Divider>
+          ),
+        },
+        'dataType',
+        'dataEncoding',
+        'dataSeparator',
+        'rowTypeFields',
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.Business.config.AccessScale')}
+            </Divider>
+          ),
+          visible: middlewareType === 'PULSAR',
+        },
+      ],
       currentValues,
       extraParams,
     ),
-    {
-      type: (
-        <Divider orientation="left">
-          {i18n.t('pages.AccessCreate.DataStream.config.DataSources')}
-        </Divider>
-      ),
-    },
-    ...genDataFields(['dataSourceType', 'dataSourcesConfig'], currentValues, extraParams),
-    {
-      type: (
-        <Divider orientation="left">
-          {i18n.t('pages.AccessCreate.DataStream.config.DataInfo')}
-        </Divider>
-      ),
-    },
+    ...genBusinessFields(['dailyRecords', 'dailyStorage', 'peakRecords', 'maxLength']).map(
+      item => ({
+        ...item,
+        visible: middlewareType === 'PULSAR',
+      }),
+    ),
     ...genDataFields(
-      ['dataType', 'dataEncoding', 'fileDelimiter', 'rowTypeFields'],
+      [
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.DataStream.config.DataStorages')}
+            </Divider>
+          ),
+        },
+        'dataStorage',
+        'dataStorageHIVE',
+        'dataStorageCLICK_HOUSE',
+      ],
       currentValues,
       extraParams,
     ),
-    {
-      type: (
-        <Divider orientation="left">
-          {i18n.t('pages.AccessCreate.DataStream.config.DataStorages')}
-        </Divider>
-      ),
-    },
-    ...genDataFields(['dataStorage', 'dataStorageHIVE'], currentValues, extraParams),
   ];
 };
diff --git a/inlong-website/src/pages/AccessCreate/DataStream/helper.ts b/inlong-website/src/pages/AccessCreate/DataStream/helper.ts
index 4d87664..0c0ce23 100644
--- a/inlong-website/src/pages/AccessCreate/DataStream/helper.ts
+++ b/inlong-website/src/pages/AccessCreate/DataStream/helper.ts
@@ -133,6 +133,7 @@ export const dataToValues = data => {
     );
 
     output = {
+      hasHigher: false,
       ...output,
       ...fieldList,
       ...streamInfo,
diff --git a/inlong-website/src/pages/AccessCreate/DataStream/index.tsx b/inlong-website/src/pages/AccessCreate/DataStream/index.tsx
index 26cf9f4..2c77d46 100644
--- a/inlong-website/src/pages/AccessCreate/DataStream/index.tsx
+++ b/inlong-website/src/pages/AccessCreate/DataStream/index.tsx
@@ -29,9 +29,10 @@ import { valuesToData, dataToValues } from './helper';
 
 export interface Props {
   inlongGroupId: string;
+  middlewareType: string;
 }
 
-const Comp = ({ inlongGroupId }: Props, ref) => {
+const Comp = ({ inlongGroupId, middlewareType }: Props, ref) => {
   const [form] = Form.useForm();
 
   const { t } = useTranslation();
@@ -151,6 +152,7 @@ const Comp = ({ inlongGroupId }: Props, ref) => {
                           inCharges: [userName],
                         },
                         inlongGroupId,
+                        middlewareType,
                       ).map(item => {
                         const obj = { ...item } as any;
                         if (obj.name) {
diff --git a/inlong-website/src/pages/AccessCreate/index.tsx b/inlong-website/src/pages/AccessCreate/index.tsx
index de9c312..77bfe4d 100644
--- a/inlong-website/src/pages/AccessCreate/index.tsx
+++ b/inlong-website/src/pages/AccessCreate/index.tsx
@@ -21,7 +21,7 @@ import React, { useState, useRef } from 'react';
 import { Button, Card, message, Steps, Space } from 'antd';
 import { parse } from 'qs';
 import { PageContainer, Container, FooterToolbar } from '@/components/PageContainer';
-import { useHistory, useLocation, useSet } from '@/hooks';
+import { useHistory, useLocation, useSet, useRequest } from '@/hooks';
 import { useTranslation } from 'react-i18next';
 import Business from './Business';
 import DataStream from './DataStream';
@@ -45,6 +45,13 @@ const Create: React.FC = () => {
   const businessRef = useRef(null);
   const dataStreamRef = useRef(null);
 
+  const [middlewareType, setMiddlewareType] = useState();
+
+  useRequest(`/business/get/${inlongGroupId}`, {
+    ready: !!inlongGroupId && !middlewareType,
+    onSuccess: result => setMiddlewareType(result.middlewareType),
+  });
+
   const steps = [
     {
       title: t('pages.AccessCreate.BusinessInfo'),
@@ -53,8 +60,14 @@ const Create: React.FC = () => {
       ref: businessRef,
     },
     {
-      title: t('pages.AccessCreate.DataStreams'),
-      content: <DataStream ref={dataStreamRef} inlongGroupId={inlongGroupId} />,
+      title: middlewareType === 'PULSAR' ? 'TOPIC' : t('pages.AccessCreate.DataStreams'),
+      content: (
+        <DataStream
+          ref={dataStreamRef}
+          inlongGroupId={inlongGroupId}
+          middlewareType={middlewareType}
+        />
+      ),
       useCache: true,
       ref: dataStreamRef,
     },
@@ -67,7 +80,8 @@ const Create: React.FC = () => {
     try {
       const result = onOk && (await onOk());
       if (current === 0) {
-        setGroupId(result);
+        setMiddlewareType(result.middlewareType);
+        setGroupId(result.inlongGroupId);
         history.push({
           search: `?inlongGroupId=${result}&step=1`,
         });
diff --git a/inlong-website/src/pages/AccessDashboard/ExecutionLogModal.tsx b/inlong-website/src/pages/AccessDashboard/ExecutionLogModal.tsx
index 31ce74a..ec6677f 100644
--- a/inlong-website/src/pages/AccessDashboard/ExecutionLogModal.tsx
+++ b/inlong-website/src/pages/AccessDashboard/ExecutionLogModal.tsx
@@ -81,7 +81,7 @@ const Comp: React.FC<Props> = ({ inlongGroupId, ...modalProps }) => {
         },
       });
     },
-    [getData, inlongGroupId],
+    [getData, inlongGroupId, t],
   );
 
   useUpdateEffect(() => {
diff --git a/inlong-website/src/pages/AccessDetail/DataStream/StreamItemModal.tsx b/inlong-website/src/pages/AccessDetail/DataStream/StreamItemModal.tsx
index bcfa063..501194c 100644
--- a/inlong-website/src/pages/AccessDetail/DataStream/StreamItemModal.tsx
+++ b/inlong-website/src/pages/AccessDetail/DataStream/StreamItemModal.tsx
@@ -23,7 +23,7 @@ import { ModalProps } from 'antd/es/modal';
 import FormGenerator, { useForm } from '@/components/FormGenerator';
 import { useUpdateEffect } from '@/hooks';
 import i18n from '@/i18n';
-import { genDataFields } from '@/components/AccessHelper';
+import { genBusinessFields, genDataFields } from '@/components/AccessHelper';
 import request from '@/utils/request';
 import { valuesToData } from '@/pages/AccessCreate/DataStream/helper';
 import { pickObject } from '@/utils';
@@ -31,40 +31,63 @@ import { pickObject } from '@/utils';
 export interface Props extends ModalProps {
   inlongGroupId: string;
   record?: Record<string, any>;
+  middlewareType: string;
 }
 
-export const genFormContent = (currentValues, inlongGroupId) => {
+export const genFormContent = (currentValues, inlongGroupId, middlewareType) => {
   const extraParams = {
     inlongGroupId,
   };
 
   return [
-    {
-      type: (
-        <Divider orientation="left">{i18n.t('pages.AccessCreate.DataStream.config.Basic')}</Divider>
-      ),
-    },
     ...genDataFields(
-      ['inlongStreamId', 'name', 'inCharges', 'description'],
+      [
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.DataStream.config.Basic')}
+            </Divider>
+          ),
+        },
+        'inlongStreamId',
+        'name',
+        'inCharges',
+        'description',
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.DataStream.config.DataSources')}
+            </Divider>
+          ),
+        },
+        'dataSourceType',
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.DataStream.config.DataInfo')}
+            </Divider>
+          ),
+        },
+        'dataType',
+        'rowTypeFields',
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.Business.config.AccessScale')}
+            </Divider>
+          ),
+          visible: middlewareType === 'PULSAR',
+        },
+      ],
       currentValues,
       extraParams,
     ),
-    {
-      type: (
-        <Divider orientation="left">
-          {i18n.t('pages.AccessCreate.DataStream.config.DataSources')}
-        </Divider>
-      ),
-    },
-    ...genDataFields(['dataSourceType'], currentValues, extraParams),
-    {
-      type: (
-        <Divider orientation="left">
-          {i18n.t('pages.AccessCreate.DataStream.config.DataInfo')}
-        </Divider>
-      ),
-    },
-    ...genDataFields(['dataType', 'rowTypeFields'], currentValues, extraParams),
+    ...genBusinessFields(['dailyRecords', 'dailyStorage', 'peakRecords', 'maxLength']).map(
+      item => ({
+        ...item,
+        visible: middlewareType === 'PULSAR',
+      }),
+    ),
   ].map(item => {
     const obj = { ...item };
 
@@ -76,7 +99,7 @@ export const genFormContent = (currentValues, inlongGroupId) => {
   });
 };
 
-const Comp: React.FC<Props> = ({ inlongGroupId, record, ...modalProps }) => {
+const Comp: React.FC<Props> = ({ inlongGroupId, record, middlewareType, ...modalProps }) => {
   const [form] = useForm();
   const onOk = async () => {
     const values = {
@@ -117,7 +140,7 @@ const Comp: React.FC<Props> = ({ inlongGroupId, record, ...modalProps }) => {
       <FormGenerator
         labelCol={{ span: 4 }}
         wrapperCol={{ span: 20 }}
-        content={genFormContent(record, inlongGroupId)}
+        content={genFormContent(record, inlongGroupId, middlewareType)}
         form={form}
         useMaxWidth
       />
diff --git a/inlong-website/src/pages/AccessDetail/DataStream/config.tsx b/inlong-website/src/pages/AccessDetail/DataStream/config.tsx
index efd3f25..481a104 100644
--- a/inlong-website/src/pages/AccessDetail/DataStream/config.tsx
+++ b/inlong-website/src/pages/AccessDetail/DataStream/config.tsx
@@ -20,7 +20,7 @@
 import React from 'react';
 import { Divider } from 'antd';
 import i18n from '@/i18n';
-import { genDataFields } from '@/components/AccessHelper';
+import { genBusinessFields, genDataFields } from '@/components/AccessHelper';
 
 export const getFilterFormContent = (defaultValues = {} as any) => [
   {
@@ -30,7 +30,15 @@ export const getFilterFormContent = (defaultValues = {} as any) => [
   },
 ];
 
-export const genExtraContent = ({ editingId, record, onSave, onCancel, onEdit, onDelete }) => {
+export const genExtraContent = ({
+  editingId,
+  record,
+  middlewareType,
+  onSave,
+  onCancel,
+  onEdit,
+  onDelete,
+}) => {
   return editingId === record.id || (editingId === true && !record.id)
     ? [
         {
@@ -58,7 +66,13 @@ export const genExtraContent = ({ editingId, record, onSave, onCancel, onEdit, o
       ];
 };
 
-export const genFormContent = (editingId, currentValues, inlongGroupId, readonly) => {
+export const genFormContent = (
+  editingId,
+  currentValues,
+  inlongGroupId,
+  readonly,
+  middlewareType,
+) => {
   const extraParams = {
     inlongGroupId,
     useDataSourcesActionRequest: !!currentValues?.id,
@@ -68,44 +82,79 @@ export const genFormContent = (editingId, currentValues, inlongGroupId, readonly
   };
 
   return [
-    {
-      type: (
-        <Divider orientation="left">{i18n.t('pages.AccessCreate.DataStream.config.Basic')}</Divider>
-      ),
-    },
     ...genDataFields(
-      ['inlongStreamId', 'name', 'inCharges', 'description'],
+      [
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.DataStream.config.Basic')}
+            </Divider>
+          ),
+        },
+        'inlongStreamId',
+        {
+          label: 'Topic Name',
+          type: 'text',
+          name: 'mqResourceObj',
+          visible: middlewareType === 'PULSAR' && editingId !== true,
+        },
+        'name',
+        'inCharges',
+        'description',
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.DataStream.config.DataSources')}
+            </Divider>
+          ),
+        },
+        'dataSourceType',
+        'dataSourcesConfig',
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.DataStream.config.DataInfo')}
+            </Divider>
+          ),
+        },
+        'dataType',
+        'dataEncoding',
+        'dataSeparator',
+        'rowTypeFields',
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.Business.config.AccessScale')}
+            </Divider>
+          ),
+          visible: middlewareType === 'PULSAR',
+        },
+      ],
       currentValues,
       extraParams,
     ),
-    {
-      type: (
-        <Divider orientation="left">
-          {i18n.t('pages.AccessCreate.DataStream.config.DataSources')}
-        </Divider>
-      ),
-    },
-    ...genDataFields(['dataSourceType', 'dataSourcesConfig'], currentValues, extraParams),
-    {
-      type: (
-        <Divider orientation="left">
-          {i18n.t('pages.AccessCreate.DataStream.config.DataInfo')}
-        </Divider>
-      ),
-    },
+    ...genBusinessFields(['dailyRecords', 'dailyStorage', 'peakRecords', 'maxLength']).map(
+      item => ({
+        ...item,
+        visible: middlewareType === 'PULSAR',
+      }),
+    ),
     ...genDataFields(
-      ['dataType', 'dataEncoding', 'fileDelimiter', 'rowTypeFields'],
+      [
+        {
+          type: (
+            <Divider orientation="left">
+              {i18n.t('pages.AccessCreate.DataStream.config.DataStorages')}
+            </Divider>
+          ),
+        },
+        'dataStorage',
+        'dataStorageHIVE',
+        'dataStorageCLICK_HOUSE',
+      ],
       currentValues,
       extraParams,
     ),
-    {
-      type: (
-        <Divider orientation="left">
-          {i18n.t('pages.AccessCreate.DataStream.config.DataStorages')}
-        </Divider>
-      ),
-    },
-    ...genDataFields(['dataStorage', 'dataStorageHIVE'], currentValues, extraParams),
   ].map(item => {
     if (
       (editingId === true && currentValues?.id === undefined) ||
diff --git a/inlong-website/src/pages/AccessDetail/DataStream/index.tsx b/inlong-website/src/pages/AccessDetail/DataStream/index.tsx
index af3008e..c4ad462 100644
--- a/inlong-website/src/pages/AccessDetail/DataStream/index.tsx
+++ b/inlong-website/src/pages/AccessDetail/DataStream/index.tsx
@@ -36,7 +36,7 @@ import styles from './index.module.less';
 
 type Props = CommonInterface;
 
-const Comp: React.FC<Props> = ({ inlongGroupId, readonly }) => {
+const Comp: React.FC<Props> = ({ inlongGroupId, readonly, middlewareType }) => {
   const { t } = useTranslation();
 
   const [form] = Form.useForm();
@@ -173,7 +173,15 @@ const Comp: React.FC<Props> = ({ inlongGroupId, readonly }) => {
   };
 
   const genExtra = (record, index) => {
-    const list = genExtraContent({ editingId, record, onSave, onEdit, onCancel, onDelete });
+    const list = genExtraContent({
+      editingId,
+      record,
+      middlewareType,
+      onSave,
+      onEdit,
+      onCancel,
+      onDelete,
+    });
     return (
       <>
         {list.map((item, k) => (
@@ -279,6 +287,7 @@ const Comp: React.FC<Props> = ({ inlongGroupId, readonly }) => {
                             { ...realTimeValues.list?.[index], inCharges: [userName] },
                             inlongGroupId,
                             readonly,
+                            middlewareType,
                           ).map(item => {
                             const obj = { ...item } as any;
                             if (obj.name) {
@@ -307,6 +316,7 @@ const Comp: React.FC<Props> = ({ inlongGroupId, readonly }) => {
 
       <StreamItemModal
         {...streamItemModal}
+        middlewareType={middlewareType}
         onOk={async () => {
           await getList();
           setEditingId(false);
diff --git a/inlong-website/src/pages/AccessDetail/Info/config.tsx b/inlong-website/src/pages/AccessDetail/Info/config.tsx
index 0143aa0..f70d41d 100644
--- a/inlong-website/src/pages/AccessDetail/Info/config.tsx
+++ b/inlong-website/src/pages/AccessDetail/Info/config.tsx
@@ -17,52 +17,86 @@
  * under the License.
  */
 
-import React from 'react';
+// import React from 'react';
 import { genBusinessFields } from '@/components/AccessHelper';
 
-export const getFormContent = ({ editing, initialValues }) => [
-  ...genBusinessFields(
+export const getFormContent = ({ editing, initialValues }) =>
+  genBusinessFields(
     [
+      'middlewareType',
       'inlongGroupId',
       'mqResourceObj',
       'name',
       'cnName',
       'inCharges',
       'description',
-      'middlewareType',
+      'queueModule',
+      'topicPartitionNum',
       'dailyRecords',
       'dailyStorage',
       'peakRecords',
       'maxLength',
+      // 'mqExtInfo.ensemble',
+      'mqExtInfo.writeQuorum',
+      'mqExtInfo.ackQuorum',
+      'mqExtInfo.retentionTime',
+      'mqExtInfo.ttl',
+      'mqExtInfo.retentionSize',
     ],
     initialValues,
-  ).map(item => {
-    const obj = { ...item };
-    if (typeof obj.suffix !== 'string') {
-      delete obj.suffix;
-    }
-    delete obj.extra;
-    if (!editing) {
-      if (typeof obj.type === 'string') {
-        obj.type = 'text';
-      } else if (obj.name === 'inCharges') {
-        obj.type = <span>{initialValues?.inCharges.join(', ')}</span>;
-      }
-    }
+  ).map(item => ({
+    ...item,
+    type: transType(editing, item, initialValues),
+    suffix:
+      typeof item.suffix === 'object' && !editing
+        ? {
+            ...item.suffix,
+            type: 'text',
+          }
+        : item.suffix,
+    extra: null,
+  }));
 
-    if (
-      [
+function transType(editing: boolean, conf, initialValues) {
+  const arr = [
+    {
+      name: [
         'middlewareType',
+        'queueModule',
+        'topicPartitionNum',
         'name',
         'dailyRecords',
         'dailyStorage',
         'peakRecords',
         'maxLength',
-      ].includes(obj.name as string)
-    ) {
-      obj.type = 'text';
-    }
+      ],
+      as: 'text',
+      active: true,
+    },
+    {
+      name: [
+        'cnName',
+        'description',
+        'inCharges',
+        // 'mqExtInfo.ensemble',
+        'mqExtInfo.writeQuorum',
+        'mqExtInfo.ackQuorum',
+        'mqExtInfo.retentionTime',
+        'mqExtInfo.ttl',
+        'mqExtInfo.retentionSize',
+      ],
+      as: 'text',
+      active: !editing,
+    },
+  ].reduce((acc, cur) => {
+    return acc.concat(Array.isArray(cur.name) ? cur.name.map(name => ({ ...cur, name })) : cur);
+  }, []);
+
+  const map = new Map(arr.map(item => [item.name, item]));
+  if (map.has(conf.name)) {
+    const item = map.get(conf.name);
+    return item.active ? item.as : conf.type;
+  }
 
-    return obj;
-  }),
-];
+  return conf.type;
+}
diff --git a/inlong-website/src/pages/AccessDetail/Info/index.tsx b/inlong-website/src/pages/AccessDetail/Info/index.tsx
index 2878377..a53be8b 100644
--- a/inlong-website/src/pages/AccessDetail/Info/index.tsx
+++ b/inlong-website/src/pages/AccessDetail/Info/index.tsx
@@ -51,6 +51,10 @@ const Comp: React.FC<Props> = ({ inlongGroupId, isActive, readonly, extraRef })
       ...values,
       inCharges: values.inCharges.join(','),
       followers: values.inCharges.join(','),
+      mqExtInfo: {
+        ...data.mqExtInfo,
+        ...values.mqExtInfo,
+      },
     };
     await request({
       url: '/business/update',
diff --git a/inlong-website/src/pages/AccessDetail/common.d.ts b/inlong-website/src/pages/AccessDetail/common.d.ts
index cf82e0b..43a86dd 100644
--- a/inlong-website/src/pages/AccessDetail/common.d.ts
+++ b/inlong-website/src/pages/AccessDetail/common.d.ts
@@ -19,6 +19,7 @@
 
 export interface CommonInterface {
   inlongGroupId: string;
+  middlewareType: 'TUBE' | 'PULSAR';
   readonly?: boolean;
   isActive?: boolean;
   // extraRef of Tab
diff --git a/inlong-website/src/pages/AccessDetail/index.tsx b/inlong-website/src/pages/AccessDetail/index.tsx
index b2e8eba..0fa38cb 100644
--- a/inlong-website/src/pages/AccessDetail/index.tsx
+++ b/inlong-website/src/pages/AccessDetail/index.tsx
@@ -38,6 +38,7 @@ const Comp: React.FC = () => {
   const extraRef = useRef<HTMLDivElement>();
 
   const isReadonly = useMemo(() => [0, 101, 102].includes(data?.status), [data]);
+  const middlewareType = data?.middlewareType;
 
   const list = useMemo(
     () =>
@@ -48,7 +49,7 @@ const Comp: React.FC = () => {
           content: Info,
         },
         {
-          label: t('pages.AccessDetail.DataStreams'),
+          label: middlewareType === 'PULSAR' ? 'TOPIC' : t('pages.AccessDetail.DataStreams'),
           value: 'dataStream',
           content: DataStream,
         },
@@ -65,7 +66,7 @@ const Comp: React.FC = () => {
           hidden: isReadonly,
         },
       ].filter(item => !item.hidden),
-    [isReadonly, t],
+    [isReadonly, middlewareType, t],
   );
 
   const [actived, setActived] = useState(list[0].value);
@@ -84,6 +85,7 @@ const Comp: React.FC = () => {
               isActive={actived === item.value}
               readonly={isReadonly}
               extraRef={extraRef}
+              middlewareType={middlewareType}
             />
           </Tabs.TabPane>
         ))}