[Optimize] 新增/编辑MM2 Topic 由当前集群获取改为对应的sourceKafka集群获取& 新增/编辑MM2入参优化(#894)

This commit is contained in:
erge
2023-02-20 16:31:35 +08:00
committed by lucasun
parent 5c26e8947b
commit ae8cc3092b
5 changed files with 93 additions and 60 deletions

View File

@@ -2,7 +2,7 @@ export const regNonnegativeInteger = /^\d+$/g; // 非负正整数
export const regOddNumber = /^\d*[13579]$/; //奇数 export const regOddNumber = /^\d*[13579]$/; //奇数
export const regClusterName = /^[\u4E00-\u9FA5A-Za-z0-9\_\-\!\"\#\$\%&'()\*\+,./\:\;\<=\>?\@\[\\\]^\`\{\|\}~]*$/im; // 大、小写字母、数字、-、_ new RegExp('\[a-z0-9_-]$', 'g') export const regClusterName = /^[\u4E00-\u9FA5A-Za-z0-9\_\-\!\#\$\%&'()\*\+,./\:\;\<=\>?\@\[\\\]^\`\{\|\}~]*$/im; // 大、小写字母、数字、-、_ new RegExp('\[a-z0-9_-]$', 'g')
export const regUsername = /^[_a-zA-Z-]*$/; // 大、小写字母、数字、-、_ new RegExp('\[a-z0-9_-]$', 'g') export const regUsername = /^[_a-zA-Z-]*$/; // 大、小写字母、数字、-、_ new RegExp('\[a-z0-9_-]$', 'g')
export const regIpAddress = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/; export const regIpAddress = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/;

View File

@@ -485,7 +485,7 @@ const StepFormSecond = (props: SubFormProps) => {
} }
if (!new RegExp(regClusterName).test(value)) { if (!new RegExp(regClusterName).test(value)) {
return Promise.reject( return Promise.reject(
'Connector 名称支持中英文、数字、特殊字符 ! " # $ % & \' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~' "Connector 名称支持中英文、数字、特殊字符 ! # $ % & ' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~"
); );
} }
return Utils.request(api.isConnectorExist(prevForm.getFieldValue('connectClusterId'), value)).then( return Utils.request(api.isConnectorExist(prevForm.getFieldValue('connectClusterId'), value)).then(

View File

@@ -37,6 +37,7 @@ const DraggableCharts = (): JSX.Element => {
connectClusters: [], connectClusters: [],
connectors: [], connectors: [],
}); });
const [screenType, setScreenType] = useState('all');
const curFetchingTimestamp = useRef(0); const curFetchingTimestamp = useRef(0);
const metricRankList = useRef<string[]>([]); const metricRankList = useRef<string[]>([]);
const metricFilterRef = useRef(null); const metricFilterRef = useRef(null);
@@ -149,7 +150,14 @@ const DraggableCharts = (): JSX.Element => {
const nullDataMetricData = [...newConnectClusterData, ...newConnectorData].filter((item) => item !== null); const nullDataMetricData = [...newConnectClusterData, ...newConnectorData].filter((item) => item !== null);
formattedMetricData.sort((a, b) => metricRankList.current.indexOf(a.metricName) - metricRankList.current.indexOf(b.metricName)); formattedMetricData.sort((a, b) => metricRankList.current.indexOf(a.metricName) - metricRankList.current.indexOf(b.metricName));
nullDataMetricData.sort((a, b) => metricRankList.current.indexOf(a.metricName) - metricRankList.current.indexOf(b.metricName)); nullDataMetricData.sort((a, b) => metricRankList.current.indexOf(a.metricName) - metricRankList.current.indexOf(b.metricName));
setMetricChartData([...formattedMetricData, ...nullDataMetricData]); const filterMetricData = [...formattedMetricData, ...nullDataMetricData];
setMetricChartData(
screenType === 'Connect'
? filterMetricData.filter((item) => item.metricType === MetricType.Connect)
: screenType === 'Connector'
? filterMetricData.filter((item) => item.metricType === MetricType.Connectors)
: filterMetricData
);
} else { } else {
setMetricChartData([]); setMetricChartData([]);
} }
@@ -216,7 +224,7 @@ const DraggableCharts = (): JSX.Element => {
if (Object.values(metricList).some((list) => list.length) && curHeaderOptions) { if (Object.values(metricList).some((list) => list.length) && curHeaderOptions) {
getMetricChartData(); getMetricChartData();
} }
}, [curHeaderOptions]); }, [curHeaderOptions, screenType]);
useEffect(() => { useEffect(() => {
if (Object.values(metricList).some((list) => list.length) && curHeaderOptions) { if (Object.values(metricList).some((list) => list.length) && curHeaderOptions) {
@@ -242,6 +250,7 @@ const DraggableCharts = (): JSX.Element => {
name: 'Connect', name: 'Connect',
customContent: <SelectContent scopeList={scopeList} title="请选择 Connect 范围" />, customContent: <SelectContent scopeList={scopeList} title="请选择 Connect 范围" />,
}} }}
setScreenType={setScreenType}
/> />
<MetricsFilter <MetricsFilter
ref={metricFilterRef} ref={metricFilterRef}

View File

@@ -1,5 +1,5 @@
import React, { createContext, createElement, forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState } from 'react'; import React, { createContext, createElement, forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { Alert, Button, Drawer, Form, Input, InputNumber, Radio, Select, Steps, Switch, Table, Transfer, Utils } from 'knowdesign'; import { Alert, Button, Drawer, Form, Input, InputNumber, Radio, Select, Spin, Steps, Switch, Table, Transfer, Utils } from 'knowdesign';
import { FormInstance } from 'knowdesign/es/basic/form/Form'; import { FormInstance } from 'knowdesign/es/basic/form/Form';
import message from '@src/components/Message'; import message from '@src/components/Message';
import api from '@src/api'; import api from '@src/api';
@@ -136,6 +136,8 @@ const StepFormFirst = (props: SubFormProps) => {
}>(); }>();
const [form] = useStepForm(0); const [form] = useStepForm(0);
const [topicData, setTopicData] = useState([]); const [topicData, setTopicData] = useState([]);
const [topicDataLoading, setTopicDataLoading] = useState(false);
const [givenSourceKafkaId, setGivenSourceKafkaId] = useState(clusterId);
const { type, detail, setSourceKafkaClusterId, setBootstrapServers, setSourceDetailConfigs, setCheckoutPointDetailConfigs } = const { type, detail, setSourceKafkaClusterId, setBootstrapServers, setSourceDetailConfigs, setCheckoutPointDetailConfigs } =
useContext(StepsFormContent); useContext(StepsFormContent);
const isEdit = type === 'edit'; const isEdit = type === 'edit';
@@ -178,21 +180,26 @@ const StepFormFirst = (props: SubFormProps) => {
}; };
// 获取Topic列表 // 获取Topic列表
const getTopicList = () => { const getTopicList = (givenSourceKafkaId: any) => {
// ! 需整理 // ! 需整理
Utils.request(api.getTopicMetaList(Number(clusterId))).then((res: any) => { setTopicDataLoading(true);
const dataDe = res || []; Utils.request(api.getTopicMetaList(Number(givenSourceKafkaId)))
const dataHandle = dataDe.map((item: any) => { .then((res: any) => {
return { const dataDe = res || [];
...item, const dataHandle = dataDe.map((item: any) => {
key: item.topicName, return {
label: item.topicName, ...item,
value: item.topicName, key: item.topicName,
title: item.topicName, label: item.topicName,
}; value: item.topicName,
title: item.topicName,
};
});
setTopicData(dataHandle);
})
.finally(() => {
setTopicDataLoading(false);
}); });
setTopicData(dataHandle);
});
}; };
const getMM2Config = (connectClusterId: string | number) => { const getMM2Config = (connectClusterId: string | number) => {
@@ -207,7 +214,6 @@ const StepFormFirst = (props: SubFormProps) => {
const detailConfigs: any[] = isEdit && res.length > 1 ? res?.[2] : []; const detailConfigs: any[] = isEdit && res.length > 1 ? res?.[2] : [];
let sourceConfigs: any; let sourceConfigs: any;
let checkpointConfigs: any; let checkpointConfigs: any;
detailConfigs?.forEach((config) => { detailConfigs?.forEach((config) => {
if (config['connector.class'] === 'org.apache.kafka.connect.mirror.MirrorCheckpointConnector') { if (config['connector.class'] === 'org.apache.kafka.connect.mirror.MirrorCheckpointConnector') {
checkpointConfigs = config; checkpointConfigs = config;
@@ -215,6 +221,7 @@ const StepFormFirst = (props: SubFormProps) => {
} else if (config['connector.class'] === 'org.apache.kafka.connect.mirror.MirrorSourceConnector') { } else if (config['connector.class'] === 'org.apache.kafka.connect.mirror.MirrorSourceConnector') {
sourceConfigs = config; sourceConfigs = config;
setSourceDetailConfigs(config); setSourceDetailConfigs(config);
setGivenSourceKafkaId(sourceConfigs['source.cluster.alias']);
} }
}); });
const formItemValue: any = {}; const formItemValue: any = {};
@@ -222,36 +229,47 @@ const StepFormFirst = (props: SubFormProps) => {
res?.[0].configs.forEach(({ definition }: any) => { res?.[0].configs.forEach(({ definition }: any) => {
if (existConfigItems.sourceConfigs.includes(definition.name)) { if (existConfigItems.sourceConfigs.includes(definition.name)) {
if (isEdit && sourceConfigs[definition.name]) { if (isEdit && sourceConfigs[definition.name]) {
formItemValue[definition.name] = sourceConfigs[definition.name];
if (definition.name === 'topics') { if (definition.name === 'topics') {
sourceConfigs[definition.name] !== '.*' formItemValue[definition.name] = topicTargetKeys || sourceConfigs[definition.name];
? formItemValues.push({ if (sourceConfigs[definition.name] === '.*' && topicTargetKeys.length < 1) {
formItemValues.push({
name: 'priority',
value: 'allTopic',
});
} else {
formItemValues.push(
{
name: 'topics', name: 'topics',
value: sourceConfigs[definition.name].split(',') || null, value: topicTargetKeys.length > 0 ? topicTargetKeys : sourceConfigs[definition.name].split(','),
}) },
: formItemValues.push({ { name: 'priority', value: 'givenTopic' }
name: 'priority', );
value: 'allTopic', topicTargetKeys.length < 1 && setTopicTargetKeys(sourceConfigs[definition.name].split(','));
}); }
} else { } else {
formItemValue[definition.name] = sourceConfigs[definition.name];
formItemValues.push({ formItemValues.push({
name: definition.name, name: definition.name,
value: sourceConfigs[definition.name] || null, value: sourceConfigs[definition.name] || null,
}); });
} }
} else { } else {
formItemValue[definition.name] = definition.defaultValue;
if (definition.name === 'topics') { if (definition.name === 'topics') {
definition.defaultValue !== '.*' formItemValue['topics'] = topicTargetKeys || definition.defaultValue.split(',');
definition.defaultValue === '.*' && topicTargetKeys.length < 1
? formItemValues.push({ ? formItemValues.push({
name: 'topics',
value: definition.defaultValue.split(',') || null,
})
: formItemValues.push({
name: 'priority', name: 'priority',
value: 'allTopic', value: 'allTopic',
}); })
: formItemValues.push(
{
name: 'topics',
value: topicTargetKeys || definition.defaultValue,
},
{ name: 'priority', value: 'givenTopic' }
);
} else { } else {
formItemValue[definition.name] = definition.defaultValue;
formItemValues.push({ formItemValues.push({
name: definition.name, name: definition.name,
value: definition.defaultValue || null, value: definition.defaultValue || null,
@@ -290,11 +308,14 @@ const StepFormFirst = (props: SubFormProps) => {
}; };
useEffect(() => { useEffect(() => {
getTopicList();
getConnectClustersList(); getConnectClustersList();
getSourceKafkaClustersList(); getSourceKafkaClustersList();
}, []); }, []);
useEffect(() => {
getTopicList(givenSourceKafkaId);
}, [givenSourceKafkaId]);
useEffect(() => { useEffect(() => {
form.resetFields(existConfigItems.sourceConfigs); form.resetFields(existConfigItems.sourceConfigs);
form.setFields(formItemValues); form.setFields(formItemValues);
@@ -306,6 +327,9 @@ const StepFormFirst = (props: SubFormProps) => {
setBootstrapServers(bootstrapServers); setBootstrapServers(bootstrapServers);
}, [sourcekafkaClustersId]); }, [sourcekafkaClustersId]);
useEffect(() => {
form.setFieldsValue({ topics: topicTargetKeys });
}, [topicTargetKeys]);
// useEffect(() => { // useEffect(() => {
// connectorConfig && // connectorConfig &&
// form.setFieldsValue({ // form.setFieldsValue({
@@ -332,7 +356,6 @@ const StepFormFirst = (props: SubFormProps) => {
'emit.checkpoints.interval.seconds': 60, 'emit.checkpoints.interval.seconds': 60,
'checkpoints.topic.replication.factor': false, 'checkpoints.topic.replication.factor': false,
'replication.policy.separator': '.', 'replication.policy.separator': '.',
priority: 'allTopic',
}; };
form.setFieldsValue(config); form.setFieldsValue(config);
setFormItemValue((state: any) => { setFormItemValue((state: any) => {
@@ -366,9 +389,7 @@ const StepFormFirst = (props: SubFormProps) => {
return Promise.reject('MM2任务名称长度限制在164字符'); return Promise.reject('MM2任务名称长度限制在164字符');
} }
if (!new RegExp(regClusterName).test(value)) { if (!new RegExp(regClusterName).test(value)) {
return Promise.reject( return Promise.reject("MM2 名称支持中英文、数字、特殊字符 ! # $ % & ' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~");
'MM2 名称支持中英文、数字、特殊字符 ! " # $ % & \' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~'
);
} }
return Promise.resolve(); return Promise.resolve();
// return Utils.request(api.isConnectorExist(prevForm.getFieldValue('connectClusterId'), value)).then( // return Utils.request(api.isConnectorExist(prevForm.getFieldValue('connectClusterId'), value)).then(
@@ -398,6 +419,7 @@ const StepFormFirst = (props: SubFormProps) => {
onChange={(e, option: any) => { onChange={(e, option: any) => {
setSourcekafkaClustersId(e); setSourcekafkaClustersId(e);
setSourceKafkaClusterId(option?.value); setSourceKafkaClusterId(option?.value);
setGivenSourceKafkaId(option?.value);
}} }}
/> />
</Form.Item> </Form.Item>
@@ -421,22 +443,24 @@ const StepFormFirst = (props: SubFormProps) => {
}, },
]} ]}
> >
<Transfer <Spin spinning={topicDataLoading}>
dataSource={topicData} <Transfer
titles={['待选Topic', '已选Topic']} dataSource={topicData}
customHeader titles={['待选Topic', '已选Topic']}
showSelectedCount customHeader
locale={{ showSelectedCount
itemUnit: '', locale={{
itemsUnit: '', itemUnit: '',
}} itemsUnit: '',
showSearch }}
filterOption={(inputValue, option) => option.topicName.indexOf(inputValue) > -1} showSearch
targetKeys={topicTargetKeys} filterOption={(inputValue, option) => option.topicName.indexOf(inputValue) > -1}
onChange={topicChange} targetKeys={topicTargetKeys}
render={(item) => item.title} onChange={topicChange}
suffix={<IconFont type="icon-fangdajing" />} render={(item) => item.title}
/> suffix={<IconFont type="icon-fangdajing" />}
/>
</Spin>
</Form.Item> </Form.Item>
) : null; ) : null;
}} }}
@@ -1006,7 +1030,7 @@ export default forwardRef(
'emit.checkpoints.enabled': result['emit.checkpoints.enabled'], 'emit.checkpoints.enabled': result['emit.checkpoints.enabled'],
'emit.checkpoints.interval.seconds': result['emit.checkpoints.interval.seconds'], 'emit.checkpoints.interval.seconds': result['emit.checkpoints.interval.seconds'],
'checkpoints.topic.replication.factor': result['checkpoints.topic.replication.factor'], 'checkpoints.topic.replication.factor': result['checkpoints.topic.replication.factor'],
'source.cluster.alias': sourceKafkaClusterId, 'source.cluster.alias': sourceKafkaClusterId || res[0].sourceKafkaClusterId,
name: detail?.checkpointConnector || result.name, name: detail?.checkpointConnector || result.name,
'source.cluster.bootstrap.servers': bootstrapServers || checkoutPointDetailConfigs?.['source.cluster.bootstrap.servers'], 'source.cluster.bootstrap.servers': bootstrapServers || checkoutPointDetailConfigs?.['source.cluster.bootstrap.servers'],
}; };
@@ -1015,7 +1039,7 @@ export default forwardRef(
'connector.class': 'org.apache.kafka.connect.mirror.MirrorHeartbeatConnector', 'connector.class': 'org.apache.kafka.connect.mirror.MirrorHeartbeatConnector',
'heartbeats.topic.replication.factor': result['heartbeats.topic.replication.factor'], 'heartbeats.topic.replication.factor': result['heartbeats.topic.replication.factor'],
'emit.heartbeats.interval.seconds': result['emit.heartbeats.interval.seconds'], 'emit.heartbeats.interval.seconds': result['emit.heartbeats.interval.seconds'],
'source.cluster.alias': sourceKafkaClusterId, 'source.cluster.alias': sourceKafkaClusterId || res[0].sourceKafkaClusterId,
name: detail?.heartbeatConnector || result.name, name: detail?.heartbeatConnector || result.name,
'source.cluster.bootstrap.servers': bootstrapServers || heartbeatDetailConfigs?.['source.cluster.bootstrap.servers'], 'source.cluster.bootstrap.servers': bootstrapServers || heartbeatDetailConfigs?.['source.cluster.bootstrap.servers'],
}; };
@@ -1036,7 +1060,7 @@ export default forwardRef(
'replication.policy.class': result['replication.policy.class'], 'replication.policy.class': result['replication.policy.class'],
'replication.policy.separator': result['replication.policy.separator'], 'replication.policy.separator': result['replication.policy.separator'],
topics: result['priority'] === 'givenTopic' ? result['topics'].join() : '.*', topics: result['priority'] === 'givenTopic' ? result['topics'].join() : '.*',
'source.cluster.alias': sourceKafkaClusterId, 'source.cluster.alias': sourceKafkaClusterId || res[0].sourceKafkaClusterId,
name: result.name, name: result.name,
'source.cluster.bootstrap.servers': bootstrapServers || sourceDetailConfigs?.['source.cluster.bootstrap.servers'], 'source.cluster.bootstrap.servers': bootstrapServers || sourceDetailConfigs?.['source.cluster.bootstrap.servers'],
}; };

View File

@@ -204,7 +204,7 @@ const ClusterTabContent = forwardRef((props: any, ref): JSX.Element => {
return Promise.reject('集群名称长度限制在1128字符'); return Promise.reject('集群名称长度限制在1128字符');
} }
if (!new RegExp(regClusterName).test(value)) { if (!new RegExp(regClusterName).test(value)) {
return Promise.reject('集群名称支持中英文、数字、特殊字符 ! " # $ % & \' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~'); return Promise.reject("集群名称支持中英文、数字、特殊字符 ! # $ % & ' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~");
} }
return Utils.request(api.getClusterBasicExit(value)) return Utils.request(api.getClusterBasicExit(value))
.then((res: any) => { .then((res: any) => {