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 45cd578a7 [INLONG-7211][Dashboard] Support Redis sink (#7212) 45cd578a7 is described below commit 45cd578a7c2cddda933714cac939051db6a740ee Author: feat <featzh...@outlook.com> AuthorDate: Wed Jan 11 15:37:42 2023 +0800 [INLONG-7211][Dashboard] Support Redis sink (#7212) --- inlong-dashboard/src/locales/cn.json | 21 ++ inlong-dashboard/src/locales/en.json | 21 ++ inlong-dashboard/src/metas/sinks/defaults/Redis.ts | 330 +++++++++++++++++++++ inlong-dashboard/src/metas/sinks/defaults/index.ts | 5 + 4 files changed, 377 insertions(+) diff --git a/inlong-dashboard/src/locales/cn.json b/inlong-dashboard/src/locales/cn.json index d9a47c92e..cd390a65b 100644 --- a/inlong-dashboard/src/locales/cn.json +++ b/inlong-dashboard/src/locales/cn.json @@ -303,6 +303,27 @@ "meta.Sinks.StarRocks.IsMetaField": "是否为元字段", "meta.Sinks.StarRocks.FieldFormat": "字段格式", "meta.Sinks.StarRocks.FieldDescription": "字段描述", + "meta.Sinks.Redis.clusterModeHelp": "Redis 集群模式, 可为 [cluster|sentinel|standalone]", + "meta.Sinks.Redis.ttlUnit": "秒", + "meta.Sinks.Redis.FieldName": "字段名", + "meta.Sinks.Redis.FieldNameRule": "以英文字母或下划线开头,只能包含英文字母、数字、下划线", + "meta.Sinks.Redis.FieldType": "字段类型", + "meta.Sinks.Redis.IsMetaField": "是否为元字段", + "meta.Sinks.Redis.FieldFormat": "字段格式", + "meta.Sinks.Redis.FieldDescription": "字段描述", + "meta.Sinks.Redis.clusterMode": "集群模式", + "meta.Sinks.Redis.database": "DatabaseID", + "meta.Sinks.Redis.password": "密码", + "meta.Sinks.Redis.ttl": "TTL", + "meta.Sinks.Redis.ExtList": "高级参数", + "meta.Sinks.Redis.Timeout": "超时时间", + "meta.Sinks.Redis.SoTimeout": "读取超时时间", + "meta.Sinks.Redis.MaxTotal": "最大连接数", + "meta.Sinks.Redis.MaxIdle": "最大空闲连接数", + "meta.Sinks.Redis.MinIdle": "最小空闲连接数", + "meta.Sinks.Redis.maxRetries": "最大重试次数", + "meta.Sinks.Redis.dataType": "数据类型", + "meta.Sinks.Redis.schemaMapMode": "Schema映射模式", "meta.Group.InlongGroupId": "数据流组 ID", "meta.Group.InlongGroupIdRules": "只能包含小写字母、数字、中划线、下划线", "meta.Group.InlongGroupName": "数据流组名称", diff --git a/inlong-dashboard/src/locales/en.json b/inlong-dashboard/src/locales/en.json index 4279632fd..a9a1883e5 100644 --- a/inlong-dashboard/src/locales/en.json +++ b/inlong-dashboard/src/locales/en.json @@ -303,6 +303,27 @@ "meta.Sinks.StarRocks.IsMetaField": "IsMetaField", "meta.Sinks.StarRocks.FieldFormat": "FieldFormat", "meta.Sinks.StarRocks.FieldDescription": "FieldDescription", + "meta.Sinks.Redis.clusterModeHelp": "Redis cluster mode, contains [cluster|sentinel|standalone]", + "meta.Sinks.Redis.ttlUnit": "s", + "meta.Sinks.Redis.FieldName": "FieldName", + "meta.Sinks.Redis.FieldNameRule": "At the beginning of English letters, only English letters, numbers, and underscores", + "meta.Sinks.Redis.FieldType": "FieldType", + "meta.Sinks.Redis.IsMetaField": "IsMetaField", + "meta.Sinks.Redis.FieldFormat": "FieldFormat", + "meta.Sinks.Redis.FieldDescription": "FieldDescription", + "meta.Sinks.Redis.clusterMode": "ClusterMode", + "meta.Sinks.Redis.database": "DatabaseID", + "meta.Sinks.Redis.password": "Password", + "meta.Sinks.Redis.ttl": "TTL", + "meta.Sinks.Redis.ExtList": "ExtList", + "meta.Sinks.Redis.Timeout": "TimeOut", + "meta.Sinks.Redis.SoTimeout": "SoTimeout", + "meta.Sinks.Redis.MaxTotal": "Max Total", + "meta.Sinks.Redis.MaxIdle": "Max Idle", + "meta.Sinks.Redis.MinIdle": "Min Idle", + "meta.Sinks.Redis.maxRetries": "Max Retries", + "meta.Sinks.Redis.dataType": "Data Type", + "meta.Sinks.Redis.schemaMapMode": "Schema Map Mode", "meta.Group.InlongGroupId": "Inlong Group ID", "meta.Group.InlongGroupIdRules": "Only lowercase letters, numbers, minus, and underscores", "meta.Group.InlongGroupName": "Inlong Group Name", diff --git a/inlong-dashboard/src/metas/sinks/defaults/Redis.ts b/inlong-dashboard/src/metas/sinks/defaults/Redis.ts new file mode 100644 index 000000000..1fe911331 --- /dev/null +++ b/inlong-dashboard/src/metas/sinks/defaults/Redis.ts @@ -0,0 +1,330 @@ +/* + * 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 '@/metas/DataWithBackend'; +import { RenderRow } from '@/metas/RenderRow'; +import { RenderList } from '@/metas/RenderList'; +import i18n from '@/i18n'; +import EditableTable from '@/components/EditableTable'; +import { sourceFields } from '../common/sourceFields'; +import { SinkInfo } from '../common/SinkInfo'; + +const { I18n } = DataWithBackend; +const { FieldDecorator } = RenderRow; +const { ColumnDecorator } = RenderList; + +const redisTargetTypes = [ + 'BOOLEAN', + 'INT', + 'BIGINT', + 'FLOAT', + 'DOUBLE', + 'DATE', + 'DATETIME', + 'CHAR', + 'TIME', +].map(item => ({ + label: item, + value: item, +})); + +export default class RedisSink extends SinkInfo implements DataWithBackend, RenderRow, RenderList { + @FieldDecorator({ + type: 'select', + rules: [{ required: true }], + initialValue: 0, + tooltip: i18n.t('meta.Sinks.Redis.clusterModeHelp'), + props: values => ({ + disabled: [110, 130].includes(values?.status), + options: [ + { + label: 'cluster', + value: 'cluster', + }, + { + label: 'sentinel', + value: 'sentinel', + }, + { + label: 'standalone', + value: 'standalone', + }, + ], + }), + }) + @I18n('meta.Sinks.Redis.clusterMode') + clusterMode: string; + + @FieldDecorator({ + type: 'inputnumber', + rules: [{ required: false }], + props: values => ({ + disabled: [110, 130].includes(values?.status), + min: 0, + }), + }) + @ColumnDecorator() + @I18n('meta.Sinks.Redis.database') + database: number; + + @FieldDecorator({ + type: 'select', + rules: [{ required: false }], + initialValue: 'PLAIN', + props: values => ({ + disabled: [110, 130].includes(values?.status), + options: [ + { + label: 'PLAIN', + value: 'PLAIN', + }, + { + label: 'HASH', + value: 'HASH', + }, + { + label: 'BITMAP', + value: 'BITMAP', + }, + ], + }), + }) + @ColumnDecorator() + @I18n('meta.Sinks.Redis.dataType') + dataType: string; + + @FieldDecorator({ + type: 'select', + rules: [{ required: false }], + initialValue: 'STATIC_PREFIX_MATCH', + props: values => ({ + disabled: [110, 130].includes(values?.status), + options: [ + { + label: 'STATIC_PREFIX_MATCH', + value: 'STATIC_PREFIX_MATCH', + }, + { + label: 'STATIC_KV_PAIR', + value: 'STATIC_KV_PAIR', + }, + { + label: 'DYNAMIC', + value: 'DYNAMIC', + }, + ], + }), + }) + @ColumnDecorator() + @I18n('meta.Sinks.Redis.schemaMapMode') + schemaMapMode: string; + + @FieldDecorator({ + type: 'password', + rules: [{ required: false }], + initialValue: '', + props: values => ({ + disabled: [110, 130].includes(values?.status), + }), + }) + @ColumnDecorator() + @I18n('meta.Sinks.Redis.password') + password: string; + + @FieldDecorator({ + type: 'inputnumber', + initialValue: 0, + props: values => ({ + disabled: [110, 130].includes(values?.status), + min: 1, + }), + rules: [{ required: true }], + suffix: i18n.t('meta.Sinks.Redis.ttlUnit'), + }) + @I18n('meta.Sinks.Redis.ttl') + ttl: number; + + @FieldDecorator({ + type: EditableTable, + rules: [{ required: false }], + initialValue: [], + props: values => ({ + size: 'small', + columns: [ + { + title: 'Key', + dataIndex: 'keyName', + props: { + disabled: [110, 130].includes(values?.status), + }, + }, + { + title: 'Value', + dataIndex: 'keyValue', + props: { + disabled: [110, 130].includes(values?.status), + }, + }, + ], + }), + }) + @ColumnDecorator() + @I18n('meta.Sinks.Redis.ExtList') + extList: string; + + @FieldDecorator({ + type: EditableTable, + props: values => ({ + size: 'small', + editing: ![110, 130].includes(values?.status), + columns: getFieldListColumns(values), + }), + }) + sinkFieldList: Record<string, unknown>[]; + + @FieldDecorator({ + type: 'inputnumber', + rules: [{ required: true }], + props: values => ({ + disabled: values?.status === 101, + }), + }) + @I18n('meta.Sinks.Redis.Timeout') + timeout: number; + + @FieldDecorator({ + type: 'inputnumber', + rules: [{ required: true }], + props: values => ({ + disabled: values?.status === 101, + }), + }) + @I18n('meta.Sinks.Redis.SoTimeout') + soTimeout: number; + + @FieldDecorator({ + type: 'inputnumber', + rules: [{ required: true }], + props: values => ({ + disabled: values?.status === 101, + }), + }) + @I18n('meta.Sinks.Redis.MaxTotal') + maxTotal: number; + + @FieldDecorator({ + type: 'inputnumber', + rules: [{ required: true }], + props: values => ({ + disabled: values?.status === 101, + }), + }) + @I18n('meta.Sinks.Redis.MaxIdle') + maxIdle: number; + + @FieldDecorator({ + type: 'inputnumber', + rules: [{ required: true }], + props: values => ({ + disabled: values?.status === 101, + }), + }) + @I18n('meta.Sinks.Redis.MinIdle') + minIdle: number; + + @FieldDecorator({ + type: 'inputnumber', + rules: [{ required: true }], + initialValue: 1, + props: values => ({ + disabled: values?.status === 101, + min: 1, + }), + }) + @I18n('meta.Sinks.Redis.maxRetries') + maxRetries: number; +} + +const getFieldListColumns = sinkValues => { + return [ + ...sourceFields, + { + title: `Redis${i18n.t('meta.Sinks.Redis.FieldName')}`, + dataIndex: 'fieldName', + initialValue: '', + rules: [ + { required: true }, + { + pattern: /^[a-z][0-9a-z_]*$/, + message: i18n.t('meta.Sinks.Redis.FieldNameRule'), + }, + ], + props: (text, record, idx, isNew) => ({ + disabled: [110, 130].includes(sinkValues?.status as number) && !isNew, + }), + }, + { + title: `Redis${i18n.t('meta.Sinks.Redis.FieldType')}`, + dataIndex: 'fieldType', + initialValue: redisTargetTypes[0].value, + type: 'select', + props: (text, record, idx, isNew) => ({ + options: redisTargetTypes, + disabled: [110, 130].includes(sinkValues?.status as number) && !isNew, + }), + rules: [{ required: true }], + }, + { + title: i18n.t('meta.Sinks.Redis.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.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.Redis.FieldDescription'), + dataIndex: 'fieldComment', + initialValue: '', + }, + ]; +}; diff --git a/inlong-dashboard/src/metas/sinks/defaults/index.ts b/inlong-dashboard/src/metas/sinks/defaults/index.ts index a19d2d4bb..cb83240d4 100644 --- a/inlong-dashboard/src/metas/sinks/defaults/index.ts +++ b/inlong-dashboard/src/metas/sinks/defaults/index.ts @@ -101,4 +101,9 @@ export const allDefaultSinks: MetaExportWithBackendList<SinkMetaType> = [ value: 'TDSQLPOSTGRESQL', LoadEntity: () => import('./TDSQLPostgreSQL'), }, + { + label: 'Redis', + value: 'REDIS', + LoadEntity: () => import('./Redis'), + }, ];