This is an automated email from the ASF dual-hosted git repository.
aloyszhang 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 80125f0f63 [INLONG-11178][Dashboard] Added http sink and http node
(#11311)
80125f0f63 is described below
commit 80125f0f6336d9990ea3dbc0b77cb7330b19648f
Author: kamianlaida <[email protected]>
AuthorDate: Thu Oct 10 09:58:54 2024 +0800
[INLONG-11178][Dashboard] Added http sink and http node (#11311)
---
.../src/plugins/clusters/defaults/SortHttp.ts | 27 +++
.../src/plugins/clusters/defaults/index.ts | 5 +
.../src/plugins/nodes/defaults/Http.ts | 79 +++++++++
.../src/plugins/nodes/defaults/index.ts | 5 +
.../src/plugins/sinks/defaults/Http.ts | 186 +++++++++++++++++++++
.../src/plugins/sinks/defaults/index.ts | 5 +
inlong-dashboard/src/ui/locales/cn.json | 11 ++
inlong-dashboard/src/ui/locales/en.json | 11 ++
.../src/ui/pages/Clusters/CreateModal.tsx | 3 +-
9 files changed, 331 insertions(+), 1 deletion(-)
diff --git a/inlong-dashboard/src/plugins/clusters/defaults/SortHttp.ts
b/inlong-dashboard/src/plugins/clusters/defaults/SortHttp.ts
new file mode 100644
index 0000000000..473d3dcaff
--- /dev/null
+++ b/inlong-dashboard/src/plugins/clusters/defaults/SortHttp.ts
@@ -0,0 +1,27 @@
+/*
+ * 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 { ClusterInfo } from '@/plugins/clusters/common/ClusterInfo';
+import { DataWithBackend } from '@/plugins/DataWithBackend';
+import { RenderRow } from '@/plugins/RenderRow';
+import { RenderList } from '@/plugins/RenderList';
+
+export default class SortHttp
+ extends ClusterInfo
+ implements DataWithBackend, RenderRow, RenderList {}
diff --git a/inlong-dashboard/src/plugins/clusters/defaults/index.ts
b/inlong-dashboard/src/plugins/clusters/defaults/index.ts
index 1c5e49bb49..0c947572b5 100644
--- a/inlong-dashboard/src/plugins/clusters/defaults/index.ts
+++ b/inlong-dashboard/src/plugins/clusters/defaults/index.ts
@@ -71,4 +71,9 @@ export const allDefaultClusters:
MetaExportWithBackendList<ClusterMetaType> = [
value: 'SORT_KAFKA',
LoadEntity: () => import('./SortKafka'),
},
+ {
+ label: 'Sort Http',
+ value: 'SORT_HTTP',
+ LoadEntity: () => import('./SortHttp'),
+ },
];
diff --git a/inlong-dashboard/src/plugins/nodes/defaults/Http.ts
b/inlong-dashboard/src/plugins/nodes/defaults/Http.ts
new file mode 100644
index 0000000000..8017394143
--- /dev/null
+++ b/inlong-dashboard/src/plugins/nodes/defaults/Http.ts
@@ -0,0 +1,79 @@
+/*
+ * 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 { NodeInfo } from '../common/NodeInfo';
+import i18n from 'i18next';
+import { Input } from 'antd';
+
+const { I18n } = DataWithBackend;
+const { FieldDecorator } = RenderRow;
+
+export default class HttpNodeInfo
+ extends NodeInfo
+ implements DataWithBackend, RenderRow, RenderList
+{
+ @FieldDecorator({
+ type: 'input',
+ rules: [{ required: true }],
+ })
+ @I18n('meta.Nodes.Http.BaseUrl')
+ baseUrl: string;
+
+ @FieldDecorator({
+ type: 'radio',
+ rules: [{ required: true }],
+ initialValue: false,
+ props: {
+ options: [
+ {
+ label: i18n.t('basic.Yes'),
+ value: true,
+ },
+ {
+ label: i18n.t('basic.No'),
+ value: false,
+ },
+ ],
+ },
+ })
+ @I18n('meta.Nodes.Http.EnableCredential')
+ enableCredential: string;
+
+ @FieldDecorator({
+ type: 'input',
+ })
+ @I18n('meta.Nodes.Http.Username')
+ username: string;
+
+ @FieldDecorator({
+ type: Input.Password,
+ })
+ @I18n('meta.Nodes.Http.Password')
+ password: string;
+
+ @FieldDecorator({
+ type: 'inputnumber',
+ initialValue: 1000,
+ })
+ @I18n('meta.Nodes.Http.MaxConnect')
+ maxConnect: number;
+}
diff --git a/inlong-dashboard/src/plugins/nodes/defaults/index.ts
b/inlong-dashboard/src/plugins/nodes/defaults/index.ts
index 06209fd940..858ac347eb 100644
--- a/inlong-dashboard/src/plugins/nodes/defaults/index.ts
+++ b/inlong-dashboard/src/plugins/nodes/defaults/index.ts
@@ -96,4 +96,9 @@ export const allDefaultNodes:
MetaExportWithBackendList<NodeMetaType> = [
value: 'KUDU',
LoadEntity: () => import('./Kudu'),
},
+ {
+ label: 'Http',
+ value: 'HTTP',
+ LoadEntity: () => import('./Http'),
+ },
];
diff --git a/inlong-dashboard/src/plugins/sinks/defaults/Http.ts
b/inlong-dashboard/src/plugins/sinks/defaults/Http.ts
new file mode 100644
index 0000000000..2dce2466da
--- /dev/null
+++ b/inlong-dashboard/src/plugins/sinks/defaults/Http.ts
@@ -0,0 +1,186 @@
+/*
+ * 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 { SinkInfo } from '@/plugins/sinks/common/SinkInfo';
+import { RenderList } from '@/plugins/RenderList';
+import NodeSelect from '@/ui/components/NodeSelect';
+import i18n from '@/i18n';
+import EditableTable from '@/ui/components/EditableTable';
+import {
+ fieldTypes,
+ fieldTypes as sourceFieldsTypes,
+ sourceFields,
+} from '@/plugins/sinks/common/sourceFields';
+
+const { I18n } = DataWithBackend;
+const { FieldDecorator, SyncField, SyncCreateTableField, IngestionField } =
RenderRow;
+const { ColumnDecorator } = RenderList;
+
+export default class HttpSinkInfo
+ extends SinkInfo
+ implements DataWithBackend, RenderRow, RenderList
+{
+ @FieldDecorator({
+ type: 'input',
+ rules: [{ required: true }],
+ props: values => ({
+ disabled: [110].includes(values?.status),
+ }),
+ })
+ @SyncField()
+ @I18n('meta.Sinks.Http.Path')
+ @IngestionField()
+ path: string;
+
+ @FieldDecorator({
+ type: 'radio',
+ initialValue: 'GET',
+ rules: [{ required: true }],
+ props: values => ({
+ options: [
+ {
+ label: 'GET',
+ value: 'GET',
+ },
+ {
+ label: 'POST',
+ value: 'POST',
+ },
+ ],
+ }),
+ })
+ @SyncField()
+ @IngestionField()
+ @I18n('meta.Sinks.Http.Method')
+ method: string;
+
+ @FieldDecorator({
+ type: NodeSelect,
+ rules: [{ required: true }],
+ props: values => ({
+ disabled: [110].includes(values?.status),
+ nodeType: 'HTTP',
+ }),
+ })
+ @I18n('meta.Sinks.DataNodeName')
+ @SyncField()
+ @IngestionField()
+ @ColumnDecorator()
+ dataNodeName: string;
+
+ @FieldDecorator({
+ type: EditableTable,
+ props: values => ({
+ size: 'small',
+ canDelete: record => !(record.id && [110].includes(values?.status)),
+ canBatchAdd: true,
+ columns: [
+ {
+ title: i18n.t('meta.Sinks.Http.FieldName'),
+ dataIndex: 'fieldName',
+ props: (text, record) => ({
+ disabled: record.id && [110].includes(values?.status),
+ }),
+ },
+ {
+ title: i18n.t('meta.Sinks.Http.FieldValue'),
+ dataIndex: 'fieldValue',
+ type: 'input',
+ },
+ ],
+ }),
+ })
+ @SyncField()
+ @IngestionField()
+ @I18n('meta.Sinks.Http.Headers')
+ headers: Record<string, string>[];
+
+ @FieldDecorator({
+ type: 'inputnumber',
+ initialValue: '0',
+ })
+ @SyncField()
+ @IngestionField()
+ @I18n('meta.Sinks.Http.MaxRetryTimes')
+ maxRetryTimes: number;
+ @FieldDecorator({
+ type: EditableTable,
+ props: values => ({
+ size: 'small',
+ editing: ![110].includes(values?.status),
+ columns: getFieldListColumns(values),
+ canBatchAdd: true,
+ upsertByFieldKey: true,
+ }),
+ })
+ @IngestionField()
+ sinkFieldList: Record<string, unknown>[];
+}
+
+const getFieldListColumns = sinkValues => {
+ return [
+ ...sourceFields,
+ {
+ title: i18n.t('meta.Sinks.SinkFieldName'),
+ dataIndex: 'fieldName',
+ initialValue: '',
+ rules: [
+ { required: true },
+ {
+ pattern: /^[a-zA-Z_][0-9a-z_]*$/,
+ message: i18n.t('meta.Sinks.SinkFieldNameRule'),
+ },
+ ],
+ props: (text, record, idx, isNew) => ({
+ disabled: [110].includes(sinkValues?.status as number) && !isNew,
+ }),
+ },
+ {
+ title: i18n.t('meta.Sinks.SinkFieldType'),
+ dataIndex: 'fieldType',
+ initialValue: fieldTypes[0].value,
+ type: 'select',
+ props: (text, record, idx, isNew) => ({
+ options: fieldTypes,
+ disabled: [110].includes(sinkValues?.status as number) && !isNew,
+ }),
+ rules: [{ required: true, message:
`${i18n.t('meta.Sinks.FieldTypeMessage')}` }],
+ },
+ {
+ title: i18n.t('meta.Sinks.Redis.FieldFormat'),
+ dataIndex: 'fieldFormat',
+ initialValue: 0,
+ type: 'autocomplete',
+ props: (text, record, idx, isNew) => ({
+ options: ['MICROSECONDS', 'MILLISECONDS', 'SECONDS', 'SQL',
'ISO_8601'].map(item => ({
+ label: item,
+ value: item,
+ })),
+ }),
+ visible: (text, record) => ['BIGINT', 'DATE'].includes(record.fieldType
as string),
+ },
+ {
+ title: i18n.t('meta.Sinks.FieldDescription'),
+ dataIndex: 'fieldComment',
+ initialValue: '',
+ },
+ ];
+};
diff --git a/inlong-dashboard/src/plugins/sinks/defaults/index.ts
b/inlong-dashboard/src/plugins/sinks/defaults/index.ts
index 0fe788c103..c916f8dcab 100644
--- a/inlong-dashboard/src/plugins/sinks/defaults/index.ts
+++ b/inlong-dashboard/src/plugins/sinks/defaults/index.ts
@@ -126,4 +126,9 @@ export const allDefaultSinks:
MetaExportWithBackendList<SinkMetaType> = [
value: 'KUDU',
LoadEntity: () => import('./Kudu'),
},
+ {
+ label: 'Http',
+ value: 'HTTP',
+ LoadEntity: () => import('./Http'),
+ },
];
diff --git a/inlong-dashboard/src/ui/locales/cn.json
b/inlong-dashboard/src/ui/locales/cn.json
index b97e66643b..d68a58001c 100644
--- a/inlong-dashboard/src/ui/locales/cn.json
+++ b/inlong-dashboard/src/ui/locales/cn.json
@@ -171,6 +171,12 @@
"meta.Sinks.EnableCreateResource": "是否创建资源",
"meta.Sinks.EnableCreateResourceHelp":
"如果库表已经存在,且无需修改,则选【不创建】,否则请选择【创建】,由系统自动创建资源。",
"meta.Sinks.DataNodeName": "数据节点",
+ "meta.Sinks.Http.MaxRetryTimes": "最大重试次数",
+ "meta.Sinks.Http.Headers": "请求头",
+ "meta.Sinks.Http.Method": "请求方式",
+ "meta.Sinks.Http.Path": "请求路径",
+ "meta.Sinks.Http.FieldName": "参数名",
+ "meta.Sinks.Http.FieldValue": "参数值",
"meta.Sinks.FieldTypeMessage": "请输入字段类型",
"meta.Sinks.Hive.FileFormat": "落地格式",
"meta.Sinks.Hive.Day": "天",
@@ -532,6 +538,11 @@
"meta.Nodes.StarRocks.Url": "地址",
"meta.Nodes.Hive.Username": "用户名",
"meta.Nodes.Hive.Password": "密码",
+ "meta.Nodes.Http.Username": "用户名",
+ "meta.Nodes.Http.Password": "密码",
+ "meta.Nodes.Http.BaseUrl": "基础路径",
+ "meta.Nodes.Http.EnableCredential": "启用凭证",
+ "meta.Nodes.Http.MaxConnect": "最大连接数",
"meta.Nodes.Hudi.Username": "用户名",
"meta.Nodes.Hudi.Password": "密码",
"meta.Nodes.Hudi.Url": "地址",
diff --git a/inlong-dashboard/src/ui/locales/en.json
b/inlong-dashboard/src/ui/locales/en.json
index ebf2bbfcb1..144e15e37d 100644
--- a/inlong-dashboard/src/ui/locales/en.json
+++ b/inlong-dashboard/src/ui/locales/en.json
@@ -171,6 +171,12 @@
"meta.Sinks.EnableCreateResource": "Create resource",
"meta.Sinks.EnableCreateResourceHelp": "If the library table already exists
and does not need to be modified, select [Do not create], otherwise select
[Create], and the system will automatically create the resource.",
"meta.Sinks.DataNodeName": "Data node",
+ "meta.Sinks.Http.MaxRetryTimes": "Max Retry Times",
+ "meta.Sinks.Http.Headers": "Headers",
+ "meta.Sinks.Http.Method": "Method",
+ "meta.Sinks.Http.Path": "Path",
+ "meta.Sinks.Http.FieldName": "Field Name",
+ "meta.Sinks.Http.FieldValue": "Field Value",
"meta.Sinks.FieldTypeMessage": "Please enter field type",
"meta.Sinks.Hive.FileFormat": "File format",
"meta.Sinks.Hive.Day": "Day(s)",
@@ -542,6 +548,11 @@
"meta.Nodes.Redis.ClusterMode": "Cluster mode",
"meta.Nodes.Redis.ClusterModeHelper": "Please select custer mode",
"meta.Nodes.Redis.PortHelper": "Please select Redis server port, default:
6379",
+ "meta.Nodes.Http.Username": "Username",
+ "meta.Nodes.Http.Password": "Password",
+ "meta.Nodes.Http.BaseUrl": "Base url",
+ "meta.Nodes.Http.EnableCredential": "EnableCredential",
+ "meta.Nodes.Http.MaxConnect": "MaxConnect",
"meta.Nodes.Hudi.Username": "Username",
"meta.Nodes.Hudi.Password": "Password",
"meta.Nodes.Hudi.Url": "URL",
diff --git a/inlong-dashboard/src/ui/pages/Clusters/CreateModal.tsx
b/inlong-dashboard/src/ui/pages/Clusters/CreateModal.tsx
index bf5645c58c..988f41613c 100644
--- a/inlong-dashboard/src/ui/pages/Clusters/CreateModal.tsx
+++ b/inlong-dashboard/src/ui/pages/Clusters/CreateModal.tsx
@@ -71,7 +71,8 @@ const Comp: React.FC<Props> = ({ id, defaultType,
...modalProps }) => {
values.type === 'SORT_ES' ||
values.type === 'SORT_CKAFKA' ||
values.type === 'SORT_KAFKA' ||
- values.type === 'SORT_PULSAR'
+ values.type === 'SORT_PULSAR' ||
+ values.type === 'SORT_HTTP'
) {
submitData.name = values.displayName;
}