mirror of
https://github.com/didi/KnowStreaming.git
synced 2026-01-15 12:48:09 +08:00
V3.2
This commit is contained in:
@@ -0,0 +1,259 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { Utils, AppContainer } from 'knowdesign';
|
||||
import api, { MetricType } from '@src/api';
|
||||
import DBreadcrumb from 'knowdesign/es/extend/d-breadcrumb';
|
||||
import ConnectCard from '@src/components/CardBar/ConnectCard';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { FormattedMetricData, formatChartData, MetricInfo } from '@src/constants/chartConfig';
|
||||
import ChartOperateBar, { KsHeaderOptions } from '@src/components/ChartOperateBar';
|
||||
import ChartDetail from '@src/components/DraggableCharts/Detail';
|
||||
import ChartList from '@src/components/DraggableCharts/ChartList';
|
||||
import MetricsFilter from './MetricsFilter';
|
||||
import SelectContent, { Connector } from './SelectContent';
|
||||
import './index.less';
|
||||
import { ConnectCluster } from '../Connect/AddConnector';
|
||||
import HasConnector from '../Connect/HasConnector';
|
||||
|
||||
type ChartFilterOptions = Omit<KsHeaderOptions, 'gridNum'>;
|
||||
|
||||
const { EventBus } = Utils;
|
||||
const busInstance = new EventBus();
|
||||
|
||||
const DraggableCharts = (): JSX.Element => {
|
||||
const [global] = AppContainer.useGlobalValue();
|
||||
const { clusterId } = useParams<{
|
||||
clusterId: string;
|
||||
}>();
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
// const [scopeList, setScopeList] = useState<IcustomScope[]>([]); // 节点范围列表
|
||||
const [curHeaderOptions, setCurHeaderOptions] = useState<ChartFilterOptions>();
|
||||
const [metricList, setMetricList] = useState<{ [key: string]: (string | number)[] }>({});
|
||||
const [metricChartData, setMetricChartData] = useState<FormattedMetricData[]>([]); // 指标图表数据列表
|
||||
const [gridNum, setGridNum] = useState<number>(12); // 图表列布局
|
||||
const [scopeList, setScopeList] = useState<{
|
||||
connectClusters: ConnectCluster[];
|
||||
connectors: Connector[];
|
||||
}>({
|
||||
connectClusters: [],
|
||||
connectors: [],
|
||||
});
|
||||
const curFetchingTimestamp = useRef(0);
|
||||
const metricRankList = useRef<string[]>([]);
|
||||
const metricFilterRef = useRef(null);
|
||||
const chartDetailRef = useRef(null);
|
||||
|
||||
// 根据筛选项获取图表信息
|
||||
const getMetricChartData = () => {
|
||||
!curHeaderOptions.isAutoReload && setLoading(true);
|
||||
const curTimestamp = Date.now();
|
||||
curFetchingTimestamp.current = curTimestamp;
|
||||
|
||||
const [startTime, endTime] = curHeaderOptions.rangeTime;
|
||||
const { connectClusters, connectors } = curHeaderOptions.scopeData.data;
|
||||
const isTop = curHeaderOptions?.scopeData?.isTop;
|
||||
const reqBasicBody = {
|
||||
startTime,
|
||||
endTime,
|
||||
topNu: isTop ? curHeaderOptions.scopeData.data : null,
|
||||
};
|
||||
|
||||
const getConnectClusterMetrics =
|
||||
metricList[MetricType.Connect] && (isTop || connectClusters?.length)
|
||||
? Utils.post(
|
||||
api.getConnectClusterMetrics(clusterId),
|
||||
Object.assign(
|
||||
{
|
||||
...reqBasicBody,
|
||||
metricsNames: metricList[MetricType.Connect],
|
||||
},
|
||||
isTop
|
||||
? {}
|
||||
: {
|
||||
connectClusterIdList: connectClusters,
|
||||
}
|
||||
)
|
||||
)
|
||||
: Promise.resolve([]);
|
||||
const getConnectorMetrics =
|
||||
metricList[MetricType.Connectors] && (isTop || connectors?.length)
|
||||
? Utils.post(
|
||||
api.getConnectorMetrics(clusterId),
|
||||
Object.assign(
|
||||
{
|
||||
...reqBasicBody,
|
||||
metricsNames: metricList[MetricType.Connectors],
|
||||
},
|
||||
isTop ? {} : { connectorNameList: connectors }
|
||||
)
|
||||
)
|
||||
: Promise.resolve([]);
|
||||
|
||||
Promise.all([getConnectClusterMetrics, getConnectorMetrics]).then(
|
||||
(res: any) => {
|
||||
// 如果当前请求不是最新请求,则不做任何操作
|
||||
if (curFetchingTimestamp.current !== curTimestamp) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 为保证指标排序结果正确,当指标全部返回后才展示图表
|
||||
if (res.length === 1 || (res.length === 2 && res[0] && res[1])) {
|
||||
const connectClusterData = formatChartData(
|
||||
res[0],
|
||||
global.getMetricDefine || {},
|
||||
MetricType.Connect,
|
||||
curHeaderOptions.rangeTime
|
||||
) as FormattedMetricData[];
|
||||
const connectorData = formatChartData(
|
||||
res[1],
|
||||
global.getMetricDefine || {},
|
||||
MetricType.Connectors,
|
||||
curHeaderOptions.rangeTime
|
||||
) as FormattedMetricData[];
|
||||
// 指标排序
|
||||
const formattedMetricData = [...connectClusterData, ...connectorData];
|
||||
formattedMetricData.sort((a, b) => metricRankList.current.indexOf(a.metricName) - metricRankList.current.indexOf(b.metricName));
|
||||
|
||||
setMetricChartData(formattedMetricData);
|
||||
} else {
|
||||
setMetricChartData([]);
|
||||
}
|
||||
setLoading(false);
|
||||
},
|
||||
() => curFetchingTimestamp.current === curTimestamp && setLoading(false)
|
||||
);
|
||||
};
|
||||
|
||||
const getScopeList = () => {
|
||||
const getConnectClusters = Utils.request(api.getConnectClusters(clusterId));
|
||||
const getConnectors = Utils.request(api.getConnectors(clusterId));
|
||||
Promise.all([getConnectClusters, getConnectors]).then(([connectClusters, connectors]: [ConnectCluster[], Connector[]]) => {
|
||||
setScopeList({
|
||||
connectClusters,
|
||||
connectors,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 筛选项变化或者点击刷新按钮
|
||||
const ksHeaderChange = (ksOptions: KsHeaderOptions) => {
|
||||
const { isAutoReload, gridNum: newGridNum, isRelativeRangeTime, rangeTime, scopeData } = ksOptions;
|
||||
let newRangeTime = rangeTime;
|
||||
// 重新渲染图表
|
||||
if (newGridNum !== gridNum) {
|
||||
setGridNum(newGridNum || 12);
|
||||
busInstance.emit('chartResize');
|
||||
} else {
|
||||
// 如果为相对时间,则当前时间减去 1 分钟,避免最近一分钟的数据还没采集到时前端多补一个点
|
||||
if (isRelativeRangeTime) {
|
||||
newRangeTime = rangeTime.map((timestamp) => timestamp - 60 * 1000) as [number, number];
|
||||
}
|
||||
setCurHeaderOptions({
|
||||
isRelativeRangeTime: isRelativeRangeTime,
|
||||
isAutoReload: isAutoReload,
|
||||
rangeTime: newRangeTime,
|
||||
scopeData: scopeData,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 图表拖拽
|
||||
const dragCallback = (oldIndex: number, newIndex: number) => {
|
||||
const originFrom = metricRankList.current.indexOf(metricChartData[oldIndex].metricName);
|
||||
const originTarget = metricRankList.current.indexOf(metricChartData[newIndex].metricName);
|
||||
metricFilterRef.current?.rankChange(originFrom, originTarget);
|
||||
};
|
||||
|
||||
// 展开图表详情
|
||||
const onExpand = (metricName: string, metricType: MetricType) => {
|
||||
const linesName =
|
||||
metricType === MetricType.Connect
|
||||
? scopeList.connectClusters.map((cluster) => cluster.id)
|
||||
: scopeList.connectors.map((connector) => ({
|
||||
connectClusterId: connector.connectClusterId,
|
||||
connectorName: connector.connectorName,
|
||||
}));
|
||||
chartDetailRef.current.onOpen(metricType, metricName, linesName);
|
||||
};
|
||||
|
||||
// 获取图表指标
|
||||
useEffect(() => {
|
||||
if (Object.values(metricList).some((list) => list.length) && curHeaderOptions) {
|
||||
getMetricChartData();
|
||||
}
|
||||
}, [curHeaderOptions]);
|
||||
|
||||
useEffect(() => {
|
||||
if (Object.values(metricList).some((list) => list.length) && curHeaderOptions) {
|
||||
setLoading(true);
|
||||
getMetricChartData();
|
||||
}
|
||||
}, [metricList]);
|
||||
|
||||
useEffect(() => {
|
||||
getScopeList();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div id="dashboard-drag-chart" className="topic-dashboard">
|
||||
<ChartOperateBar
|
||||
onChange={ksHeaderChange}
|
||||
hideNodeScope={false}
|
||||
openMetricFilter={() => metricFilterRef.current?.open()}
|
||||
nodeSelect={{
|
||||
name: 'Connect',
|
||||
customContent: <SelectContent scopeList={scopeList} title="请选择 Connect 范围" />,
|
||||
}}
|
||||
/>
|
||||
<MetricsFilter
|
||||
ref={metricFilterRef}
|
||||
metricType={[MetricType.Connect, MetricType.Connectors]}
|
||||
onSelectChange={(list) => {
|
||||
const res: { [key: string]: (string | number)[] } = {};
|
||||
list.forEach(({ type, name, set }) => {
|
||||
set && (res[type] ? res[type].push(name) : (res[type] = [name]));
|
||||
});
|
||||
setMetricList(res);
|
||||
}}
|
||||
onRankChange={(rankList) => {
|
||||
metricRankList.current = rankList;
|
||||
}}
|
||||
/>
|
||||
<ChartList
|
||||
busInstance={busInstance}
|
||||
loading={loading}
|
||||
gridNum={gridNum}
|
||||
data={metricChartData}
|
||||
autoReload={curHeaderOptions?.isAutoReload}
|
||||
dragCallback={dragCallback}
|
||||
onExpand={onExpand}
|
||||
/>
|
||||
{/* 图表详情 */}
|
||||
<ChartDetail ref={chartDetailRef} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ConnectDashboard = (): JSX.Element => {
|
||||
const [global] = AppContainer.useGlobalValue();
|
||||
return (
|
||||
<>
|
||||
<div className="breadcrumb" style={{ marginBottom: '10px' }}>
|
||||
<DBreadcrumb
|
||||
breadcrumbs={[
|
||||
{ label: '多集群管理', aHref: '/' },
|
||||
{ label: global?.clusterInfo?.name, aHref: `/cluster/${global?.clusterInfo?.id}` },
|
||||
{ label: 'Connect', aHref: `` },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<HasConnector>
|
||||
<>
|
||||
<ConnectCard />
|
||||
<DraggableCharts />
|
||||
</>
|
||||
</HasConnector>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConnectDashboard;
|
||||
Reference in New Issue
Block a user