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 4425586894 [INLONG-10632][Dashboard] Dashboard Add Oceanbase Support 
(#10698)
4425586894 is described below

commit 4425586894b91495a17556a3814d2f0a6a71c301
Author: xxsc0529 <[email protected]>
AuthorDate: Wed Jul 24 11:04:10 2024 +0800

    [INLONG-10632][Dashboard] Dashboard Add Oceanbase Support (#10698)
---
 README.md                                          |   1 +
 inlong-dashboard/src/plugins/images/OceanBase.png  | Bin 0 -> 50206 bytes
 .../src/plugins/nodes/defaults/OceanBase.ts        |  64 +++++
 .../src/plugins/nodes/defaults/index.ts            |   5 +
 .../src/plugins/sinks/defaults/OceanBase.ts        | 265 +++++++++++++++++++++
 .../src/plugins/sinks/defaults/index.ts            |   5 +
 .../plugins/sources/defaults/OceanBaseBinlog.ts    | 204 ++++++++++++++++
 .../src/plugins/sources/defaults/index.ts          |   5 +
 .../src/ui/components/FieldList/FieldTypeConf.tsx  |  27 ++-
 inlong-dashboard/src/ui/locales/cn.json            |   9 +
 inlong-dashboard/src/ui/locales/en.json            |   9 +
 11 files changed, 593 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 6c09eca8ba..9eef5e4a45 100644
--- a/README.md
+++ b/README.md
@@ -104,6 +104,7 @@ You can use InLong in the following ways:
 |              | StarRocks         | >= 2.0                       |
 |              | Kudu              | >= 1.12.0                    |
 |              | Redis             | >= 3.0                       |
+|              | OceanBase         | >= 1.0                       |
 
 ## Build InLong
 More detailed instructions can be found at [Quick 
Start](https://inlong.apache.org/docs/next/quick_start/how_to_build) section in 
the documentation.
diff --git a/inlong-dashboard/src/plugins/images/OceanBase.png 
b/inlong-dashboard/src/plugins/images/OceanBase.png
new file mode 100644
index 0000000000..e67803d72f
Binary files /dev/null and b/inlong-dashboard/src/plugins/images/OceanBase.png 
differ
diff --git a/inlong-dashboard/src/plugins/nodes/defaults/OceanBase.ts 
b/inlong-dashboard/src/plugins/nodes/defaults/OceanBase.ts
new file mode 100644
index 0000000000..d73bcaab92
--- /dev/null
+++ b/inlong-dashboard/src/plugins/nodes/defaults/OceanBase.ts
@@ -0,0 +1,64 @@
+/*
+ * 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';
+
+const { I18n } = DataWithBackend;
+const { FieldDecorator } = RenderRow;
+
+export default class OceanBaseNode
+  extends NodeInfo
+  implements DataWithBackend, RenderRow, RenderList
+{
+  @FieldDecorator({
+    type: 'input',
+    rules: [{ required: true }],
+  })
+  @I18n('meta.Nodes.OceanBase.Username')
+  username: string;
+
+  @FieldDecorator({
+    type: 'password',
+    rules: [{ required: true }],
+  })
+  @I18n('meta.Nodes.OceanBase.Password')
+  token: string;
+
+  @FieldDecorator({
+    type: 'input',
+    rules: [{ required: true }],
+    props: {
+      placeholder: '127.0.0.1:2883',
+    },
+  })
+  @I18n('meta.Nodes.OceanBase.Url')
+  url: string;
+
+  @FieldDecorator({
+    type: 'input',
+    props: {
+      placeholder: '127.0.0.1:2883',
+    },
+  })
+  @I18n('meta.Nodes.OceanBase.BackupUrl')
+  backupUrl: string;
+}
diff --git a/inlong-dashboard/src/plugins/nodes/defaults/index.ts 
b/inlong-dashboard/src/plugins/nodes/defaults/index.ts
index 212b0e53ef..06209fd940 100644
--- a/inlong-dashboard/src/plugins/nodes/defaults/index.ts
+++ b/inlong-dashboard/src/plugins/nodes/defaults/index.ts
@@ -66,6 +66,11 @@ export const allDefaultNodes: 
MetaExportWithBackendList<NodeMetaType> = [
     value: 'MYSQL',
     LoadEntity: () => import('./MySQL'),
   },
+  {
+    label: 'OceanBase',
+    value: 'OCEANBASE',
+    LoadEntity: () => import('./OceanBase'),
+  },
   {
     label: 'PostgreSQL',
     value: 'POSTGRESQL',
diff --git a/inlong-dashboard/src/plugins/sinks/defaults/OceanBase.ts 
b/inlong-dashboard/src/plugins/sinks/defaults/OceanBase.ts
new file mode 100644
index 0000000000..299ac99bda
--- /dev/null
+++ b/inlong-dashboard/src/plugins/sinks/defaults/OceanBase.ts
@@ -0,0 +1,265 @@
+/*
+ * 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 { sourceFields } from '../common/sourceFields';
+import { SinkInfo } from '../common/SinkInfo';
+import NodeSelect from '@/ui/components/NodeSelect';
+import CreateTable from '@/ui/components/CreateTable';
+
+const { I18n } = DataWithBackend;
+const { FieldDecorator, SyncField, SyncCreateTableField, IngestionField } = 
RenderRow;
+const { ColumnDecorator } = RenderList;
+
+const fieldTypesConf = {
+  tinyint: (m, d) => (1 <= m && m <= 4 ? '' : '1<=M<=4'),
+  smallint: (m, d) => (1 <= m && m <= 6 ? '' : '1<=M<=6'),
+  mediumint: (m, d) => (1 <= m && m <= 9 ? '' : '1<=M<=9'),
+  int: (m, d) => (1 <= m && m <= 11 ? '' : '1<=M<=11'),
+  float: (m, d) =>
+    1 <= m && m <= 255 && 1 <= d && d <= 30 && d <= m - 2 ? '' : 
'1<=M<=255,1<=D<=30,D<=M-2',
+  bigint: (m, d) => (1 <= m && m <= 20 ? '' : '1<=M<=20'),
+  double: (m, d) =>
+    1 <= m && m <= 255 && 1 <= d && d <= 30 && d <= m - 2 ? '' : 
'1<=M<=255,1<=D<=30,D<=M-2',
+  numeric: (m, d) =>
+    1 <= m && m <= 255 && 1 <= d && d <= 30 && d <= m - 2 ? '' : 
'1<=M<=255,1<=D<=30,D<=M-2',
+  decimal: (m, d) =>
+    1 <= m && m <= 255 && 1 <= d && d <= 30 && d <= m - 2 ? '' : 
'1<=M<=255,1<=D<=30,D<=M-2',
+  boolean: () => '',
+  date: () => '',
+  time: () => '',
+  datetime: () => '',
+  char: (m, d) => (1 <= m && m <= 255 ? '' : '1<=M<=255'),
+  varchar: (m, d) => (1 <= m && m <= 16383 ? '' : '1<=M<=16383'),
+  text: () => '',
+  binary: (m, d) => (1 <= m && m <= 64 ? '' : '1<=M<=64'),
+  varbinary: (m, d) => (1 <= m && m <= 64 ? '' : '1<=M<=64'),
+  blob: () => '',
+};
+
+const fieldTypes = Object.keys(fieldTypesConf).reduce(
+  (acc, key) =>
+    acc.concat({
+      label: key,
+      value: key,
+    }),
+  [],
+);
+
+export default class HiveSink extends SinkInfo implements DataWithBackend, 
RenderRow, RenderList {
+  @FieldDecorator({
+    type: 'input',
+    rules: [{ required: true }],
+    props: values => ({
+      disabled: [110].includes(values?.status),
+    }),
+  })
+  @ColumnDecorator()
+  @I18n('meta.Sinks.OceanBase.DatabaseName')
+  @SyncField()
+  @IngestionField()
+  databaseName: string;
+
+  @FieldDecorator({
+    type: CreateTable,
+    rules: [{ required: true }],
+    props: values => ({
+      disabled: [110].includes(values?.status),
+      sinkType: values.sinkType,
+      inlongGroupId: values.inlongGroupId,
+      inlongStreamId: values.inlongStreamId,
+      fieldName: 'tableName',
+      sinkObj: {
+        ...values,
+      },
+    }),
+  })
+  @ColumnDecorator()
+  @I18n('meta.Sinks.OceanBase.TableName')
+  @SyncField()
+  @IngestionField()
+  tableName: string;
+
+  @FieldDecorator({
+    type: 'input',
+    rules: [{ required: true }],
+    props: values => ({
+      disabled: [110].includes(values?.status),
+    }),
+  })
+  @ColumnDecorator()
+  @I18n('meta.Sinks.OceanBase.PrimaryKey')
+  @SyncField()
+  @IngestionField()
+  primaryKey: string;
+
+  @FieldDecorator({
+    type: 'radio',
+    rules: [{ required: true }],
+    initialValue: 1,
+    tooltip: i18n.t('meta.Sinks.EnableCreateResourceHelp'),
+    props: values => ({
+      disabled: [110].includes(values?.status),
+      options: [
+        {
+          label: i18n.t('basic.Yes'),
+          value: 1,
+        },
+        {
+          label: i18n.t('basic.No'),
+          value: 0,
+        },
+      ],
+    }),
+  })
+  @IngestionField()
+  @I18n('meta.Sinks.EnableCreateResource')
+  enableCreateResource: number;
+
+  @FieldDecorator({
+    type: NodeSelect,
+    rules: [{ required: true }],
+    props: values => ({
+      disabled: [110].includes(values?.status),
+      nodeType: 'OceanBase',
+    }),
+  })
+  @SyncField()
+  @IngestionField()
+  @I18n('meta.Sinks.DataNodeName')
+  dataNodeName: string;
+
+  @FieldDecorator({
+    type: EditableTable,
+    props: values => ({
+      size: 'small',
+      editing: ![110].includes(values?.status),
+      columns: getFieldListColumns(values),
+      canBatchAdd: true,
+      upsertByFieldKey: true,
+    }),
+  })
+  @IngestionField()
+  sinkFieldList: Record<string, unknown>[];
+
+  @FieldDecorator({
+    type: EditableTable,
+    initialValue: [],
+    props: values => ({
+      size: 'small',
+      editing: ![110].includes(values?.status),
+      columns: getFieldListColumns(values).filter(
+        item => item.dataIndex !== 'sourceFieldName' && item.dataIndex !== 
'sourceFieldType',
+      ),
+      canBatchAdd: true,
+      upsertByFieldKey: true,
+    }),
+  })
+  @SyncCreateTableField()
+  createTableField: 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: 'autocomplete',
+      props: (text, record, idx, isNew) => ({
+        options: fieldTypes,
+        disabled: [110].includes(sinkValues?.status as number) && !isNew,
+        allowClear: true,
+      }),
+      rules: [
+        { required: true, message: `${i18n.t('meta.Sinks.FieldTypeMessage')}` 
},
+        () => ({
+          validator(_, val) {
+            if (val) {
+              const [, type = val, typeLength = ''] = 
val.match(/^(.+)\((.+)\)$/) || [];
+              if (fieldTypesConf.hasOwnProperty(type)) {
+                const [m = -1, d = -1] = typeLength.split(',');
+                const errMsg = fieldTypesConf[type]?.(m, d);
+                if (typeLength && errMsg) return Promise.reject(new 
Error(errMsg));
+              } else {
+                return Promise.reject(new Error('FieldType error'));
+              }
+            }
+            return Promise.resolve();
+          },
+        }),
+      ],
+    },
+    {
+      title: i18n.t('meta.Sinks.OceanBase.IsMetaField'),
+      dataIndex: 'isMetaField',
+      initialValue: 0,
+      type: 'select',
+      props: (text, record, idx, isNew) => ({
+        options: [
+          {
+            label: i18n.t('basic.Yes'),
+            value: 1,
+          },
+          {
+            label: i18n.t('basic.No'),
+            value: 0,
+          },
+        ],
+      }),
+    },
+    {
+      title: i18n.t('meta.Sinks.OceanBase.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', 'TIMESTAMP'].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 d9b5ef5220..0fe788c103 100644
--- a/inlong-dashboard/src/plugins/sinks/defaults/index.ts
+++ b/inlong-dashboard/src/plugins/sinks/defaults/index.ts
@@ -81,6 +81,11 @@ export const allDefaultSinks: 
MetaExportWithBackendList<SinkMetaType> = [
     value: 'MYSQL',
     LoadEntity: () => import('./MySQL'),
   },
+  {
+    label: 'OceanBase',
+    value: 'OCEANBASE',
+    LoadEntity: () => import('./OceanBase'),
+  },
   {
     label: 'Oracle',
     value: 'ORACLE',
diff --git a/inlong-dashboard/src/plugins/sources/defaults/OceanBaseBinlog.ts 
b/inlong-dashboard/src/plugins/sources/defaults/OceanBaseBinlog.ts
new file mode 100644
index 0000000000..31645656c7
--- /dev/null
+++ b/inlong-dashboard/src/plugins/sources/defaults/OceanBaseBinlog.ts
@@ -0,0 +1,204 @@
+/*
+ * 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 { SourceInfo } from '../common/SourceInfo';
+
+const { I18n } = DataWithBackend;
+const { FieldDecorator, SyncField, SyncMoveDbField, IngestionField } = 
RenderRow;
+const { ColumnDecorator } = RenderList;
+
+export default class TubeMqSource
+  extends SourceInfo
+  implements DataWithBackend, RenderRow, RenderList
+{
+  @FieldDecorator({
+    type: 'input',
+    rules: [{ required: true }],
+    props: values => ({
+      disabled: values?.status === 101,
+    }),
+  })
+  @SyncField()
+  @IngestionField()
+  @ColumnDecorator()
+  @SyncMoveDbField()
+  @I18n('meta.Sources.Db.Server')
+  hostname: string;
+
+  @FieldDecorator({
+    type: 'inputnumber',
+    initialValue: 3306,
+    rules: [{ required: true }],
+    props: values => ({
+      disabled: values?.status === 101,
+      min: 0,
+      max: 65535,
+    }),
+  })
+  @SyncField()
+  @IngestionField()
+  @ColumnDecorator()
+  @SyncMoveDbField()
+  @I18n('meta.Sources.Db.Port')
+  port: number;
+
+  @FieldDecorator({
+    type: 'input',
+    rules: [{ required: true }],
+    props: values => ({
+      disabled: values?.status === 101,
+    }),
+  })
+  @SyncField()
+  @IngestionField()
+  @SyncMoveDbField()
+  @I18n('meta.Sources.Db.User')
+  user: string;
+
+  @FieldDecorator({
+    type: 'password',
+    rules: [{ required: true }],
+    props: values => ({
+      disabled: values?.status === 101,
+    }),
+  })
+  @SyncField()
+  @IngestionField()
+  @SyncMoveDbField()
+  @I18n('meta.Sources.Db.Password')
+  password: string;
+
+  @FieldDecorator({
+    type: 'input',
+    rules: [{ required: true }],
+    initialValue: '/data/inlong-agent/.history',
+    props: values => ({
+      disabled: values?.status === 101,
+    }),
+  })
+  @IngestionField()
+  @I18n('meta.Sources.Db.HistoryFilename')
+  historyFilename: string;
+
+  @FieldDecorator({
+    type: 'input',
+    tooltip: 'UTC, UTC+8, Asia/Shanghai, ...',
+    initialValue: 'UTC',
+    rules: [{ required: true }],
+    props: values => ({
+      disabled: values?.status === 101,
+    }),
+  })
+  @IngestionField()
+  @I18n('meta.Sources.Db.ServerTimezone')
+  serverTimezone: string;
+
+  @FieldDecorator({
+    type: 'inputnumber',
+    initialValue: 1000,
+    rules: [{ required: true }],
+    suffix: 'ms',
+    props: values => ({
+      disabled: values?.status === 101,
+      min: 1000,
+      max: 3600000,
+    }),
+  })
+  @IngestionField()
+  @I18n('meta.Sources.Db.IntervalMs')
+  intervalMs: number;
+
+  @FieldDecorator({
+    type: 'radio',
+    rules: [{ required: true }],
+    initialValue: false,
+    props: values => ({
+      disabled: values?.status === 101,
+      options: [
+        {
+          label: i18n.t('basic.Yes'),
+          value: true,
+        },
+        {
+          label: i18n.t('basic.No'),
+          value: false,
+        },
+      ],
+    }),
+  })
+  @IngestionField()
+  @I18n('meta.Sources.Db.AllMigration')
+  allMigration: boolean;
+
+  @FieldDecorator({
+    type: 'radio',
+    rules: [{ required: true }],
+    initialValue: true,
+    props: values => ({
+      disabled: values?.status === 101,
+      options: [
+        {
+          label: i18n.t('meta.Sources.Db.FullAmountAndIncremental'),
+          value: false,
+        },
+        {
+          label: i18n.t('meta.Sources.Db.Incremental'),
+          value: true,
+        },
+      ],
+    }),
+  })
+  @SyncField()
+  @IngestionField()
+  @SyncMoveDbField()
+  @I18n('meta.Sources.Db.ReadMode')
+  onlyIncremental: boolean;
+
+  @FieldDecorator({
+    type: 'input',
+    rules: [{ required: true }],
+    tooltip: i18n.t('meta.Sources.Db.DatabaseWhiteListHelp'),
+    props: values => ({
+      disabled: values?.status === 101,
+    }),
+  })
+  @SyncField()
+  @IngestionField()
+  @SyncMoveDbField()
+  @I18n('meta.Sources.Db.DatabaseWhiteList')
+  databaseWhiteList: string;
+
+  @FieldDecorator({
+    type: 'input',
+    tooltip: i18n.t('meta.Sources.Db.TableWhiteListHelp'),
+    rules: [{ required: true }],
+    props: values => ({
+      disabled: values?.status === 101,
+    }),
+  })
+  @SyncField()
+  @IngestionField()
+  @SyncMoveDbField()
+  @I18n('meta.Sources.Db.TableWhiteList')
+  tableWhiteList: boolean;
+}
diff --git a/inlong-dashboard/src/plugins/sources/defaults/index.ts 
b/inlong-dashboard/src/plugins/sources/defaults/index.ts
index 58d55b30cb..416e7c310f 100644
--- a/inlong-dashboard/src/plugins/sources/defaults/index.ts
+++ b/inlong-dashboard/src/plugins/sources/defaults/index.ts
@@ -50,6 +50,11 @@ export const allDefaultSources: 
MetaExportWithBackendList<SourceMetaType> = [
     value: 'MYSQL_BINLOG',
     LoadEntity: () => import('./MySQLBinlog'),
   },
+  {
+    label: 'OceanBase',
+    value: 'OCEANBASE',
+    LoadEntity: () => import('./OceanBaseBinlog'),
+  },
   {
     label: 'MongoDB',
     value: 'MONGODB',
diff --git a/inlong-dashboard/src/ui/components/FieldList/FieldTypeConf.tsx 
b/inlong-dashboard/src/ui/components/FieldList/FieldTypeConf.tsx
index d1b4a00c24..14fe2473a4 100644
--- a/inlong-dashboard/src/ui/components/FieldList/FieldTypeConf.tsx
+++ b/inlong-dashboard/src/ui/components/FieldList/FieldTypeConf.tsx
@@ -277,7 +277,31 @@ const mysqlTypesConf = {
   varbinary: (m, d) => (1 <= m && m <= 64 ? '' : '1<=M<=64'),
   blob: () => '',
 };
-
+const oceanBaseTypesConf = {
+  tinyint: (m, d) => (1 <= m && m <= 4 ? '' : '1<=M<=4'),
+  smallint: (m, d) => (1 <= m && m <= 6 ? '' : '1<=M<=6'),
+  mediumint: (m, d) => (1 <= m && m <= 9 ? '' : '1<=M<=9'),
+  int: (m, d) => (1 <= m && m <= 11 ? '' : '1<=M<=11'),
+  float: (m, d) =>
+    1 <= m && m <= 255 && 1 <= d && d <= 30 && d <= m - 2 ? '' : 
'1<=M<=255,1<=D<=30,D<=M-2',
+  bigint: (m, d) => (1 <= m && m <= 20 ? '' : '1<=M<=20'),
+  double: (m, d) =>
+    1 <= m && m <= 255 && 1 <= d && d <= 30 && d <= m - 2 ? '' : 
'1<=M<=255,1<=D<=30,D<=M-2',
+  numeric: (m, d) =>
+    1 <= m && m <= 255 && 1 <= d && d <= 30 && d <= m - 2 ? '' : 
'1<=M<=255,1<=D<=30,D<=M-2',
+  decimal: (m, d) =>
+    1 <= m && m <= 255 && 1 <= d && d <= 30 && d <= m - 2 ? '' : 
'1<=M<=255,1<=D<=30,D<=M-2',
+  boolean: () => '',
+  date: () => '',
+  time: () => '',
+  datetime: () => '',
+  char: (m, d) => (1 <= m && m <= 255 ? '' : '1<=M<=255'),
+  varchar: (m, d) => (1 <= m && m <= 16383 ? '' : '1<=M<=16383'),
+  text: () => '',
+  binary: (m, d) => (1 <= m && m <= 64 ? '' : '1<=M<=64'),
+  varbinary: (m, d) => (1 <= m && m <= 64 ? '' : '1<=M<=64'),
+  blob: () => '',
+};
 const oracleTypesConf = {
   binary_float: (m, d) => (1 <= m && m <= 6 ? '' : '1 <= M <= 6'),
   binary_double: (m, d) => (1 <= m && m <= 10 ? '' : '1 <= M <= 10'),
@@ -394,6 +418,7 @@ export const fieldAllTypes = {
   ICEBERG: icebergFieldTypes,
   HUDI: hudiFieldTypes,
   MYSQL: getFieldTypes(mysqlTypesConf),
+  OCEANBASE: getFieldTypes(oceanBaseTypesConf),
   ORACLE: getFieldTypes(oracleTypesConf),
   POSTGRESQL: getFieldTypes(pgTypesConf),
   SQLSERVER: getFieldTypes(sqlServerTypesConf),
diff --git a/inlong-dashboard/src/ui/locales/cn.json 
b/inlong-dashboard/src/ui/locales/cn.json
index 88f10feb5d..59c69445c7 100644
--- a/inlong-dashboard/src/ui/locales/cn.json
+++ b/inlong-dashboard/src/ui/locales/cn.json
@@ -258,6 +258,11 @@
   "meta.Sinks.MySQL.PrimaryKey": "主键",
   "meta.Sinks.MySQL.IsMetaField": "是否为元字段",
   "meta.Sinks.MySQL.FieldFormat": "字段格式",
+  "meta.Sinks.OceanBase.DatabaseName": "数据库名",
+  "meta.Sinks.OceanBase.TableName": "表名称",
+  "meta.Sinks.OceanBase.PrimaryKey": "主键",
+  "meta.Sinks.OceanBase.IsMetaField": "是否为元字段",
+  "meta.Sinks.OceanBase.FieldFormat": "字段格式",
   "meta.Sinks.Oracle.TableName": "表名称",
   "meta.Sinks.Oracle.PrimaryKey": "主键",
   "meta.Sinks.Oracle.IsMetaField": "是否为元字段",
@@ -468,6 +473,10 @@
   "meta.Nodes.MySQL.Password": "密码",
   "meta.Nodes.MySQL.Url": "地址",
   "meta.Nodes.MySQL.BackupUrl": "备份地址",
+  "meta.Nodes.OceanBase.Username": "用户名",
+  "meta.Nodes.OceanBase.Password": "密码",
+  "meta.Nodes.OceanBase.Url": "地址",
+  "meta.Nodes.OceanBase.BackupUrl": "备份地址",
   "meta.Nodes.PostgreSQL.Username": "用户名",
   "meta.Nodes.PostgreSQL.Password": "密码",
   "meta.Nodes.PostgreSQL.Url": "地址",
diff --git a/inlong-dashboard/src/ui/locales/en.json 
b/inlong-dashboard/src/ui/locales/en.json
index 8998a2d13f..2cfb58d6de 100644
--- a/inlong-dashboard/src/ui/locales/en.json
+++ b/inlong-dashboard/src/ui/locales/en.json
@@ -258,6 +258,11 @@
   "meta.Sinks.MySQL.PrimaryKey": "Primary key",
   "meta.Sinks.MySQL.IsMetaField": "Is meta field",
   "meta.Sinks.MySQL.FieldFormat": "Field format",
+  "meta.Sinks.OceanBase.DatabaseName": "Database name",
+  "meta.Sinks.OceanBase.TableName": "Table name",
+  "meta.Sinks.OceanBase.PrimaryKey": "Primary key",
+  "meta.Sinks.OceanBase.IsMetaField": "Is meta field",
+  "meta.Sinks.OceanBase.FieldFormat": "Field format",
   "meta.Sinks.Oracle.TableName": "Table name",
   "meta.Sinks.Oracle.PrimaryKey": "Primary key",
   "meta.Sinks.Oracle.IsMetaField": "Is meta field",
@@ -468,6 +473,10 @@
   "meta.Nodes.MySQL.Password": "Password",
   "meta.Nodes.MySQL.Url": "URL",
   "meta.Nodes.MySQL.BackupUrl": "Backup url",
+  "meta.Nodes.OceanBase.Username": "Username",
+  "meta.Nodes.OceanBase.Password": "Password",
+  "meta.Nodes.OceanBase.Url": "URL",
+  "meta.Nodes.OceanBase.BackupUrl": "Backup url",
   "meta.Nodes.PostgreSQL.Username": "Username",
   "meta.Nodes.PostgreSQL.Password": "Password",
   "meta.Nodes.PostgreSQL.Url": "URL",

Reply via email to