Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions km-console/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ module.exports = {
'prettier/prettier': 2, // 这项配置 对于不符合prettier规范的写法,eslint会提示报错
'no-console': 1,
'react/display-name': 0,
'@typescript-eslint/explicit-module-boundary-types': 'off',
},
};
38 changes: 36 additions & 2 deletions km-console/packages/layout-clusters-fe/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export enum MetricType {
Connect = 120,
Connectors = 121,
Controls = 901,
MM2 = 122,
}

const api = {
Expand Down Expand Up @@ -233,9 +234,9 @@ const api = {
getConnectors: (clusterPhyId: string) => getApi(`/clusters/${clusterPhyId}/connectors-basic`),
getConnectorMetrics: (clusterPhyId: string) => getApi(`/clusters/${clusterPhyId}/connectors-metrics`),
getConnectorPlugins: (connectClusterId: number) => getApi(`/kafka-connect/clusters/${connectClusterId}/connector-plugins`),
getConnectorPluginConfig: (connectClusterId: number, pluginName: string) =>
getConnectorPluginConfig: (connectClusterId: number | string, pluginName: string) =>
getApi(`/kafka-connect/clusters/${connectClusterId}/connector-plugins/${pluginName}/config`),
getCurPluginConfig: (connectClusterId: number, connectorName: string) =>
getCurPluginConfig: (connectClusterId: number | string, connectorName: string) =>
getApi(`/kafka-connect/clusters/${connectClusterId}/connectors/${connectorName}/config`),
isConnectorExist: (connectClusterId: number, connectorName: string) =>
getApi(`/kafka-connect/clusters/${connectClusterId}/connectors/${connectorName}/basic-combine-exist`),
Expand All @@ -251,6 +252,39 @@ const api = {

getConnectClusterBasicExit: (clusterPhyId: string, clusterPhyName: string) =>
getApi(`/kafka-clusters/${clusterPhyId}/connect-clusters/${clusterPhyName}/basic-combine-exist`),

// MM2 列表
getMirrorMakerList: (clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/mirror-makers-overview`),
// MM2 状态卡片
getMirrorMakerState: (clusterPhyId: string) => getApi(`/kafka-clusters/${clusterPhyId}/mirror-makers-state`),
// MM2 指标卡片
getMirrorMakerMetrics: (clusterPhyId: string) => getApi(`/clusters/${clusterPhyId}/mirror-makers-metrics`),
// MM2 筛选
getMirrorMakerMetadata: (clusterPhyId: string) => getApi(`/clusters/${clusterPhyId}/mirror-makers-basic`),
// MM2 详情列表
getMM2DetailTasks: (connectorName: number | string, connectClusterId: number | string) =>
getApi(`/kafka-mm2/clusters/${connectClusterId}/connectors/${connectorName}/tasks`),
// MM2 详情状态卡片
getMM2DetailState: (connectorName: number | string, connectClusterId: number | string) =>
getApi(`/kafka-mm2/clusters/${connectClusterId}/connectors/${connectorName}/state`),
// MM2 操作接口 新增、暂停、重启、删除
mirrorMakerOperates: getApi('/kafka-mm2/mirror-makers'),
// MM2 操作接口 新增、编辑校验
validateMM2Config: getApi('/kafka-mm2/mirror-makers-config/validate'),
// 修改 Connector 配置
updateMM2Config: getApi('/kafka-mm2/mirror-makers-config'),
// MM2 详情
getMirrorMakerMetricPoints: (mirrorMakerName: number | string, connectClusterId: number | string) =>
getApi(`/kafka-mm2/clusters/${connectClusterId}/connectors/${mirrorMakerName}/latest-metrics`),
getSourceKafkaClusterBasic: getApi(`/physical-clusters/basic`),
getGroupBasic: (clusterPhyId: string) => getApi(`/clusters/${clusterPhyId}/groups-basic`),
// Topic复制
getMirrorClusterList: () => getApi(`/ha-mirror/physical-clusters/basic`),
handleTopicMirror: () => getApi(`/ha-mirror/topics`),
getTopicMirrorList: (clusterPhyId: number, topicName: string) =>
getApi(`/ha-mirror/clusters/${clusterPhyId}/topics/${topicName}/mirror-info`),
getMirrorMakerConfig: (connectClusterId: number | string, connectorName: string) =>
getApi(`/kafka-mm2/clusters/${connectClusterId}/connectors/${connectorName}/config`),
};

export default api;
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import CardBar, { healthDataProps } from './index';
import { Tooltip, Utils } from 'knowdesign';
import api from '@src/api';
import { HealthStateEnum } from '../HealthState';
import { InfoCircleOutlined } from '@ant-design/icons';

interface MM2State {
workerCount: number;
aliveConnectorCount: number;
aliveTaskCount: number;
healthCheckPassed: number;
healthCheckTotal: number;
healthState: number;
totalConnectorCount: string;
totalTaskCount: number;
totalServerCount: number;
mirrorMakerCount: number;
}

const getVal = (val: string | number | undefined | null) => {
return val === undefined || val === null || val === '' ? '0' : val;
};

const ConnectCard = ({ state }: { state?: boolean }) => {
const { clusterId } = useParams<{
clusterId: string;
}>();
const [loading, setLoading] = useState(false);
const [cardData, setCardData] = useState([]);
const [healthData, setHealthData] = useState<healthDataProps>({
state: HealthStateEnum.UNKNOWN,
passed: 0,
total: 0,
});

const getHealthData = () => {
return Utils.post(api.getMetricPointsLatest(Number(clusterId)), [
'HealthCheckPassed_MirrorMaker',
'HealthCheckTotal_MirrorMaker',
'HealthState_MirrorMaker',
]).then((data: any) => {
setHealthData({
state: data?.metrics?.['HealthState_MirrorMaker'],
passed: data?.metrics?.['HealthCheckPassed_MirrorMaker'] || 0,
total: data?.metrics?.['HealthCheckTotal_MirrorMaker'] || 0,
});
});
};

const getCardInfo = () => {
return Utils.request(api.getMirrorMakerState(clusterId)).then((res: MM2State) => {
const { mirrorMakerCount, aliveConnectorCount, aliveTaskCount, totalConnectorCount, totalTaskCount, workerCount } = res || {};
const cardMap = [
{
title: 'MM2s',
value: getVal(mirrorMakerCount),
customStyle: {
// 自定义cardbar样式
marginLeft: 0,
},
},
{
title: 'Workers',
value: getVal(workerCount),
},
{
title() {
return (
<div>
<span style={{ display: 'inline-block', marginRight: '8px' }}>Connectors</span>
<Tooltip overlayClassName="rebalance-tooltip" title="conector运行数/总数">
<InfoCircleOutlined />
</Tooltip>
</div>
);
},
value() {
return (
<span>
{getVal(aliveConnectorCount)}/{getVal(totalConnectorCount)}
</span>
);
},
},
{
title() {
return (
<div>
<span style={{ display: 'inline-block', marginRight: '8px' }}>Tasks</span>
<Tooltip overlayClassName="rebalance-tooltip" title="Task运行数/总数">
<InfoCircleOutlined />
</Tooltip>
</div>
);
},
value() {
return (
<span>
{getVal(aliveTaskCount)}/{getVal(totalTaskCount)}
</span>
);
},
},
];
setCardData(cardMap);
});
};
useEffect(() => {
setLoading(true);
Promise.all([getHealthData(), getCardInfo()]).finally(() => {
setLoading(false);
});
}, [clusterId, state]);
return <CardBar scene="mm2" healthData={healthData} cardColumns={cardData} loading={loading}></CardBar>;
};

export default ConnectCard;
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/* eslint-disable react/display-name */
import React, { useState, useEffect } from 'react';
import { useLocation, useParams } from 'react-router-dom';
import CardBar from '@src/components/CardBar';
import { healthDataProps } from '.';
import { Tooltip, Utils } from 'knowdesign';
import Api from '@src/api';
import { hashDataParse } from '@src/constants/common';
import { HealthStateEnum } from '../HealthState';
import { InfoCircleOutlined } from '@ant-design/icons';
import { stateEnum } from '@src/pages/Connect/config';
const getVal = (val: string | number | undefined | null) => {
return val === undefined || val === null || val === '' ? '0' : val;
};

const ConnectDetailCard = (props: { record: any; tabSelectType: string }) => {
const { record, tabSelectType } = props;
const urlParams = useParams<{ clusterId: string; brokerId: string }>();
const urlLocation = useLocation<any>();
const [loading, setLoading] = useState(false);
const [cardData, setCardData] = useState([]);
const [healthData, setHealthData] = useState<healthDataProps>({
state: HealthStateEnum.UNKNOWN,
passed: 0,
total: 0,
});

const getHealthData = (tabSelectTypeName: string) => {
return Utils.post(Api.getMirrorMakerMetricPoints(tabSelectTypeName, record?.connectClusterId), [
'HealthState',
'HealthCheckPassed',
'HealthCheckTotal',
]).then((data: any) => {
setHealthData({
state: data?.metrics?.['HealthState'],
passed: data?.metrics?.['HealthCheckPassed'] || 0,
total: data?.metrics?.['HealthCheckTotal'] || 0,
});
});
};

const getCardInfo = (tabSelectTypeName: string) => {
return Utils.request(Api.getConnectDetailState(tabSelectTypeName, record?.connectClusterId)).then((res: any) => {
const { type, aliveTaskCount, state, totalTaskCount, totalWorkerCount } = res || {};
const cordRightMap = [
{
title: 'Status',
// value: Utils.firstCharUppercase(state) || '-',
value: () => {
return (
<>
{
<span style={{ fontFamily: 'HelveticaNeue-Medium', fontSize: 32, color: stateEnum[state].color }}>
{Utils.firstCharUppercase(state) || '-'}
</span>
}
</>
);
},
},

{
title() {
return (
<div>
<span style={{ display: 'inline-block', marginRight: '8px' }}>Tasks</span>
<Tooltip overlayClassName="rebalance-tooltip" title="Task运行数/总数">
<InfoCircleOutlined />
</Tooltip>
</div>
);
},
value() {
return (
<span>
{getVal(aliveTaskCount)}/{getVal(totalTaskCount)}
</span>
);
},
},
{
title: 'Workers',
value: getVal(totalWorkerCount),
},
];
setCardData(cordRightMap);
});
};

const noDataCardInfo = () => {
const cordRightMap = [
{
title: 'Status',
// value: Utils.firstCharUppercase(state) || '-',
value() {
return <span>-</span>;
},
},

{
title() {
return (
<div>
<span style={{ display: 'inline-block', marginRight: '8px' }}>Tasks</span>
<Tooltip overlayClassName="rebalance-tooltip" title="Task运行数/总数">
<InfoCircleOutlined />
</Tooltip>
</div>
);
},
value() {
return <span>-/-</span>;
},
},
{
title: 'Workers',
value() {
return <span>-</span>;
},
},
];
setCardData(cordRightMap);
};

useEffect(() => {
setLoading(true);

const filterCardInfo =
tabSelectType === 'MirrorCheckpoint' && record.checkpointConnector
? getCardInfo(record.checkpointConnector)
: tabSelectType === 'MirrorHeatbeat' && record.heartbeatConnector
? getCardInfo(record.heartbeatConnector)
: tabSelectType === 'MirrorSource' && record.connectorName
? getCardInfo(record.connectorName)
: noDataCardInfo();
Promise.all([getHealthData(record.connectorName), filterCardInfo]).finally(() => {
setLoading(false);
});
}, [record, tabSelectType]);
return (
<CardBar record={record} scene="mm2" healthData={healthData} cardColumns={cardData} showCardBg={false} loading={loading}></CardBar>
);
};

export default ConnectDetailCard;
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface CardBarProps {
cardColumns?: any[];
healthData?: healthDataProps;
showCardBg?: boolean;
scene: 'topics' | 'brokers' | 'topic' | 'broker' | 'group' | 'zookeeper' | 'connect' | 'connector';
scene: 'topics' | 'brokers' | 'topic' | 'broker' | 'group' | 'zookeeper' | 'connect' | 'connector' | 'mm2';
record?: any;
loading?: boolean;
needProgress?: boolean;
Expand Down Expand Up @@ -67,6 +67,11 @@ const sceneCodeMap = {
fieldName: 'connectorName',
alias: 'Connector',
},
mm2: {
code: 7,
fieldName: 'connectorName',
alias: 'MM2',
},
};
const CardColumnsItem: any = (cardItem: any) => {
const { cardColumnsItemData, showCardBg } = cardItem;
Expand Down Expand Up @@ -108,7 +113,7 @@ const CardBar = (props: CardBarProps) => {
const sceneObj = sceneCodeMap[scene];
const path = record
? api.getResourceHealthDetail(
scene === 'connector' ? Number(record?.connectClusterId) : Number(routeParams.clusterId),
scene === 'connector' || scene === 'mm2' ? Number(record?.connectClusterId) : Number(routeParams.clusterId),
sceneObj.code,
record[sceneObj.fieldName]
)
Expand Down
Loading