import { AppContainer, Divider, Form, Input, List, Modal, Progress, Spin, Tooltip, Utils } from 'knowdesign'; import message from '@src/components/Message'; import { IconFont } from '@knowdesign/icons'; import moment from 'moment'; import API from '@src/api'; import React, { useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'; import InfiniteScroll from 'react-infinite-scroll-component'; import { Link, useHistory } from 'react-router-dom'; import { timeFormat, oneDayMillims } from '@src/constants/common'; import { IMetricPoint, linesMetric, pointsMetric } from './config'; import { useIntl } from 'react-intl'; import api, { MetricType } from '@src/api'; import { ClustersPermissionMap } from '../CommonConfig'; import { getDataUnit } from '@src/constants/chartConfig'; import SmallChart from '@src/components/SmallChart'; import HealthState, { HealthStateEnum } from '@src/components/HealthState'; import { SearchParams } from './HomePage'; const DEFAULT_PAGE_SIZE = 10; export enum ClusterRunState { Raft = 2, } const DeleteCluster = React.forwardRef((_, ref) => { const intl = useIntl(); const [form] = Form.useForm(); const [visible, setVisible] = useState(false); const [clusterInfo, setClusterInfo] = useState({}); const callback = useRef(() => { return; }); const onFinish = () => { form.validateFields().then(() => { Utils.delete(api.phyCluster, { params: { clusterPhyId: clusterInfo.id, }, }).then(() => { message.success('删除成功'); callback.current(); setVisible(false); }); }); }; useImperativeHandle(ref, () => ({ onOpen: (clusterInfo: any, cbk: () => void) => { setClusterInfo(clusterInfo); callback.current = cbk; setVisible(true); }, })); useEffect(() => { if (visible) { form.resetFields(); } }, [visible]); return ( setVisible(false)} okButtonProps={{ style: { width: 56, }, danger: true, size: 'small', }} cancelButtonProps={{ style: { width: 56, }, size: 'small', }} >
{intl.formatMessage({ id: 'delete.cluster.confirm.tip', })}
{clusterInfo.name} { value = value || ''; if (!value.trim() || value.trim() !== clusterInfo.name) return Promise.reject( intl.formatMessage({ id: 'delete.cluster.confirm.cluster', }) ); return Promise.resolve(); }, }, ]} >
); }); const ClusterList = (props: { searchParams: SearchParams; showAccessCluster: any; getPhyClusterState: any; getExistKafkaVersion: any }) => { const { searchParams, showAccessCluster, getPhyClusterState, getExistKafkaVersion } = props; const history = useHistory(); const [global] = AppContainer.useGlobalValue(); const [isReload, setIsReload] = useState(false); const [list, setList] = useState<[]>([]); const [clusterLoading, setClusterLoading] = useState(true); const [isLoadingMore, setIsLoadingMore] = useState(false); const [pagination, setPagination] = useState({ pageNo: 1, pageSize: DEFAULT_PAGE_SIZE, total: 0, }); const deleteModalRef = useRef(null); const getClusterList = (pageNo: number, pageSize: number) => { const endTime = new Date().getTime(); const startTime = endTime - oneDayMillims; const params = { metricLines: { endTime, metricsNames: linesMetric, startTime, }, latestMetricNames: pointsMetric, pageNo: pageNo, pageSize: pageSize, preciseFilterDTOList: [ { fieldName: 'kafkaVersion', fieldValueList: searchParams.checkedKafkaVersions as (string | number)[], }, { fieldName: 'HealthState', fieldValueList: searchParams.healthState, }, ], searchKeywords: searchParams.keywords, ...searchParams.sortInfo, }; if (searchParams.clusterStatus.length === 1) { params.preciseFilterDTOList.push({ fieldName: 'Alive', fieldValueList: searchParams.clusterStatus, }); } return Utils.post(API.phyClustersDashbord, params); }; // 重置集群列表 const reloadClusterList = (pageSize = DEFAULT_PAGE_SIZE) => { setClusterLoading(true); getClusterList(1, pageSize) .then((res: any) => { setList(res?.bizData || []); setPagination(res.pagination); }) .finally(() => setClusterLoading(false)); }; // 加载更多列表 const loadMoreData = async () => { if (isLoadingMore) { return; } setIsLoadingMore(true); const res: any = await getClusterList(pagination.pageNo + 1, pagination.pageSize); const _data = list.concat(res.bizData || []) as any; setList(_data); setPagination(res.pagination); setIsLoadingMore(false); }; // 重载列表 useEffect( () => (searchParams.isReloadAll ? reloadClusterList(pagination.pageNo * pagination.pageSize) : reloadClusterList()), [searchParams] ); const RenderItem = (itemData: any) => { itemData = itemData || {}; const metrics = linesMetric; const metricPoints = [] as IMetricPoint[]; metrics.forEach((item) => { const line = { metricName: item, value: itemData.latestMetrics?.metrics?.[item] || 0, unit: (global.getMetricDefine && global.getMetricDefine(MetricType.Cluster, item).unit) || '', metricLines: { name: item, data: itemData.metricLines .find((metric: any) => metric.metricName === item) ?.metricPoints.map((point: IMetricPoint) => [point.timeStamp, point.value]), }, } as IMetricPoint; // 如果单位是 字节 ,进行单位换算 if (line.unit.toLowerCase().includes('byte')) { const [unit, size] = getDataUnit['Memory'](line.value); line.value = Number((line.value / size).toFixed(2)); line.unit = line.unit.toLowerCase().replace('byte', unit); } // Messages 指标值特殊处理 if (line.metricName === 'LeaderMessages') { const [unit, size] = getDataUnit['Num'](line.value); line.value = Number((line.value / size).toFixed(2)); line.unit = unit + line.unit; } metricPoints.push(line); }); const runState = itemData.runState; const { Brokers: brokers, Zookeepers: zks, HealthCheckPassed: healthCheckPassed, HealthCheckTotal: healthCheckTotal, HealthState: healthState, ZookeepersAvailable: zookeepersAvailable, LoadReBalanceCpu: loadReBalanceCpu, LoadReBalanceDisk: loadReBalanceDisk, LoadReBalanceEnable: loadReBalanceEnable, LoadReBalanceNwIn: loadReBalanceNwIn, LoadReBalanceNwOut: loadReBalanceNwOut, } = itemData.latestMetrics?.metrics || {}; return ( { history.push(`/cluster/${itemData.id}/cluster`); }} >
通过 {healthCheckPassed}/{healthCheckTotal}
{itemData.name ?? '-'}
{itemData.kafkaVersion ?? '-'} {loadReBalanceEnable !== undefined && (
{ e.preventDefault(); e.stopPropagation(); }} > {[ ['BytesIn', loadReBalanceNwIn === 1], ['BytesOut', loadReBalanceNwOut === 1], ['Disk', loadReBalanceDisk === 1], ].map(([name, isBalanced]) => { return isBalanced ? (
{name} 已均衡
) : loadReBalanceEnable ? (
{name} 未均衡
) : ( 尚未开启 {name} 均衡策略, 前往开启 } >
{name} 未均衡
); })}
)}
{moment(itemData.createTime).format(timeFormat)}
Brokers
{brokers}
{/* 2: raft 模式 无zk */} {runState !== ClusterRunState.Raft && (
ZK
{zookeepersAvailable === -1 ? '-' : zks}
)}
{metricPoints.map((row, index) => { return (
{row.metricName === 'TotalLogSize' ? 'MessageSize' : row.metricName}
{row.value} {row.unit}
); })}
{global.hasPermission ? (
{global.hasPermission(ClustersPermissionMap.CLUSTER_CHANGE_INFO) && (
{ e.stopPropagation(); showAccessCluster(itemData); }} >
)} {global.hasPermission(ClustersPermissionMap.CLUSTER_DEL) && (
{ e.stopPropagation(); deleteModalRef.current.onOpen(itemData, () => { getPhyClusterState(); getExistKafkaVersion(true); reloadClusterList(pagination.pageNo * pagination.pageSize); }); }} >
)}
) : ( <> )}
); }; return ( {useMemo( () => ( } endMessage={ !pagination.total ? ( '' ) : ( 加载完成 共 {pagination.total} 条 ) } scrollableTarget="scrollableDiv" > ), [list, pagination, isLoadingMore] )} ); }; export default ClusterList;