This is an automated email from the ASF dual-hosted git repository.
dockerzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/inlong.git
The following commit(s) were added to refs/heads/master by this push:
new 6c94610372 [INLONG-10377][Dashboard] Add Source Data Field Template
(#10378)
6c94610372 is described below
commit 6c9461037217b2bfff61676a9745f80d66bb2766
Author: wohainilaodou <[email protected]>
AuthorDate: Wed Jun 12 19:30:30 2024 +0800
[INLONG-10377][Dashboard] Add Source Data Field Template (#10378)
Co-authored-by: v_shuomqiu <[email protected]>
---
inlong-dashboard/src/configs/menus/conf.tsx | 13 +-
inlong-dashboard/src/configs/routes/conf.ts | 4 +
inlong-dashboard/src/i18n.ts | 4 +
.../plugins/groups/common/GroupDataTemplateInfo.ts | 171 ++++++++++++++++++
.../plugins/streams/common/StreamDefaultInfo.ts | 30 ++++
inlong-dashboard/src/ui/locales/cn.json | 12 +-
inlong-dashboard/src/ui/locales/en.json | 10 +-
.../src/ui/pages/Clusters/NodeEditModal.tsx | 114 ++++++++----
.../src/ui/pages/GroupDataTemplate/CreateModal.tsx | 112 ++++++++++++
.../src/ui/pages/GroupDataTemplate/index.tsx | 195 +++++++++++++++++++++
.../GroupDetail/DataStream/StreamItemModal.tsx | 21 +++
11 files changed, 649 insertions(+), 37 deletions(-)
diff --git a/inlong-dashboard/src/configs/menus/conf.tsx
b/inlong-dashboard/src/configs/menus/conf.tsx
index dc660dc62f..a4e80f26bd 100644
--- a/inlong-dashboard/src/configs/menus/conf.tsx
+++ b/inlong-dashboard/src/configs/menus/conf.tsx
@@ -33,9 +33,18 @@ import type { MenuItemType } from '.';
const conf: MenuItemType[] = [
{
- path: '/group',
- name: i18n.t('configs.menus.Groups'),
+ name: i18n.t('configs.menus.GroupsManagement'),
icon: <ApiOutlined />,
+ children: [
+ {
+ path: '/group',
+ name: i18n.t('configs.menus.Groups'),
+ },
+ {
+ path: '/dataTemplate',
+ name: i18n.t('configs.menus.Groups.Template'),
+ },
+ ],
},
{
path: '/sync',
diff --git a/inlong-dashboard/src/configs/routes/conf.ts
b/inlong-dashboard/src/configs/routes/conf.ts
index 007538d997..ce3a38ab12 100644
--- a/inlong-dashboard/src/configs/routes/conf.ts
+++ b/inlong-dashboard/src/configs/routes/conf.ts
@@ -38,6 +38,10 @@ const conf: RouteProps[] = [
},
],
},
+ {
+ path: '/dataTemplate',
+ component: () => import('@/ui/pages/GroupDataTemplate'),
+ },
{
path: '/consume',
component: () => import('@/ui/pages/ConsumeDashboard'),
diff --git a/inlong-dashboard/src/i18n.ts b/inlong-dashboard/src/i18n.ts
index 0146bf9320..eebff6c37f 100644
--- a/inlong-dashboard/src/i18n.ts
+++ b/inlong-dashboard/src/i18n.ts
@@ -27,6 +27,8 @@ const resources = {
translation: {
'configs.menus.Process': 'Approval',
'configs.menus.Groups': 'Ingestion',
+ 'configs.menus.GroupsManagement': 'Ingestion Management',
+ 'configs.menus.Groups.Template': 'Template',
'configs.menus.Subscribe': 'Subscription',
'configs.menus.Clusters': 'Clusters',
'configs.menus.ClusterTags': 'ClusterTags',
@@ -46,6 +48,8 @@ const resources = {
translation: {
'configs.menus.Process': '审批管理',
'configs.menus.Groups': '数据接入',
+ 'configs.menus.GroupsManagement': '接入管理',
+ 'configs.menus.Groups.Template': '模板',
'configs.menus.Subscribe': '数据订阅',
'configs.menus.Clusters': '集群管理',
'configs.menus.ClusterTags': '标签管理',
diff --git
a/inlong-dashboard/src/plugins/groups/common/GroupDataTemplateInfo.ts
b/inlong-dashboard/src/plugins/groups/common/GroupDataTemplateInfo.ts
new file mode 100644
index 0000000000..4699970415
--- /dev/null
+++ b/inlong-dashboard/src/plugins/groups/common/GroupDataTemplateInfo.ts
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { DataWithBackend } from '@/plugins/DataWithBackend';
+import { RenderRow } from '@/plugins/RenderRow';
+import { RenderList } from '@/plugins/RenderList';
+import i18n from '@/i18n';
+import EditableTable from '@/ui/components/EditableTable';
+import { fieldTypes as sourceFieldsTypes } from
'@/plugins/sinks/common/sourceFields';
+import UserSelect from '@/ui/components/UserSelect';
+
+const { I18nMap, I18n } = DataWithBackend;
+const { FieldList, FieldDecorator } = RenderRow;
+const { ColumnList, ColumnDecorator } = RenderList;
+
+export class GroupDataTemplateInfo implements DataWithBackend, RenderRow,
RenderList {
+ static I18nMap = I18nMap;
+ static FieldList = FieldList;
+ static ColumnList = ColumnList;
+
+ readonly id: number;
+
+ @FieldDecorator({
+ type: 'input',
+ rules: [{ required: true }],
+ })
+ @ColumnDecorator()
+ @I18n('pages.GroupDataTemplate.Name')
+ name: string;
+
+ @FieldDecorator({
+ type: UserSelect,
+ rules: [{ required: true }],
+ props: {
+ mode: 'multiple',
+ currentUserClosable: false,
+ },
+ })
+ @ColumnDecorator()
+ @I18n('pages.GroupDataTemplate.InChargers')
+ inCharges: string;
+
+ @FieldDecorator({
+ type: 'select',
+ props: {
+ mode: 'multiple',
+ filterOption: true,
+ options: {
+ requestTrigger: ['onOpen', 'onSearch'],
+ requestService: keyword => ({
+ url: '/tenant/list',
+ method: 'POST',
+ data: {
+ keyword,
+ pageNum: 1,
+ pageSize: 9999,
+ },
+ }),
+ requestParams: {
+ formatResult: result => {
+ return result?.list?.map(item => ({
+ ...item,
+ label: item.name,
+ value: item.name.toString(),
+ }));
+ },
+ },
+ },
+ },
+ rules: [
+ {
+ required: true,
+ },
+ ],
+ })
+ @ColumnDecorator()
+ @I18n('pages.GroupDataTemplate.TenantList')
+ tenantList: string[];
+
+ @FieldDecorator({
+ type: 'input',
+ initialValue: 0,
+ rules: [{ required: true }],
+ })
+ @I18n('pages.GroupDataTemplate.Version')
+ version: number;
+
+ @FieldDecorator({
+ type: 'input',
+ initialValue: '',
+ rules: [{ required: true }],
+ })
+ @I18n('pages.GroupDataTemplate.VisibleRange')
+ visibleRange: String;
+
+ @FieldDecorator({
+ type: EditableTable,
+ props: values => ({
+ size: 'small',
+ canDelete: record => !(record.id && [110].includes(values?.status)),
+ canBatchAdd: true,
+ columns: [
+ {
+ title: i18n.t('meta.Stream.FieldName'),
+ dataIndex: 'fieldName',
+ rules: [
+ { required: true },
+ {
+ pattern: /^[_a-zA-Z][a-zA-Z0-9_]*$/,
+ message: i18n.t('meta.Stream.FieldNameRule'),
+ },
+ ],
+ props: (text, record) => ({
+ disabled: record.id && [110].includes(values?.status),
+ }),
+ },
+ {
+ title: i18n.t('meta.Stream.FieldType'),
+ dataIndex: 'fieldType',
+ type: 'select',
+ initialValue: sourceFieldsTypes[0].value,
+ props: (text, record) => ({
+ disabled: record.id && [110].includes(values?.status),
+ options: sourceFieldsTypes,
+ }),
+ rules: [{ required: true }],
+ },
+ {
+ title: i18n.t('meta.Stream.FieldComment'),
+ dataIndex: 'fieldComment',
+ },
+ ],
+ }),
+ })
+ @I18n('meta.Stream.SourceDataField')
+ fieldList: Record<string, string>[];
+
+ parse(data) {
+ return data;
+ }
+
+ stringify(data) {
+ return data;
+ }
+
+ renderRow() {
+ const constructor = this.constructor as typeof GroupDataTemplateInfo;
+ return constructor.FieldList;
+ }
+
+ renderList() {
+ const constructor = this.constructor as typeof GroupDataTemplateInfo;
+ return constructor.ColumnList;
+ }
+}
diff --git a/inlong-dashboard/src/plugins/streams/common/StreamDefaultInfo.ts
b/inlong-dashboard/src/plugins/streams/common/StreamDefaultInfo.ts
index 54b840bd29..592c53b508 100644
--- a/inlong-dashboard/src/plugins/streams/common/StreamDefaultInfo.ts
+++ b/inlong-dashboard/src/plugins/streams/common/StreamDefaultInfo.ts
@@ -222,6 +222,36 @@ export class StreamDefaultInfo implements DataWithBackend,
RenderRow, RenderList
})
@I18n('meta.Stream.DataSeparator')
dataSeparator: string;
+ @FieldDecorator({
+ type: 'select',
+ props: {
+ filterOption: true,
+ options: {
+ requestTrigger: ['onOpen', 'onSearch'],
+ requestService: keyword => ({
+ url: '/template/list',
+ method: 'POST',
+ data: {
+ keyword,
+ pageNum: 1,
+ pageSize: 20,
+ },
+ }),
+ requestParams: {
+ formatResult: result => {
+ return result?.list?.map(item => ({
+ ...item,
+ label: item.name,
+ value: item.name,
+ }));
+ },
+ },
+ },
+ },
+ rules: [],
+ })
+ @I18n('meta.Stream.SourceDataField.Template')
+ streamDataTemplate: string;
@FieldDecorator({
type: EditableTable,
diff --git a/inlong-dashboard/src/ui/locales/cn.json
b/inlong-dashboard/src/ui/locales/cn.json
index d357134e7b..09b1d493f8 100644
--- a/inlong-dashboard/src/ui/locales/cn.json
+++ b/inlong-dashboard/src/ui/locales/cn.json
@@ -34,6 +34,7 @@
"meta.Sources.File.FilePathHelp": "必须是绝对路径,支持正则表达式,多个时以逗号分隔,如:/data/.*log",
"meta.Sources.File.FileIpHelp": "请选择文件采集节点 IP,若 IP 不固定请选择 All",
"meta.Sources.File.IpRule": "请输入正确的 IP 地址",
+ "meta.Sources.File.VersionRule": "请输入正确的版本号",
"meta.Sources.File.TimeOffset": "时间偏移量",
"meta.Sources.File.TimeOffsetHelp":
"从文件的某个时间开始采集,'1m'表示1分钟之后,'-1m'表示1分钟之前,支持m(分钟),h(小时),d(天),空则从当前时间开始采集",
"meta.Sources.File.TimeOffsetRules": "只能包含数字和字母 m、h、d",
@@ -428,6 +429,7 @@
"meta.Stream.DataEncoding": "数据编码",
"meta.Stream.Description": "介绍",
"meta.Stream.SourceDataField": "源数据字段",
+ "meta.Stream.SourceDataField.Template": "源数据字段模板",
"meta.Stream.IgnoreParseError": "忽略数据解析错误",
"meta.Stream.Status.New": "新建",
"meta.Stream.Status.Pending": "配置中",
@@ -758,6 +760,7 @@
"pages.Clusters.Node.Port": "端口",
"pages.Clusters.Node.ProtocolType": "协议类型",
"pages.Clusters.Node.Agent": "Agent",
+ "pages.Clusters.Node.Agent.Version": "Version",
"pages.Clusters.Node.AgentInstaller": "Installer",
"pages.Clusters.Node.IsInstall": "安装方式",
"pages.Clusters.Node.ManualInstall": "手动安装",
@@ -899,5 +902,12 @@
"pages.PackageAgent.Config.FileName": "文件名称",
"pages.PackageAgent.Config.DownloadUrl": "下载地址",
"pages.PackageAgent.Config.StoragePath": "存储路径",
- "pages.PackageAgent.Config.Md5": "MD5"
+ "pages.PackageAgent.Config.Md5": "MD5",
+ "pages.GroupDataTemplate.Edit":"编辑模板",
+ "pages.GroupDataTemplate.Create":"新建模板",
+ "pages.GroupDataTemplate.Name":"模板名称",
+ "pages.GroupDataTemplate.TenantList":"租户",
+ "pages.GroupDataTemplate.Version":"版本",
+ "pages.GroupDataTemplate.VisibleRange":"可视范围",
+ "pages.GroupDataTemplate.InChargers":"负责人"
}
diff --git a/inlong-dashboard/src/ui/locales/en.json
b/inlong-dashboard/src/ui/locales/en.json
index 88dd932c31..fdc2bf3e85 100644
--- a/inlong-dashboard/src/ui/locales/en.json
+++ b/inlong-dashboard/src/ui/locales/en.json
@@ -428,6 +428,7 @@
"meta.Stream.DataEncoding": "Data encoding",
"meta.Stream.Description": "Description",
"meta.Stream.SourceDataField": "Source fields",
+ "meta.Stream.SourceDataField.Template": "Source fields Template",
"meta.Stream.IgnoreParseError": "Ignore parse error",
"meta.Stream.Status.New": "New",
"meta.Stream.Status.Pending": "Pending",
@@ -899,5 +900,12 @@
"pages.PackageAgent.Config.FileName": "File Name",
"pages.PackageAgent.Config.DownloadUrl": "Download Url",
"pages.PackageAgent.Config.Md5": "MD5",
- "pages.PackageAgent.Config.StoragePath": "Storage Path"
+ "pages.PackageAgent.Config.StoragePath": "Storage Path",
+ "pages.GroupDataTemplate.Edit":"Edit Template",
+ "pages.GroupDataTemplate.Create":"Create Template",
+ "pages.GroupDataTemplate.Name":"Template Name",
+ "pages.GroupDataTemplate.TenantList":"Tenant",
+ "pages.GroupDataTemplate.Version":"Version",
+ "pages.GroupDataTemplate.VisibleRange":"Visible Range",
+ "pages.GroupDataTemplate.InChargers":"InChargers"
}
diff --git a/inlong-dashboard/src/ui/pages/Clusters/NodeEditModal.tsx
b/inlong-dashboard/src/ui/pages/Clusters/NodeEditModal.tsx
index 8050756849..687713f9e7 100644
--- a/inlong-dashboard/src/ui/pages/Clusters/NodeEditModal.tsx
+++ b/inlong-dashboard/src/ui/pages/Clusters/NodeEditModal.tsx
@@ -79,12 +79,40 @@ const NodeEditModal: React.FC<NodeEditModalProps> = ({ id,
type, clusterId, ...m
message.success(i18n.t('basic.OperatingSuccess'));
};
+ const { data: agentInstaller, run: getAgentInstall } = useRequest(
+ () => ({
+ url: '/module/list',
+ method: 'POST',
+ data: {
+ pageNum: 1,
+ pageSize: 9999,
+ },
+ }),
+ {
+ manual: true,
+ onSuccess: result => {
+ const temp = result?.list
+ ?.filter(item => item.type === 'INSTALLER')
+ .map(item => ({
+ ...item,
+ label: `${item.name} ${item.version}`,
+ value: item.id,
+ }));
+ form.setFieldValue('installer', temp[0].id);
+ },
+ },
+ );
+
useUpdateEffect(() => {
if (modalProps.open) {
// open
form.resetFields();
if (id) {
getData(id);
+ } else {
+ if (type === 'AGENT') {
+ getAgentInstall();
+ }
}
}
}, [modalProps.open]);
@@ -139,42 +167,29 @@ const NodeEditModal: React.FC<NodeEditModalProps> = ({
id, type, clusterId, ...m
},
{
type: 'select',
- label: i18n.t('pages.Clusters.Node.Agent'),
- name: 'moduleIdList',
- hidden: type !== 'AGENT',
+ label: i18n.t('pages.Clusters.Node.ProtocolType'),
+ name: 'protocolType',
+ initialValue: 'HTTP',
+ rules: [{ required: true }],
props: {
- options: {
- requestAuto: true,
- requestTrigger: ['onOpen'],
- requestService: keyword => ({
- url: '/module/list',
- method: 'POST',
- data: {
- keyword,
- pageNum: 1,
- pageSize: 9999,
- },
- }),
- requestParams: {
- formatResult: result =>
- result?.list
- ?.filter(item => item.type === 'AGENT')
- .map(item => ({
- ...item,
- label: `${item.name} ${item.version}`,
- value: item.id,
- })),
+ options: [
+ {
+ label: 'HTTP',
+ value: 'HTTP',
},
- },
+ {
+ label: 'TCP',
+ value: 'TCP',
+ },
+ ],
},
},
{
type: 'select',
- label: i18n.t('pages.Clusters.Node.AgentInstaller'),
- name: 'installer',
+ label: i18n.t('pages.Clusters.Node.Agent.Version'),
+ name: 'moduleIdList',
hidden: type !== 'AGENT',
props: {
- mode: 'multiple',
options: {
requestAuto: true,
requestTrigger: ['onOpen'],
@@ -190,7 +205,7 @@ const NodeEditModal: React.FC<NodeEditModalProps> = ({ id,
type, clusterId, ...m
requestParams: {
formatResult: result =>
result?.list
- ?.filter(item => item.type === 'INSTALLER')
+ ?.filter(item => item.type === 'AGENT')
.map(item => ({
...item,
label: `${item.name} ${item.version}`,
@@ -200,6 +215,14 @@ const NodeEditModal: React.FC<NodeEditModalProps> = ({ id,
type, clusterId, ...m
},
},
},
+ {
+ type: 'textarea',
+ label: i18n.t('pages.Clusters.Description'),
+ name: 'description',
+ props: {
+ maxLength: 256,
+ },
+ },
{
type: 'radio',
label: i18n.t('pages.Clusters.Node.IsInstall'),
@@ -245,11 +268,36 @@ const NodeEditModal: React.FC<NodeEditModalProps> = ({
id, type, clusterId, ...m
visible: values => values?.isInstall,
},
{
- type: 'textarea',
- label: i18n.t('pages.Clusters.Description'),
- name: 'description',
+ type: 'select',
+ label: i18n.t('pages.Clusters.Node.AgentInstaller'),
+ name: 'installer',
+ isPro: type === 'AGENT',
+ hidden: type !== 'AGENT',
props: {
- maxLength: 256,
+ mode: 'multiple',
+ options: {
+ requestAuto: true,
+ requestTrigger: ['onOpen'],
+ requestService: keyword => ({
+ url: '/module/list',
+ method: 'POST',
+ data: {
+ keyword,
+ pageNum: 1,
+ pageSize: 9999,
+ },
+ }),
+ requestParams: {
+ formatResult: result =>
+ result?.list
+ ?.filter(item => item.type === 'INSTALLER')
+ .map(item => ({
+ ...item,
+ label: `${item.name} ${item.version}`,
+ value: item.id,
+ })),
+ },
+ },
},
},
];
diff --git a/inlong-dashboard/src/ui/pages/GroupDataTemplate/CreateModal.tsx
b/inlong-dashboard/src/ui/pages/GroupDataTemplate/CreateModal.tsx
new file mode 100644
index 0000000000..e385d48070
--- /dev/null
+++ b/inlong-dashboard/src/ui/pages/GroupDataTemplate/CreateModal.tsx
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React, { useState, useMemo } from 'react';
+import { Modal, message, Button } from 'antd';
+import { ModalProps } from 'antd/es/modal';
+import FormGenerator, { useForm } from '@/ui/components/FormGenerator';
+import { useRequest, useUpdateEffect } from '@/ui/hooks';
+import request from '@/core/utils/request';
+import i18n from '@/i18n';
+import { GroupDataTemplateInfo } from
'@/plugins/groups/common/GroupDataTemplateInfo';
+import { dataToValues } from '@/ui/pages/GroupDetail/DataStream/helper';
+
+export interface Props extends ModalProps {
+ // Require when edit
+ id?: string;
+ templateName?: string;
+}
+
+const Comp: React.FC<Props> = ({ id, templateName, ...modalProps }) => {
+ const [form] = useForm();
+
+ const { data: savedData, run: getData } = useRequest(
+ () => ({
+ url: `/template/get/`,
+ method: 'GET',
+ params: {
+ templateName: templateName,
+ },
+ }),
+ {
+ manual: true,
+ formatResult: result => ({
+ ...result,
+ inCharges: result.inCharges?.split(','),
+ }),
+ onSuccess: result => {
+ form.setFieldsValue(dataToValues(result));
+ },
+ },
+ );
+
+ const onOk = async () => {
+ const values = await form.validateFields();
+ const isUpdate = id;
+ const submitData = {
+ ...values,
+ inCharges: values.inCharges?.join(','),
+ };
+
+ if (isUpdate) {
+ submitData.id = id;
+ submitData.version = savedData?.version;
+ }
+ await request({
+ url: `/template/${isUpdate ? 'update' : 'save'}`,
+ method: 'POST',
+ data: submitData,
+ });
+ await modalProps?.onOk(submitData);
+ message.success(i18n.t('basic.OperatingSuccess'));
+ };
+
+ useUpdateEffect(() => {
+ if (modalProps.open) {
+ if (templateName) {
+ getData();
+ }
+ } else {
+ form.resetFields();
+ }
+ }, [modalProps.open]);
+
+ const content = useMemo(() => {
+ return new GroupDataTemplateInfo().renderRow();
+ }, []);
+ return (
+ <Modal
+ width={1000}
+ {...modalProps}
+ title={id ? i18n.t('pages.GroupDataTemplate.Edit') :
i18n.t('pages.GroupDataTemplate.Create')}
+ footer={[
+ <Button key="cancel" onClick={e => modalProps.onCancel(e)}>
+ {i18n.t('basic.Cancel')}
+ </Button>,
+ <Button key="save" type="primary" onClick={onOk}>
+ {i18n.t('basic.Save')}
+ </Button>,
+ ]}
+ >
+ <FormGenerator content={content} form={form} onValuesChange={(c, values)
=> {}} useMaxWidth />
+ </Modal>
+ );
+};
+
+export default Comp;
diff --git a/inlong-dashboard/src/ui/pages/GroupDataTemplate/index.tsx
b/inlong-dashboard/src/ui/pages/GroupDataTemplate/index.tsx
new file mode 100644
index 0000000000..b53dddd83f
--- /dev/null
+++ b/inlong-dashboard/src/ui/pages/GroupDataTemplate/index.tsx
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React, { useCallback, useMemo, useState } from 'react';
+import { Button } from 'antd';
+import i18n from '@/i18n';
+import HighTable from '@/ui/components/HighTable';
+import { PageContainer } from '@/ui/components/PageContainer';
+import { defaultSize } from '@/configs/pagination';
+import { useRequest } from '@/ui/hooks';
+import CreateModal from './CreateModal';
+import { timestampFormat } from '@/core/utils';
+
+const Comp: React.FC = () => {
+ const [options, setOptions] = useState({
+ inCharges: null,
+ name: null,
+ tenantList: null,
+ orderField: null,
+ orderType: null,
+ pageNum: 1,
+ pageSize: defaultSize,
+ visibleRange: null,
+ });
+
+ const [createModal, setCreateModal] = useState<Record<string, unknown>>({
+ open: false,
+ });
+
+ const {
+ data,
+ loading,
+ run: getList,
+ } = useRequest(
+ {
+ url: '/template/list',
+ method: 'POST',
+ data: {
+ ...options,
+ },
+ },
+ {
+ refreshDeps: [options],
+ onSuccess: result => {},
+ },
+ );
+
+ const onEdit = ({ id, name }) => {
+ setCreateModal({ open: true, id, templateName: name });
+ };
+
+ const onChange = ({ current: pageNum, pageSize }) => {
+ setOptions(prev => ({
+ ...prev,
+ pageNum,
+ pageSize,
+ }));
+ };
+
+ const onFilter = allValues => {
+ for (const key in allValues) {
+ if (allValues[key] === '') {
+ allValues[key] = null;
+ }
+ }
+ setOptions(prev => ({
+ ...prev,
+ ...allValues,
+ pageNum: 1,
+ }));
+ };
+
+ const pagination = {
+ pageSize: +options.pageSize,
+ current: +options.pageNum,
+ total: data?.total,
+ };
+
+ const getFilterFormContent = useCallback(
+ defaultValues => [
+ {
+ type: 'inputsearch',
+ name: 'name',
+ },
+ ],
+ [],
+ );
+ const entityColumns = useMemo(() => {
+ return [
+ {
+ title: 'id',
+ dataIndex: 'id',
+ key: 'id',
+ width: 100,
+ },
+ {
+ title: i18n.t('pages.GroupDataTemplate.Name'),
+ dataIndex: 'name',
+ key: 'name',
+ width: 100,
+ },
+ {
+ title: i18n.t('pages.GroupDataTemplate.InChargers'),
+ dataIndex: 'inCharges',
+ key: 'inCharges',
+ width: 100,
+ },
+ {
+ title: i18n.t('pages.GroupDataTemplate.TenantList'),
+ dataIndex: 'tenantList',
+ key: 'tenantList',
+ width: 200,
+ render: (text, record: any) => (
+ <>
+ <div>{record.tenantList?.join(',')}</div>
+ </>
+ ),
+ },
+ {
+ title: i18n.t('pages.GroupDataTemplate.Version'),
+ dataIndex: 'version',
+ key: 'version',
+ width: 200,
+ },
+ ];
+ }, []);
+ const columns = useMemo(() => {
+ return entityColumns?.concat([
+ {
+ title: i18n.t('basic.Operating'),
+ dataIndex: 'action',
+ width: 200,
+ render: (text, record) => (
+ <>
+ <Button type="link" onClick={() => onEdit(record)}>
+ {i18n.t('basic.Edit')}
+ </Button>
+ </>
+ ),
+ } as any,
+ ]);
+ }, [entityColumns]);
+
+ return (
+ <PageContainer useDefaultBreadcrumb={false}>
+ <HighTable
+ filterForm={{
+ content: getFilterFormContent(options),
+ onFilter,
+ }}
+ suffix={
+ <Button type="primary" onClick={() => setCreateModal({ open: true
})}>
+ {i18n.t('pages.GroupDataTemplate.Create')}
+ </Button>
+ }
+ table={{
+ columns,
+ rowKey: 'id',
+ dataSource: data?.list,
+ pagination,
+ loading,
+ onChange,
+ }}
+ />
+
+ <CreateModal
+ {...createModal}
+ open={createModal.open as boolean}
+ onOk={async () => {
+ await getList();
+ setCreateModal({ open: false });
+ }}
+ onCancel={() => setCreateModal({ open: false })}
+ />
+ </PageContainer>
+ );
+};
+
+export default Comp;
diff --git
a/inlong-dashboard/src/ui/pages/GroupDetail/DataStream/StreamItemModal.tsx
b/inlong-dashboard/src/ui/pages/GroupDetail/DataStream/StreamItemModal.tsx
index b7b9c4d0d4..c8587efa46 100644
--- a/inlong-dashboard/src/ui/pages/GroupDetail/DataStream/StreamItemModal.tsx
+++ b/inlong-dashboard/src/ui/pages/GroupDetail/DataStream/StreamItemModal.tsx
@@ -175,6 +175,22 @@ const Comp: React.FC<Props> = ({ inlongGroupId,
inlongStreamId, mqType, ...modal
message.success(i18n.t('basic.OperatingSuccess'));
};
+ const { run: getDataTemplateValue } = useRequest(
+ template => ({
+ url: '/template/get',
+ params: {
+ templateName: template,
+ },
+ }),
+ {
+ manual: true,
+ onSuccess: result => {
+ savedData.fieldList = result['fieldList'];
+ form.setFieldsValue(dataToValues(savedData));
+ },
+ },
+ );
+
useUpdateEffect(() => {
if (modalProps.open) {
// open
@@ -199,6 +215,11 @@ const Comp: React.FC<Props> = ({ inlongGroupId,
inlongStreamId, mqType, ...modal
content={formContent}
form={form}
useMaxWidth
+ onValuesChange={(c, values) => {
+ if (Object.keys(c)[0] === 'streamDataTemplate') {
+ getDataTemplateValue(c['streamDataTemplate']);
+ }
+ }}
/>
</Modal>
);