mirror of
https://github.com/didi/KnowStreaming.git
synced 2026-01-05 04:50:55 +08:00
fix: 图表逻辑 & 展示优化
This commit is contained in:
@@ -14,6 +14,7 @@ export enum MetricType {
|
|||||||
Broker = 103,
|
Broker = 103,
|
||||||
Partition = 104,
|
Partition = 104,
|
||||||
Replication = 105,
|
Replication = 105,
|
||||||
|
Zookeeper = 110,
|
||||||
Controls = 901,
|
Controls = 901,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +62,8 @@ const api = {
|
|||||||
phyClusterState: getApi(`/physical-clusters/state`),
|
phyClusterState: getApi(`/physical-clusters/state`),
|
||||||
|
|
||||||
getOperatingStateList: (clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/groups-overview`),
|
getOperatingStateList: (clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/groups-overview`),
|
||||||
|
getGroupTopicList: (clusterPhyId: number, groupName: string) => getApi(`/clusters/${clusterPhyId}/groups/${groupName}/topics-overview`),
|
||||||
|
|
||||||
// 物理集群接口
|
// 物理集群接口
|
||||||
phyCluster: getApi(`/physical-clusters`),
|
phyCluster: getApi(`/physical-clusters`),
|
||||||
getPhyClusterBasic: (clusterPhyId: number) => getApi(`/physical-clusters/${clusterPhyId}/basic`),
|
getPhyClusterBasic: (clusterPhyId: number) => getApi(`/physical-clusters/${clusterPhyId}/basic`),
|
||||||
@@ -127,6 +130,7 @@ const api = {
|
|||||||
getApi(`/clusters/${clusterPhyId}/topics/${topicName}/brokers-partitions-summary`),
|
getApi(`/clusters/${clusterPhyId}/topics/${topicName}/brokers-partitions-summary`),
|
||||||
getTopicPartitionsDetail: (clusterPhyId: string, topicName: string) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/partitions`),
|
getTopicPartitionsDetail: (clusterPhyId: string, topicName: string) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/partitions`),
|
||||||
getTopicMessagesList: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/records`), // Messages列表
|
getTopicMessagesList: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/records`), // Messages列表
|
||||||
|
getTopicGroupList: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/groups-overview`), // Consumers列表
|
||||||
getTopicMessagesMetadata: (topicName: string, clusterPhyId: number) => getApi(`/clusters//${clusterPhyId}/topics/${topicName}/metadata`), // Messages列表
|
getTopicMessagesMetadata: (topicName: string, clusterPhyId: number) => getApi(`/clusters//${clusterPhyId}/topics/${topicName}/metadata`), // Messages列表
|
||||||
getTopicACLsList: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/acl-Bindings`), // ACLs列表
|
getTopicACLsList: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/topics/${topicName}/acl-Bindings`), // ACLs列表
|
||||||
getTopicConfigs: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/config-topics/${topicName}/configs`), // Configuration列表
|
getTopicConfigs: (topicName: string, clusterPhyId: number) => getApi(`/clusters/${clusterPhyId}/config-topics/${topicName}/configs`), // Configuration列表
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
|
||||||
import { Drawer, Button, Space, Divider, AppContainer, ProTable } from 'knowdesign';
|
import { Drawer, Button, Space, Divider, AppContainer, ProTable, Utils } from 'knowdesign';
|
||||||
import { IconFont } from '@knowdesign/icons';
|
import { IconFont } from '@knowdesign/icons';
|
||||||
import { IindicatorSelectModule } from './index';
|
import { MetricSelect } from './index';
|
||||||
import './style/indicator-drawer.less';
|
import './style/indicator-drawer.less';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
interface PropsType extends React.HTMLAttributes<HTMLDivElement> {
|
interface PropsType extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
onClose: () => void;
|
metricSelect: MetricSelect;
|
||||||
visible: boolean;
|
|
||||||
isGroup?: boolean; // 是否分组
|
|
||||||
indicatorSelectModule: IindicatorSelectModule;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MetricInfo {
|
interface MetricInfo {
|
||||||
@@ -27,25 +24,25 @@ type CategoryData = {
|
|||||||
metrics: MetricInfo[];
|
metrics: MetricInfo[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const ExpandedRow = ({ metrics, category, selectedMetrics, selectedMetricChange }: any) => {
|
const expandedRowColumns = [
|
||||||
const innerColumns = [
|
{
|
||||||
{
|
title: '指标名称',
|
||||||
title: '指标名称',
|
dataIndex: 'name',
|
||||||
dataIndex: 'name',
|
key: 'name',
|
||||||
key: 'name',
|
},
|
||||||
},
|
{
|
||||||
{
|
title: '单位',
|
||||||
title: '单位',
|
dataIndex: 'unit',
|
||||||
dataIndex: 'unit',
|
key: 'unit',
|
||||||
key: 'unit',
|
},
|
||||||
},
|
{
|
||||||
{
|
title: '描述',
|
||||||
title: '描述',
|
dataIndex: 'desc',
|
||||||
dataIndex: 'desc',
|
key: 'desc',
|
||||||
key: 'desc',
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
|
const ExpandedRow = ({ metrics, category, selectedMetrics, selectedMetricChange }: any) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -62,7 +59,7 @@ const ExpandedRow = ({ metrics, category, selectedMetrics, selectedMetricChange
|
|||||||
showHeader: false,
|
showHeader: false,
|
||||||
noPagination: true,
|
noPagination: true,
|
||||||
rowKey: 'name',
|
rowKey: 'name',
|
||||||
columns: innerColumns,
|
columns: expandedRowColumns,
|
||||||
dataSource: metrics,
|
dataSource: metrics,
|
||||||
attrs: {
|
attrs: {
|
||||||
rowSelection: {
|
rowSelection: {
|
||||||
@@ -79,13 +76,14 @@ const ExpandedRow = ({ metrics, category, selectedMetrics, selectedMetricChange
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType) => {
|
const MetricSelect = forwardRef(({ metricSelect }: PropsType, ref) => {
|
||||||
const [global] = AppContainer.useGlobalValue();
|
const [global] = AppContainer.useGlobalValue();
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
const [confirmLoading, setConfirmLoading] = useState<boolean>(false);
|
const [confirmLoading, setConfirmLoading] = useState<boolean>(false);
|
||||||
const [categoryData, setCategoryData] = useState<CategoryData[]>([]);
|
const [categoryData, setCategoryData] = useState<CategoryData[]>([]);
|
||||||
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
|
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
|
||||||
const [childrenSelectedRowKeys, setChildrenSelectedRowKeys] = useState<SelectedMetrics>({});
|
const [childrenSelectedRowKeys, setChildrenSelectedRowKeys] = useState<SelectedMetrics>({});
|
||||||
|
const [visible, setVisible] = useState<boolean>(false);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@@ -96,13 +94,13 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
|||||||
];
|
];
|
||||||
|
|
||||||
const formateTableData = () => {
|
const formateTableData = () => {
|
||||||
const tableData = indicatorSelectModule.tableData;
|
const tableData = metricSelect.tableData;
|
||||||
const categoryData: {
|
const categoryData: {
|
||||||
[category: string]: MetricInfo[];
|
[category: string]: MetricInfo[];
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
tableData.forEach(({ name, desc }) => {
|
tableData.forEach(({ name, desc }) => {
|
||||||
const metricDefine = global.getMetricDefine(indicatorSelectModule?.metricType, name);
|
const metricDefine = global.getMetricDefine(metricSelect?.metricType, name);
|
||||||
const returnData = {
|
const returnData = {
|
||||||
name,
|
name,
|
||||||
desc,
|
desc,
|
||||||
@@ -125,12 +123,12 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
|||||||
};
|
};
|
||||||
|
|
||||||
const formateSelectedKeys = () => {
|
const formateSelectedKeys = () => {
|
||||||
const newKeys = indicatorSelectModule.selectedRows;
|
const newKeys = metricSelect.selectedRows;
|
||||||
const result: SelectedMetrics = {};
|
const result: SelectedMetrics = {};
|
||||||
const selectedCategories: string[] = [];
|
const selectedCategories: string[] = [];
|
||||||
|
|
||||||
newKeys.forEach((name: string) => {
|
newKeys.forEach((name: string) => {
|
||||||
const metricDefine = global.getMetricDefine(indicatorSelectModule?.metricType, name);
|
const metricDefine = global.getMetricDefine(metricSelect?.metricType, name);
|
||||||
if (metricDefine) {
|
if (metricDefine) {
|
||||||
if (!result[metricDefine.category]) {
|
if (!result[metricDefine.category]) {
|
||||||
result[metricDefine.category] = [name];
|
result[metricDefine.category] = [name];
|
||||||
@@ -217,10 +215,10 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
|||||||
const allRowKeys: string[] = [];
|
const allRowKeys: string[] = [];
|
||||||
Object.entries(childrenSelectedRowKeys).forEach(([, arr]) => allRowKeys.push(...arr));
|
Object.entries(childrenSelectedRowKeys).forEach(([, arr]) => allRowKeys.push(...arr));
|
||||||
|
|
||||||
indicatorSelectModule.submitCallback(allRowKeys).then(
|
metricSelect.submitCallback(allRowKeys).then(
|
||||||
() => {
|
() => {
|
||||||
setConfirmLoading(false);
|
setConfirmLoading(false);
|
||||||
onClose();
|
setVisible(false);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
setConfirmLoading(false);
|
setConfirmLoading(false);
|
||||||
@@ -231,7 +229,7 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
|||||||
const rowSelection = {
|
const rowSelection = {
|
||||||
selectedRowKeys: selectedCategories,
|
selectedRowKeys: selectedCategories,
|
||||||
onChange: rowChange,
|
onChange: rowChange,
|
||||||
// getCheckboxProps: (record: any) => indicatorSelectModule.checkboxProps && indicatorSelectModule.checkboxProps(record),
|
// getCheckboxProps: (record: any) => metricSelect.checkboxProps && metricSelect.checkboxProps(record),
|
||||||
getCheckboxProps: (record: CategoryData) => {
|
getCheckboxProps: (record: CategoryData) => {
|
||||||
const isAllSelected = record.metrics.length === childrenSelectedRowKeys[record.category]?.length;
|
const isAllSelected = record.metrics.length === childrenSelectedRowKeys[record.category]?.length;
|
||||||
const isNotCheck = !childrenSelectedRowKeys[record.category] || childrenSelectedRowKeys[record.category]?.length === 0;
|
const isNotCheck = !childrenSelectedRowKeys[record.category] || childrenSelectedRowKeys[record.category]?.length === 0;
|
||||||
@@ -241,25 +239,33 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(formateTableData, [indicatorSelectModule.tableData]);
|
useEffect(formateTableData, [metricSelect.tableData]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
visible && formateSelectedKeys();
|
visible && formateSelectedKeys();
|
||||||
}, [visible, indicatorSelectModule.selectedRows]);
|
}, [visible, metricSelect.selectedRows]);
|
||||||
|
|
||||||
|
useImperativeHandle(
|
||||||
|
ref,
|
||||||
|
() => ({
|
||||||
|
open: () => setVisible(true),
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Drawer
|
<Drawer
|
||||||
className="indicator-drawer"
|
className="indicator-drawer"
|
||||||
title={indicatorSelectModule.drawerTitle || '指标筛选'}
|
title={metricSelect.drawerTitle || '指标筛选'}
|
||||||
width="868px"
|
width="868px"
|
||||||
forceRender={true}
|
forceRender={true}
|
||||||
onClose={onClose}
|
onClose={() => setVisible(false)}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
extra={
|
extra={
|
||||||
<Space>
|
<Space>
|
||||||
<Button size="small" onClick={onClose}>
|
<Button size="small" onClick={() => setVisible(false)}>
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -281,6 +287,7 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
|||||||
rowKey: 'category',
|
rowKey: 'category',
|
||||||
columns: columns,
|
columns: columns,
|
||||||
dataSource: categoryData,
|
dataSource: categoryData,
|
||||||
|
noPagination: true,
|
||||||
attrs: {
|
attrs: {
|
||||||
rowSelection: rowSelection,
|
rowSelection: rowSelection,
|
||||||
expandable: {
|
expandable: {
|
||||||
@@ -319,6 +326,6 @@ const IndicatorDrawer = ({ onClose, visible, indicatorSelectModule }: PropsType)
|
|||||||
</Drawer>
|
</Drawer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
export default IndicatorDrawer;
|
export default MetricSelect;
|
||||||
@@ -26,6 +26,7 @@ const OptionsDefault = [
|
|||||||
|
|
||||||
const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
||||||
const {
|
const {
|
||||||
|
hasCustomScope,
|
||||||
customScopeList: customList,
|
customScopeList: customList,
|
||||||
scopeName = '',
|
scopeName = '',
|
||||||
scopeLabel = '自定义范围',
|
scopeLabel = '自定义范围',
|
||||||
@@ -128,51 +129,53 @@ const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
|||||||
</Space>
|
</Space>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</div>
|
</div>
|
||||||
<div className="flx_r">
|
{hasCustomScope && (
|
||||||
<h6 className="time_title">{scopeLabel}</h6>
|
<div className="flx_r">
|
||||||
<div className="custom-scope">
|
<h6 className="time_title">{scopeLabel}</h6>
|
||||||
<div className="check-row">
|
<div className="custom-scope">
|
||||||
<Checkbox className="check-all" indeterminate={indeterminate} onChange={onCheckAllChange} checked={checkAll}>
|
<div className="check-row">
|
||||||
全选
|
<Checkbox className="check-all" indeterminate={indeterminate} onChange={onCheckAllChange} checked={checkAll}>
|
||||||
</Checkbox>
|
全选
|
||||||
<Input
|
</Checkbox>
|
||||||
className="search-input"
|
<Input
|
||||||
suffix={<IconFont type="icon-fangdajing" style={{ fontSize: '16px' }} />}
|
className="search-input"
|
||||||
size="small"
|
suffix={<IconFont type="icon-fangdajing" style={{ fontSize: '16px' }} />}
|
||||||
placeholder={searchPlaceholder}
|
size="small"
|
||||||
onChange={(e) => setScopeSearchValue(e.target.value)}
|
placeholder={searchPlaceholder}
|
||||||
/>
|
onChange={(e) => setScopeSearchValue(e.target.value)}
|
||||||
</div>
|
/>
|
||||||
<div className="fixed-height">
|
</div>
|
||||||
<Checkbox.Group style={{ width: '100%' }} onChange={checkChange} value={checkedListTemp}>
|
<div className="fixed-height">
|
||||||
<Row gutter={[10, 12]}>
|
<Checkbox.Group style={{ width: '100%' }} onChange={checkChange} value={checkedListTemp}>
|
||||||
{customList
|
<Row gutter={[10, 12]}>
|
||||||
.filter((item) => item.label.includes(scopeSearchValue))
|
{customList
|
||||||
.map((item) => (
|
.filter((item) => item.label.includes(scopeSearchValue))
|
||||||
<Col span={12} key={item.value}>
|
.map((item) => (
|
||||||
<Checkbox value={item.value}>{item.label}</Checkbox>
|
<Col span={12} key={item.value}>
|
||||||
</Col>
|
<Checkbox value={item.value}>{item.label}</Checkbox>
|
||||||
))}
|
</Col>
|
||||||
</Row>
|
))}
|
||||||
</Checkbox.Group>
|
</Row>
|
||||||
</div>
|
</Checkbox.Group>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="btn-con">
|
<div className="btn-con">
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
className="btn-sure"
|
className="btn-sure"
|
||||||
onClick={customSure}
|
onClick={customSure}
|
||||||
disabled={checkedListTemp?.length > 0 ? false : true}
|
disabled={checkedListTemp?.length > 0 ? false : true}
|
||||||
>
|
>
|
||||||
确定
|
确定
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="small" onClick={customCancel}>
|
<Button size="small" onClick={customCancel}>
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -185,7 +188,7 @@ const NodeScope = ({ nodeScopeModule, change }: propsType) => {
|
|||||||
visible={popVisible}
|
visible={popVisible}
|
||||||
content={clickContent}
|
content={clickContent}
|
||||||
placement="bottomRight"
|
placement="bottomRight"
|
||||||
overlayClassName="d-node-scope-popover"
|
overlayClassName={`d-node-scope-popover ${hasCustomScope ? 'large-size' : ''}`}
|
||||||
onVisibleChange={visibleChange}
|
onVisibleChange={visibleChange}
|
||||||
>
|
>
|
||||||
<span className="input-span">
|
<span className="input-span">
|
||||||
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
@@ -1,9 +1,9 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import { Tooltip, Select, Utils, Divider, Button } from 'knowdesign';
|
import { Select, Divider, Button } from 'knowdesign';
|
||||||
import { IconFont } from '@knowdesign/icons';
|
import { IconFont } from '@knowdesign/icons';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { DRangeTime } from 'knowdesign';
|
import { DRangeTime } from 'knowdesign';
|
||||||
import IndicatorDrawer from './IndicatorDrawer';
|
import MetricSelect from './MetricSelect';
|
||||||
import NodeScope from './NodeScope';
|
import NodeScope from './NodeScope';
|
||||||
|
|
||||||
import './style/index.less';
|
import './style/index.less';
|
||||||
@@ -24,8 +24,8 @@ export interface KsHeaderOptions {
|
|||||||
data: number | number[];
|
data: number | number[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export interface IindicatorSelectModule {
|
export interface MetricSelect {
|
||||||
metricType?: MetricType;
|
metricType: MetricType;
|
||||||
hide?: boolean;
|
hide?: boolean;
|
||||||
drawerTitle?: string;
|
drawerTitle?: string;
|
||||||
selectedRows: (string | number)[];
|
selectedRows: (string | number)[];
|
||||||
@@ -47,20 +47,27 @@ export interface IcustomScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface InodeScopeModule {
|
export interface InodeScopeModule {
|
||||||
|
hasCustomScope: boolean;
|
||||||
customScopeList: IcustomScope[];
|
customScopeList: IcustomScope[];
|
||||||
scopeName?: string;
|
scopeName?: string;
|
||||||
scopeLabel?: string;
|
scopeLabel?: string;
|
||||||
searchPlaceholder?: string;
|
searchPlaceholder?: string;
|
||||||
change?: () => void;
|
change?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PropsType {
|
interface PropsType {
|
||||||
indicatorSelectModule?: IindicatorSelectModule;
|
metricSelect?: MetricSelect;
|
||||||
hideNodeScope?: boolean;
|
hideNodeScope?: boolean;
|
||||||
hideGridSelect?: boolean;
|
hideGridSelect?: boolean;
|
||||||
nodeScopeModule?: InodeScopeModule;
|
nodeScopeModule?: InodeScopeModule;
|
||||||
onChange: (options: KsHeaderOptions) => void;
|
onChange: (options: KsHeaderOptions) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ScopeData {
|
||||||
|
isTop: boolean;
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
|
||||||
// 列布局选项
|
// 列布局选项
|
||||||
const GRID_SIZE_OPTIONS = [
|
const GRID_SIZE_OPTIONS = [
|
||||||
{
|
{
|
||||||
@@ -77,15 +84,17 @@ const GRID_SIZE_OPTIONS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const SingleChartHeader = ({
|
const MetricOperateBar = ({
|
||||||
indicatorSelectModule,
|
metricSelect,
|
||||||
nodeScopeModule = {
|
nodeScopeModule = {
|
||||||
|
hasCustomScope: false,
|
||||||
customScopeList: [],
|
customScopeList: [],
|
||||||
},
|
},
|
||||||
hideNodeScope = false,
|
hideNodeScope = false,
|
||||||
hideGridSelect = false,
|
hideGridSelect = false,
|
||||||
onChange: onChangeCallback,
|
onChange: onChangeCallback,
|
||||||
}: PropsType): JSX.Element => {
|
}: PropsType): JSX.Element => {
|
||||||
|
const metricSelectRef = useRef(null);
|
||||||
const [gridNum, setGridNum] = useState<number>(GRID_SIZE_OPTIONS[1].value);
|
const [gridNum, setGridNum] = useState<number>(GRID_SIZE_OPTIONS[1].value);
|
||||||
const [rangeTime, setRangeTime] = useState<[number, number]>(() => {
|
const [rangeTime, setRangeTime] = useState<[number, number]>(() => {
|
||||||
const curTimeStamp = moment().valueOf();
|
const curTimeStamp = moment().valueOf();
|
||||||
@@ -93,16 +102,35 @@ const SingleChartHeader = ({
|
|||||||
});
|
});
|
||||||
const [isRelativeRangeTime, setIsRelativeRangeTime] = useState(true);
|
const [isRelativeRangeTime, setIsRelativeRangeTime] = useState(true);
|
||||||
const [isAutoReload, setIsAutoReload] = useState(false);
|
const [isAutoReload, setIsAutoReload] = useState(false);
|
||||||
const [indicatorDrawerVisible, setIndicatorDrawerVisible] = useState(false);
|
const [scopeData, setScopeData] = useState<ScopeData>({
|
||||||
|
|
||||||
const [scopeData, setScopeData] = useState<{
|
|
||||||
isTop: boolean;
|
|
||||||
data: any;
|
|
||||||
}>({
|
|
||||||
isTop: true,
|
isTop: true,
|
||||||
data: 5,
|
data: 5,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const sizeChange = (value: number) => setGridNum(value);
|
||||||
|
|
||||||
|
const timeChange = (curRangeTime: [number, number], isRelative: boolean) => {
|
||||||
|
setRangeTime([...curRangeTime]);
|
||||||
|
setIsRelativeRangeTime(isRelative);
|
||||||
|
};
|
||||||
|
|
||||||
|
const reloadRangeTime = () => {
|
||||||
|
if (isRelativeRangeTime) {
|
||||||
|
const timeLen = rangeTime[1] - rangeTime[0] || 0;
|
||||||
|
const curTimeStamp = moment().valueOf();
|
||||||
|
setRangeTime([curTimeStamp - timeLen, curTimeStamp]);
|
||||||
|
} else {
|
||||||
|
setRangeTime([...rangeTime]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const nodeScopeChange = (data: any, isTop?: any) => {
|
||||||
|
setScopeData({
|
||||||
|
isTop,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onChangeCallback({
|
onChangeCallback({
|
||||||
rangeTime,
|
rangeTime,
|
||||||
@@ -129,68 +157,37 @@ const SingleChartHeader = ({
|
|||||||
};
|
};
|
||||||
}, [isRelativeRangeTime, rangeTime]);
|
}, [isRelativeRangeTime, rangeTime]);
|
||||||
|
|
||||||
const sizeChange = (value: number) => {
|
|
||||||
setGridNum(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const timeChange = (curRangeTime: [number, number], isRelative: boolean) => {
|
|
||||||
setRangeTime([...curRangeTime]);
|
|
||||||
setIsRelativeRangeTime(isRelative);
|
|
||||||
};
|
|
||||||
|
|
||||||
const reloadRangeTime = () => {
|
|
||||||
if (isRelativeRangeTime) {
|
|
||||||
const timeLen = rangeTime[1] - rangeTime[0] || 0;
|
|
||||||
const curTimeStamp = moment().valueOf();
|
|
||||||
setRangeTime([curTimeStamp - timeLen, curTimeStamp]);
|
|
||||||
} else {
|
|
||||||
setRangeTime([...rangeTime]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const openIndicatorDrawer = () => {
|
|
||||||
setIndicatorDrawerVisible(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeIndicatorDrawer = () => {
|
|
||||||
setIndicatorDrawerVisible(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const nodeScopeChange = (data: any, isTop?: any) => {
|
|
||||||
setScopeData({
|
|
||||||
isTop,
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="ks-chart-container">
|
<div className="ks-chart-container">
|
||||||
<div className="ks-chart-container-header">
|
<div className="ks-chart-container-header">
|
||||||
<div className="header-left">
|
<div className="header-left">
|
||||||
|
{/* 刷新 */}
|
||||||
<div className="icon-box" onClick={reloadRangeTime}>
|
<div className="icon-box" onClick={reloadRangeTime}>
|
||||||
<IconFont className="icon" type="icon-shuaxin1" />
|
<IconFont className="icon" type="icon-shuaxin1" />
|
||||||
</div>
|
</div>
|
||||||
<Divider type="vertical" style={{ height: 20, top: 0 }} />
|
<Divider type="vertical" style={{ height: 20, top: 0 }} />
|
||||||
|
{/* 时间选择 */}
|
||||||
<DRangeTime timeChange={timeChange} rangeTimeArr={rangeTime} />
|
<DRangeTime timeChange={timeChange} rangeTimeArr={rangeTime} />
|
||||||
</div>
|
</div>
|
||||||
<div className="header-right">
|
<div className="header-right">
|
||||||
|
{/* 节点范围 */}
|
||||||
{!hideNodeScope && <NodeScope nodeScopeModule={nodeScopeModule} change={nodeScopeChange} />}
|
{!hideNodeScope && <NodeScope nodeScopeModule={nodeScopeModule} change={nodeScopeChange} />}
|
||||||
|
{/* 分栏 */}
|
||||||
{!hideGridSelect && (
|
{!hideGridSelect && (
|
||||||
<Select className="grid-select" style={{ width: 70 }} value={gridNum} options={GRID_SIZE_OPTIONS} onChange={sizeChange} />
|
<Select className="grid-select" style={{ width: 70 }} value={gridNum} options={GRID_SIZE_OPTIONS} onChange={sizeChange} />
|
||||||
)}
|
)}
|
||||||
{(!hideNodeScope || !hideGridSelect) && <Divider type="vertical" style={{ height: 20, top: 0 }} />}
|
{(!hideNodeScope || !hideGridSelect) && <Divider type="vertical" style={{ height: 20, top: 0 }} />}
|
||||||
<Button type="primary" onClick={openIndicatorDrawer}>
|
<Button type="primary" onClick={() => metricSelectRef.current.open()}>
|
||||||
指标筛选
|
指标筛选
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!indicatorSelectModule?.hide && (
|
{/* 指标筛选 */}
|
||||||
<IndicatorDrawer visible={indicatorDrawerVisible} onClose={closeIndicatorDrawer} indicatorSelectModule={indicatorSelectModule} />
|
{!metricSelect?.hide && <MetricSelect ref={metricSelectRef} metricSelect={metricSelect} />}
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SingleChartHeader;
|
export default MetricOperateBar;
|
||||||
@@ -1,13 +1,8 @@
|
|||||||
@root-entry-name: 'default';
|
.indicator-drawer {
|
||||||
@import '~knowdesign/es/basic/style/themes/index';
|
.dcloud-drawer-body {
|
||||||
@import '~knowdesign/es/basic/style/mixins/index';
|
padding-top: 2px !important;
|
||||||
|
|
||||||
|
|
||||||
.indicator-drawer{
|
|
||||||
.dcloud-drawer-body{
|
|
||||||
padding-top: 2px !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// .dd-indicator-drawer {
|
// .dd-indicator-drawer {
|
||||||
// @drawerItemH: 27px;
|
// @drawerItemH: 27px;
|
||||||
// @primary-color: #556ee6;
|
// @primary-color: #556ee6;
|
||||||
@@ -63,9 +63,16 @@
|
|||||||
}
|
}
|
||||||
.@{ant-prefix}-popover-inner-content {
|
.@{ant-prefix}-popover-inner-content {
|
||||||
padding: 16px 24px;
|
padding: 16px 24px;
|
||||||
width: 479px;
|
width: 200px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
&.large-size {
|
||||||
|
.@{ant-prefix}-popover-inner-content {
|
||||||
|
padding: 16px 24px;
|
||||||
|
width: 479px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
&.@{ant-prefix}-popover-placement-bottomRight {
|
&.@{ant-prefix}-popover-placement-bottomRight {
|
||||||
// padding-top: 0;
|
// padding-top: 0;
|
||||||
}
|
}
|
||||||
@@ -2,11 +2,10 @@ import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, use
|
|||||||
import { AppContainer, Drawer, Spin, Table, SingleChart, Utils, Tooltip } from 'knowdesign';
|
import { AppContainer, Drawer, Spin, Table, SingleChart, Utils, Tooltip } from 'knowdesign';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import api, { MetricType } from '@src/api';
|
import api, { MetricType } from '@src/api';
|
||||||
import { MetricDefaultChartDataType, MetricChartDataType, formatChartData } from '@src/constants/chartConfig';
|
import { OriginMetricData, FormattedMetricData, formatChartData } from '@src/constants/chartConfig';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { getDetailChartConfig } from './config';
|
import { getDetailChartConfig } from './config';
|
||||||
import { UNIT_MAP } from '@src/constants/chartConfig';
|
|
||||||
import RenderEmpty from '../RenderEmpty';
|
import RenderEmpty from '../RenderEmpty';
|
||||||
|
|
||||||
interface ChartDetailProps {
|
interface ChartDetailProps {
|
||||||
@@ -35,7 +34,7 @@ interface ChartInfo {
|
|||||||
curTimeRange?: readonly [number, number];
|
curTimeRange?: readonly [number, number];
|
||||||
sliderPos?: readonly [number, number];
|
sliderPos?: readonly [number, number];
|
||||||
transformUnit?: [string, number];
|
transformUnit?: [string, number];
|
||||||
fullMetricData?: MetricChartDataType;
|
fullMetricData?: FormattedMetricData;
|
||||||
oldDataZoomOption?: any;
|
oldDataZoomOption?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +78,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
|||||||
isLoadingAdditionData: false,
|
isLoadingAdditionData: false,
|
||||||
isLoadedFullData: false,
|
isLoadedFullData: false,
|
||||||
fullTimeRange: curTimeRange,
|
fullTimeRange: curTimeRange,
|
||||||
fullMetricData: {} as MetricChartDataType,
|
fullMetricData: {} as FormattedMetricData,
|
||||||
curTimeRange,
|
curTimeRange,
|
||||||
oldDataZoomOption: {},
|
oldDataZoomOption: {},
|
||||||
sliderPos: [0, 0],
|
sliderPos: [0, 0],
|
||||||
@@ -90,7 +89,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
|||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
// 当前展示的图表数据
|
// 当前展示的图表数据
|
||||||
const [curMetricData, setCurMetricData] = useState<MetricChartDataType>();
|
const [curMetricData, setCurMetricData] = useState<FormattedMetricData>();
|
||||||
// 图表数据的各项计算指标
|
// 图表数据的各项计算指标
|
||||||
const [tableInfo, setTableInfo] = useState<MetricTableInfo[]>([]);
|
const [tableInfo, setTableInfo] = useState<MetricTableInfo[]>([]);
|
||||||
const [linesStatus, setLinesStatus] = useState<{
|
const [linesStatus, setLinesStatus] = useState<{
|
||||||
@@ -329,7 +328,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
|||||||
if (i === DEFAULT_REQUEST_COUNT - 1) {
|
if (i === DEFAULT_REQUEST_COUNT - 1) {
|
||||||
Promise.all(requestArr).then((resList) => {
|
Promise.all(requestArr).then((resList) => {
|
||||||
// 填充增量的图表数据
|
// 填充增量的图表数据
|
||||||
resList.forEach((res: MetricDefaultChartDataType[], i) => {
|
resList.forEach((res: OriginMetricData[], i) => {
|
||||||
// 最后一个请求返回数据为空时,认为已获取到全部图表数据
|
// 最后一个请求返回数据为空时,认为已获取到全部图表数据
|
||||||
if (!res?.length) {
|
if (!res?.length) {
|
||||||
// 标记数据已经全部加载完毕
|
// 标记数据已经全部加载完毕
|
||||||
@@ -368,7 +367,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 处理增量图表数据
|
// 处理增量图表数据
|
||||||
const resolveAdditionChartData = (res: MetricDefaultChartDataType[], timeRange: [number, number]) => {
|
const resolveAdditionChartData = (res: OriginMetricData[], timeRange: [number, number]) => {
|
||||||
// 格式化图表需要的数据
|
// 格式化图表需要的数据
|
||||||
const formattedMetricData = formatChartData(
|
const formattedMetricData = formatChartData(
|
||||||
res,
|
res,
|
||||||
@@ -376,7 +375,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
|||||||
metricType,
|
metricType,
|
||||||
timeRange,
|
timeRange,
|
||||||
chartInfo.current.transformUnit
|
chartInfo.current.transformUnit
|
||||||
) as MetricChartDataType[];
|
) as FormattedMetricData[];
|
||||||
// 增量填充图表数据
|
// 增量填充图表数据
|
||||||
const additionMetricPoints = formattedMetricData[0].metricLines;
|
const additionMetricPoints = formattedMetricData[0].metricLines;
|
||||||
Object.values(additionMetricPoints).forEach((additionLine) => {
|
Object.values(additionMetricPoints).forEach((additionLine) => {
|
||||||
@@ -536,9 +535,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
|||||||
// 如果图表返回数据
|
// 如果图表返回数据
|
||||||
if (res?.length) {
|
if (res?.length) {
|
||||||
// 格式化图表需要的数据
|
// 格式化图表需要的数据
|
||||||
const formattedMetricData = (
|
const formattedMetricData = formatChartData(res, global.getMetricDefine || {}, metricType, curTimeRange)[0];
|
||||||
formatChartData(res, global.getMetricDefine || {}, metricType, curTimeRange) as MetricChartDataType[]
|
|
||||||
)[0];
|
|
||||||
// 填充图表数据
|
// 填充图表数据
|
||||||
let initFullTimeRange = curTimeRange;
|
let initFullTimeRange = curTimeRange;
|
||||||
const pointsOfFirstLine = formattedMetricData.metricLines.find((line) => line.data.length).data;
|
const pointsOfFirstLine = formattedMetricData.metricLines.find((line) => line.data.length).data;
|
||||||
@@ -549,14 +546,6 @@ const ChartDetail = (props: ChartDetailProps) => {
|
|||||||
] as const;
|
] as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取单位保存起来
|
|
||||||
let transformUnit = undefined;
|
|
||||||
Object.entries(UNIT_MAP).forEach((unit) => {
|
|
||||||
if (formattedMetricData.metricUnit.includes(unit[0])) {
|
|
||||||
transformUnit = unit;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
updateChartInfo({
|
updateChartInfo({
|
||||||
fullMetricData: formattedMetricData,
|
fullMetricData: formattedMetricData,
|
||||||
fullTimeRange: [...initFullTimeRange],
|
fullTimeRange: [...initFullTimeRange],
|
||||||
@@ -565,7 +554,7 @@ const ChartDetail = (props: ChartDetailProps) => {
|
|||||||
initFullTimeRange[1] - (initFullTimeRange[1] - initFullTimeRange[0]) * DATA_ZOOM_DEFAULT_SCALE,
|
initFullTimeRange[1] - (initFullTimeRange[1] - initFullTimeRange[0]) * DATA_ZOOM_DEFAULT_SCALE,
|
||||||
initFullTimeRange[1],
|
initFullTimeRange[1],
|
||||||
],
|
],
|
||||||
transformUnit,
|
transformUnit: formattedMetricData.targetUnit,
|
||||||
});
|
});
|
||||||
setCurMetricData(formattedMetricData);
|
setCurMetricData(formattedMetricData);
|
||||||
const newLinesStatus: { [lineName: string]: boolean } = {};
|
const newLinesStatus: { [lineName: string]: boolean } = {};
|
||||||
@@ -1,11 +1,22 @@
|
|||||||
|
import api, { MetricType } from '@src/api';
|
||||||
import { getBasicChartConfig, CHART_COLOR_LIST } from '@src/constants/chartConfig';
|
import { getBasicChartConfig, CHART_COLOR_LIST } from '@src/constants/chartConfig';
|
||||||
|
|
||||||
|
const METRIC_DASHBOARD_REQ_MAP = {
|
||||||
|
[MetricType.Broker]: (clusterId: string) => api.getDashboardMetricChartData(clusterId, MetricType.Broker),
|
||||||
|
[MetricType.Topic]: (clusterId: string) => api.getDashboardMetricChartData(clusterId, MetricType.Topic),
|
||||||
|
[MetricType.Zookeeper]: (clusterId: string) => '',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getMetricDashboardReq = (clusterId: string, type: MetricType.Broker | MetricType.Topic | MetricType.Zookeeper) =>
|
||||||
|
METRIC_DASHBOARD_REQ_MAP[type](clusterId);
|
||||||
|
|
||||||
const seriesCallback = (lines: { name: string; data: [number, string | number][] }[]) => {
|
const seriesCallback = (lines: { name: string; data: [number, string | number][] }[]) => {
|
||||||
const len = CHART_COLOR_LIST.length;
|
const len = CHART_COLOR_LIST.length;
|
||||||
// series 配置
|
// series 配置
|
||||||
return lines.map((line, i) => {
|
return lines.map((line, i) => {
|
||||||
return {
|
return {
|
||||||
...line,
|
...line,
|
||||||
|
z: len - i,
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
width: 1.5,
|
width: 1.5,
|
||||||
},
|
},
|
||||||
@@ -13,6 +24,7 @@ const seriesCallback = (lines: { name: string; data: [number, string | number][]
|
|||||||
symbol: 'emptyCircle',
|
symbol: 'emptyCircle',
|
||||||
symbolSize: 4,
|
symbolSize: 4,
|
||||||
smooth: 0.25,
|
smooth: 0.25,
|
||||||
|
color: CHART_COLOR_LIST[i % len],
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: {
|
color: {
|
||||||
type: 'linear',
|
type: 'linear',
|
||||||
@@ -38,17 +50,13 @@ const seriesCallback = (lines: { name: string; data: [number, string | number][]
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 返回图表配置
|
// 返回图表配置
|
||||||
export const getChartConfig = (title: string, metricLength: number) => {
|
export const getChartConfig = (title: string, metricLength: number, showLegend = true) => {
|
||||||
return {
|
return {
|
||||||
option: getBasicChartConfig({
|
option: getBasicChartConfig({
|
||||||
title: { show: false },
|
title: { show: false },
|
||||||
grid: { top: 24 },
|
grid: { top: 24, bottom: showLegend ? 40 : 20 },
|
||||||
tooltip: { enterable: metricLength > 9, legendContextMaxHeight: 192 },
|
tooltip: { enterable: metricLength > 9, legendContextMaxHeight: 192 },
|
||||||
color: CHART_COLOR_LIST,
|
legend: { show: showLegend },
|
||||||
// xAxis: {
|
|
||||||
// type: 'time',
|
|
||||||
// boundaryGap: ['5%', '5%'],
|
|
||||||
// },
|
|
||||||
}),
|
}),
|
||||||
seriesCallback,
|
seriesCallback,
|
||||||
};
|
};
|
||||||
@@ -67,7 +75,6 @@ export const getDetailChartConfig = (title: string, sliderPos: readonly [number,
|
|||||||
legend: {
|
legend: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
color: CHART_COLOR_LIST,
|
|
||||||
dataZoom: [
|
dataZoom: [
|
||||||
{
|
{
|
||||||
type: 'inside',
|
type: 'inside',
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
.topic-dashboard {
|
.topic-dashboard {
|
||||||
height: calc(100% - 160px);
|
height: calc(100% - 162px);
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
.ks-chart-container-header {
|
.ks-chart-container-header {
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
@@ -4,17 +4,11 @@ import { Utils, Empty, Spin, AppContainer, SingleChart, Tooltip } from 'knowdesi
|
|||||||
import { IconFont } from '@knowdesign/icons';
|
import { IconFont } from '@knowdesign/icons';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import api, { MetricType } from '@src/api';
|
import api, { MetricType } from '@src/api';
|
||||||
import {
|
import { MetricInfo, OriginMetricData, FormattedMetricData, formatChartData, resolveMetricsRank } from '@src/constants/chartConfig';
|
||||||
MetricInfo,
|
import ChartOperateBar, { KsHeaderOptions } from '../ChartOperateBar';
|
||||||
MetricDefaultChartDataType,
|
|
||||||
MetricChartDataType,
|
|
||||||
formatChartData,
|
|
||||||
resolveMetricsRank,
|
|
||||||
} from '@src/constants/chartConfig';
|
|
||||||
import SingleChartHeader, { KsHeaderOptions } from '../SingleChartHeader';
|
|
||||||
import DragGroup from '../DragGroup';
|
import DragGroup from '../DragGroup';
|
||||||
import ChartDetail from './ChartDetail';
|
import ChartDetail from './Detail';
|
||||||
import { getChartConfig } from './config';
|
import { getChartConfig, getMetricDashboardReq } from './config';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
|
||||||
interface IcustomScope {
|
interface IcustomScope {
|
||||||
@@ -33,7 +27,7 @@ const busInstance = new EventBus();
|
|||||||
|
|
||||||
const DRAG_GROUP_GUTTER_NUM: [number, number] = [16, 16];
|
const DRAG_GROUP_GUTTER_NUM: [number, number] = [16, 16];
|
||||||
|
|
||||||
const DashboardDragChart = (props: PropsType): JSX.Element => {
|
const DraggableCharts = (props: PropsType): JSX.Element => {
|
||||||
const [global] = AppContainer.useGlobalValue();
|
const [global] = AppContainer.useGlobalValue();
|
||||||
const { type: dashboardType } = props;
|
const { type: dashboardType } = props;
|
||||||
const { clusterId } = useParams<{
|
const { clusterId } = useParams<{
|
||||||
@@ -44,7 +38,7 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
|||||||
const [metricsList, setMetricsList] = useState<MetricInfo[]>([]); // 指标列表
|
const [metricsList, setMetricsList] = useState<MetricInfo[]>([]); // 指标列表
|
||||||
const [selectedMetricNames, setSelectedMetricNames] = useState<(string | number)[]>([]); // 默认选中的指标的列表
|
const [selectedMetricNames, setSelectedMetricNames] = useState<(string | number)[]>([]); // 默认选中的指标的列表
|
||||||
const [curHeaderOptions, setCurHeaderOptions] = useState<ChartFilterOptions>();
|
const [curHeaderOptions, setCurHeaderOptions] = useState<ChartFilterOptions>();
|
||||||
const [metricChartData, setMetricChartData] = useState<MetricChartDataType[]>([]); // 指标图表数据列表
|
const [metricChartData, setMetricChartData] = useState<FormattedMetricData[]>([]); // 指标图表数据列表
|
||||||
const [gridNum, setGridNum] = useState<number>(12); // 图表列布局
|
const [gridNum, setGridNum] = useState<number>(12); // 图表列布局
|
||||||
const metricRankList = useRef<string[]>([]);
|
const metricRankList = useRef<string[]>([]);
|
||||||
const chartDetailRef = useRef(null);
|
const chartDetailRef = useRef(null);
|
||||||
@@ -85,6 +79,9 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
|||||||
updateRank([...supportMetrics]);
|
updateRank([...supportMetrics]);
|
||||||
setMetricsList(supportMetrics);
|
setMetricsList(supportMetrics);
|
||||||
setSelectedMetricNames(selectedMetrics);
|
setSelectedMetricNames(selectedMetrics);
|
||||||
|
if (!selectedMetrics.length) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -106,16 +103,24 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
|||||||
const curTimestamp = Date.now();
|
const curTimestamp = Date.now();
|
||||||
curFetchingTimestamp.current = curTimestamp;
|
curFetchingTimestamp.current = curTimestamp;
|
||||||
|
|
||||||
Utils.post(api.getDashboardMetricChartData(clusterId, dashboardType), {
|
const reqBody = Object.assign(
|
||||||
startTime,
|
{
|
||||||
endTime,
|
startTime,
|
||||||
metricsNames: selectedMetricNames,
|
endTime,
|
||||||
topNu: curHeaderOptions?.scopeData?.isTop ? curHeaderOptions.scopeData.data : null,
|
metricsNames: selectedMetricNames,
|
||||||
[dashboardType === MetricType.Broker ? 'brokerIds' : 'topics']: curHeaderOptions?.scopeData?.isTop
|
topNu: curHeaderOptions?.scopeData?.isTop ? curHeaderOptions.scopeData.data : null,
|
||||||
? null
|
},
|
||||||
: curHeaderOptions.scopeData.data,
|
dashboardType === MetricType.Broker || dashboardType === MetricType.Topic
|
||||||
}).then(
|
? {
|
||||||
(res: MetricDefaultChartDataType[] | null) => {
|
[dashboardType === MetricType.Broker ? 'brokerIds' : 'topics']: curHeaderOptions?.scopeData?.isTop
|
||||||
|
? null
|
||||||
|
: curHeaderOptions.scopeData.data,
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
);
|
||||||
|
|
||||||
|
Utils.post(getMetricDashboardReq(clusterId, dashboardType as any), reqBody).then(
|
||||||
|
(res: OriginMetricData[] | null) => {
|
||||||
// 如果当前请求不是最新请求,则不做任何操作
|
// 如果当前请求不是最新请求,则不做任何操作
|
||||||
if (curFetchingTimestamp.current !== curTimestamp) {
|
if (curFetchingTimestamp.current !== curTimestamp) {
|
||||||
return;
|
return;
|
||||||
@@ -131,7 +136,7 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
|||||||
global.getMetricDefine || {},
|
global.getMetricDefine || {},
|
||||||
dashboardType,
|
dashboardType,
|
||||||
curHeaderOptions.rangeTime
|
curHeaderOptions.rangeTime
|
||||||
) as MetricChartDataType[];
|
) as FormattedMetricData[];
|
||||||
// 指标排序
|
// 指标排序
|
||||||
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));
|
||||||
|
|
||||||
@@ -164,7 +169,7 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 指标选中项更新回调
|
// 指标选中项更新回调
|
||||||
const indicatorChangeCallback = (newMetricNames: (string | number)[]) => {
|
const metricSelectCallback = (newMetricNames: (string | number)[]) => {
|
||||||
const updateMetrics: { metric: string; set: boolean; rank: number }[] = [];
|
const updateMetrics: { metric: string; set: boolean; rank: number }[] = [];
|
||||||
// 需要选中的指标
|
// 需要选中的指标
|
||||||
newMetricNames.forEach(
|
newMetricNames.forEach(
|
||||||
@@ -218,7 +223,7 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 初始化页面,获取 scope 和 metric 信息
|
// 初始化页面,获取 scope 和 metric 信息
|
||||||
getScopeList();
|
(dashboardType === MetricType.Broker || dashboardType === MetricType.Topic) && getScopeList();
|
||||||
getMetricList();
|
getMetricList();
|
||||||
|
|
||||||
setTimeout(() => observeDashboardWidthChange());
|
setTimeout(() => observeDashboardWidthChange());
|
||||||
@@ -226,19 +231,22 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="dashboard-drag-chart" className="topic-dashboard">
|
<div id="dashboard-drag-chart" className="topic-dashboard">
|
||||||
<SingleChartHeader
|
<ChartOperateBar
|
||||||
onChange={ksHeaderChange}
|
onChange={ksHeaderChange}
|
||||||
nodeScopeModule={{
|
nodeScopeModule={{
|
||||||
|
hasCustomScope: !(dashboardType === MetricType.Zookeeper),
|
||||||
customScopeList: scopeList,
|
customScopeList: scopeList,
|
||||||
scopeName: dashboardType === MetricType.Broker ? 'Broker' : 'Topic',
|
scopeName: dashboardType === MetricType.Broker ? 'Broker' : dashboardType === MetricType.Topic ? 'Topic' : 'Zookeeper',
|
||||||
scopeLabel: `自定义 ${dashboardType === MetricType.Broker ? 'Broker' : 'Topic'} 范围`,
|
scopeLabel: `自定义 ${
|
||||||
|
dashboardType === MetricType.Broker ? 'Broker' : dashboardType === MetricType.Topic ? 'Topic' : 'Zookeeper'
|
||||||
|
} 范围`,
|
||||||
}}
|
}}
|
||||||
indicatorSelectModule={{
|
metricSelect={{
|
||||||
hide: false,
|
hide: false,
|
||||||
metricType: dashboardType,
|
metricType: dashboardType,
|
||||||
tableData: metricsList,
|
tableData: metricsList,
|
||||||
selectedRows: selectedMetricNames,
|
selectedRows: selectedMetricNames,
|
||||||
submitCallback: indicatorChangeCallback,
|
submitCallback: metricSelectCallback,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="topic-dashboard-container">
|
<div className="topic-dashboard-container">
|
||||||
@@ -258,7 +266,7 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{metricChartData.map((data) => {
|
{metricChartData.map((data) => {
|
||||||
const { metricName, metricUnit, metricLines } = data;
|
const { metricName, metricUnit, metricLines, showLegend } = data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={metricName} className="dashboard-drag-item-box">
|
<div key={metricName} className="dashboard-drag-item-box">
|
||||||
@@ -301,7 +309,7 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
|||||||
eventBus={busInstance}
|
eventBus={busInstance}
|
||||||
propChartData={metricLines}
|
propChartData={metricLines}
|
||||||
optionMergeProps={{ replaceMerge: curHeaderOptions.isAutoReload ? ['xAxis'] : ['series'] }}
|
optionMergeProps={{ replaceMerge: curHeaderOptions.isAutoReload ? ['xAxis'] : ['series'] }}
|
||||||
{...getChartConfig(`${metricName}{unit|(${metricUnit})}`, metricLines.length)}
|
{...getChartConfig(`${metricName}{unit|(${metricUnit})}`, metricLines.length, showLegend)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -321,4 +329,4 @@ const DashboardDragChart = (props: PropsType): JSX.Element => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DashboardDragChart;
|
export default DraggableCharts;
|
||||||
@@ -12,30 +12,38 @@ export interface MetricInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 接口返回图表原始数据类型
|
// 接口返回图表原始数据类型
|
||||||
export interface MetricDefaultChartDataType {
|
export interface OriginMetricData {
|
||||||
metricName: string;
|
metricName: string;
|
||||||
metricLines: {
|
metricLines?: {
|
||||||
name: string;
|
name: string;
|
||||||
createTime: number;
|
createTime: number;
|
||||||
updateTime: number;
|
updateTime: number;
|
||||||
metricPoints: {
|
metricPoints: {
|
||||||
aggType: string;
|
aggType: string;
|
||||||
timeStamp: number;
|
timeStamp: number;
|
||||||
value: number;
|
value: string;
|
||||||
createTime: number;
|
createTime: number;
|
||||||
updateTime: number;
|
updateTime: number;
|
||||||
}[];
|
}[];
|
||||||
}[];
|
}[];
|
||||||
|
metricPoints?: {
|
||||||
|
aggType: string;
|
||||||
|
name: string;
|
||||||
|
timeStamp: number;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 格式化后图表数据类型
|
// 格式化后图表数据类型
|
||||||
export interface MetricChartDataType {
|
export interface FormattedMetricData {
|
||||||
metricName: string;
|
metricName: string;
|
||||||
metricUnit: string;
|
metricUnit: string;
|
||||||
metricLines: {
|
metricLines: {
|
||||||
name: string;
|
name: string;
|
||||||
data: (string | number)[][];
|
data: (string | number)[][];
|
||||||
}[];
|
}[];
|
||||||
|
showLegend: boolean;
|
||||||
|
targetUnit: [string, number] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 图表颜色库
|
// 图表颜色库
|
||||||
@@ -55,22 +63,38 @@ export const CHART_COLOR_LIST = [
|
|||||||
'#C9E795',
|
'#C9E795',
|
||||||
];
|
];
|
||||||
|
|
||||||
// 图表存储单位换算
|
// 图表存储单位
|
||||||
export const UNIT_MAP = {
|
export const MEMORY_MAP = {
|
||||||
TB: Math.pow(1024, 4),
|
TB: Math.pow(1024, 4),
|
||||||
GB: Math.pow(1024, 3),
|
GB: Math.pow(1024, 3),
|
||||||
MB: Math.pow(1024, 2),
|
MB: Math.pow(1024, 2),
|
||||||
KB: 1024,
|
KB: 1024,
|
||||||
};
|
};
|
||||||
export const getUnit = (value: number) => Object.entries(UNIT_MAP).find(([, size]) => value / size >= 1) || ['Byte', 1];
|
// 图表时间单位
|
||||||
|
export const TIME_MAP = {
|
||||||
// 图表数字单位换算
|
h: 1000 * 60 * 60,
|
||||||
export const DATA_NUMBER_MAP = {
|
min: 1000 * 60,
|
||||||
|
s: 1000,
|
||||||
|
};
|
||||||
|
// 图表数字单位
|
||||||
|
export const NUM_MAP = {
|
||||||
十亿: Math.pow(1000, 3),
|
十亿: Math.pow(1000, 3),
|
||||||
百万: Math.pow(1000, 2),
|
百万: Math.pow(1000, 2),
|
||||||
千: 1000,
|
千: 1000,
|
||||||
};
|
};
|
||||||
export const getDataNumberUnit = (value: number) => Object.entries(DATA_NUMBER_MAP).find(([, size]) => value / size >= 1) || ['', 1];
|
const calculateUnit = (map: { [unit: string]: number }, targetValue: number) => {
|
||||||
|
return Object.entries(map).find(([, size]) => targetValue / size >= 1);
|
||||||
|
};
|
||||||
|
const getMemoryUnit = (value: number) => calculateUnit(MEMORY_MAP, value) || ['Byte', 1];
|
||||||
|
const getTimeUnit = (value: number) => calculateUnit(TIME_MAP, value) || ['ms', 1];
|
||||||
|
const getNumUnit = (value: number) => calculateUnit(NUM_MAP, value) || ['', 1];
|
||||||
|
|
||||||
|
export const getDataUnit = {
|
||||||
|
Memory: getMemoryUnit,
|
||||||
|
Time: getTimeUnit,
|
||||||
|
Num: getNumUnit,
|
||||||
|
};
|
||||||
|
export type DataUnitType = keyof typeof getDataUnit;
|
||||||
|
|
||||||
// 图表补点间隔计算
|
// 图表补点间隔计算
|
||||||
export const SUPPLEMENTARY_INTERVAL_MAP = {
|
export const SUPPLEMENTARY_INTERVAL_MAP = {
|
||||||
@@ -112,9 +136,9 @@ export const resolveMetricsRank = (metricList: MetricInfo[]) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// 补点
|
// 图表补点
|
||||||
export const supplementaryPoints = (
|
export const supplementaryPoints = (
|
||||||
lines: MetricChartDataType['metricLines'],
|
lines: FormattedMetricData['metricLines'],
|
||||||
timeRange: readonly [number, number],
|
timeRange: readonly [number, number],
|
||||||
extraCallback?: (point: [number, 0]) => any[]
|
extraCallback?: (point: [number, 0]) => any[]
|
||||||
): void => {
|
): void => {
|
||||||
@@ -165,19 +189,39 @@ export const supplementaryPoints = (
|
|||||||
// 格式化图表数据
|
// 格式化图表数据
|
||||||
export const formatChartData = (
|
export const formatChartData = (
|
||||||
// 图表源数据
|
// 图表源数据
|
||||||
metricData: MetricDefaultChartDataType[],
|
metricsData: OriginMetricData[],
|
||||||
// 获取指标单位
|
// 获取指标单位
|
||||||
getMetricDefine: (type: MetricType, metric: string) => MetricsDefine[keyof MetricsDefine],
|
getMetricDefine: (type: MetricType, metric: string) => MetricsDefine[keyof MetricsDefine],
|
||||||
// 指标类型
|
// 指标类型
|
||||||
metricType: MetricType,
|
metricType: MetricType,
|
||||||
// 图表时间范围,用于补点
|
// 图表时间范围,用于补点
|
||||||
timeRange: readonly [number, number],
|
timeRange: readonly [number, number],
|
||||||
transformUnit: [string, number] = undefined
|
targetUnit: [string, number] = undefined
|
||||||
): MetricChartDataType[] => {
|
): FormattedMetricData[] => {
|
||||||
return metricData.map(({ metricName, metricLines }) => {
|
return metricsData.map((originData) => {
|
||||||
|
const { metricName } = originData;
|
||||||
const curMetricInfo = (getMetricDefine && getMetricDefine(metricType, metricName)) || null;
|
const curMetricInfo = (getMetricDefine && getMetricDefine(metricType, metricName)) || null;
|
||||||
const isByteUnit = curMetricInfo?.unit?.toLowerCase().includes('byte');
|
let showLegend = true;
|
||||||
|
let metricLines = [];
|
||||||
let maxValue = -1;
|
let maxValue = -1;
|
||||||
|
let unitType: DataUnitType;
|
||||||
|
|
||||||
|
if (originData?.metricLines && originData?.metricLines !== null) {
|
||||||
|
metricLines = originData.metricLines;
|
||||||
|
} else {
|
||||||
|
showLegend = false;
|
||||||
|
metricLines = [
|
||||||
|
{
|
||||||
|
name: metricName,
|
||||||
|
metricPoints: originData.metricPoints,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const originUnit = curMetricInfo?.unit?.toLowerCase();
|
||||||
|
unitType = originUnit.includes('byte') ? 'Memory' : originUnit.includes('ms') ? 'Time' : 'Num';
|
||||||
|
}
|
||||||
|
|
||||||
const PointsMapMethod = ({ timeStamp, value }: { timeStamp: number; value: string | number }) => {
|
const PointsMapMethod = ({ timeStamp, value }: { timeStamp: number; value: string | number }) => {
|
||||||
let parsedValue: string | number = Number(value);
|
let parsedValue: string | number = Number(value);
|
||||||
@@ -194,7 +238,7 @@ export const formatChartData = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 初始化返回结构
|
// 初始化返回结构
|
||||||
const chartData = {
|
const chartData: FormattedMetricData = {
|
||||||
metricName,
|
metricName,
|
||||||
metricUnit: curMetricInfo?.unit || '',
|
metricUnit: curMetricInfo?.unit || '',
|
||||||
metricLines: metricLines
|
metricLines: metricLines
|
||||||
@@ -203,17 +247,21 @@ export const formatChartData = (
|
|||||||
name,
|
name,
|
||||||
data: metricPoints.map(PointsMapMethod),
|
data: metricPoints.map(PointsMapMethod),
|
||||||
})),
|
})),
|
||||||
|
showLegend,
|
||||||
|
targetUnit: undefined,
|
||||||
};
|
};
|
||||||
// 按时间先后进行对图表点排序
|
// 按时间先后进行对图表点排序
|
||||||
chartData.metricLines.forEach(({ data }) => data.sort((a, b) => (a[0] as number) - (b[0] as number)));
|
chartData.metricLines.forEach(({ data }) => data.sort((a, b) => (a[0] as number) - (b[0] as number)));
|
||||||
|
|
||||||
// 图表值单位转换
|
// 图表值单位转换
|
||||||
if (maxValue > 0) {
|
if (maxValue > 0) {
|
||||||
const [unitName, unitSize]: [string, number] = transformUnit || isByteUnit ? getUnit(maxValue) : getDataNumberUnit(maxValue);
|
const [unitName, unitSize]: [string, number] = targetUnit || getDataUnit[unitType](maxValue);
|
||||||
chartData.metricUnit = isByteUnit
|
chartData.targetUnit = [unitName, unitSize];
|
||||||
? chartData.metricUnit.toLowerCase().replace('byte', unitName)
|
chartData.metricUnit =
|
||||||
: `${unitName}${chartData.metricUnit}`;
|
unitType !== 'Num'
|
||||||
chartData.metricLines.forEach(({ data }) => data.forEach((point: any) => (point[1] /= unitSize)));
|
? chartData.metricUnit.toLowerCase().replace(unitType === 'Memory' ? 'byte' : 'ms', unitName)
|
||||||
|
: `${unitName}${chartData.metricUnit}`;
|
||||||
|
chartData.metricLines.forEach(({ data }) => data.forEach((point: any) => parseFloat((point[1] /= unitSize).toFixed(3))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 补点
|
// 补点
|
||||||
@@ -231,7 +279,7 @@ const tooltipFormatter = (date: any, arr: any, tooltip: any) => {
|
|||||||
<div style="display:flex;align-items:center;">
|
<div style="display:flex;align-items:center;">
|
||||||
<div style="margin-right:4px;width:8px;height:2px;background-color:${item.color};"></div>
|
<div style="margin-right:4px;width:8px;height:2px;background-color:${item.color};"></div>
|
||||||
<div style="flex:1;display:flex;justify-content:space-between;align-items:center;overflow: hidden;">
|
<div style="flex:1;display:flex;justify-content:space-between;align-items:center;overflow: hidden;">
|
||||||
<span style="font-size:12px;color:#74788D;pointer-events:auto;margin-left:2px;line-height: 18px;font-family: HelveticaNeue;overflow: hidden; text-overflow: ellipsis; white-space: no-wrap;">
|
<span style="font-size:12px;color:#74788D;pointer-events:auto;margin-left:2px;line-height: 18px;font-family: HelveticaNeue;overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||||
${item.seriesName}
|
${item.seriesName}
|
||||||
</span>
|
</span>
|
||||||
<span style="font-size:12px;color:#212529;line-height:18px;font-family:HelveticaNeue-Medium; padding-left: 6px;">
|
<span style="font-size:12px;color:#212529;line-height:18px;font-family:HelveticaNeue-Medium; padding-left: 6px;">
|
||||||
@@ -324,6 +372,7 @@ export const getBasicChartConfig = (props: any = {}) => {
|
|||||||
tooltip: false,
|
tooltip: false,
|
||||||
...legend,
|
...legend,
|
||||||
},
|
},
|
||||||
|
color: CHART_COLOR_LIST,
|
||||||
// 横坐标配置
|
// 横坐标配置
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'category',
|
type: 'category',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MetricType } from '@src/api';
|
import { MetricType } from '@src/api';
|
||||||
import BrokerHealthCheck from '@src/components/CardBar/BrokerHealthCheck';
|
import BrokerHealthCheck from '@src/components/CardBar/BrokerHealthCheck';
|
||||||
import DashboardDragChart from '@src/components/DashboardDragChart';
|
import DraggableCharts from '@src/components/DraggableCharts';
|
||||||
import DBreadcrumb from 'knowdesign/es/extend/d-breadcrumb';
|
import DBreadcrumb from 'knowdesign/es/extend/d-breadcrumb';
|
||||||
import { AppContainer } from 'knowdesign';
|
import { AppContainer } from 'knowdesign';
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ const BrokerDashboard = (): JSX.Element => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<BrokerHealthCheck />
|
<BrokerHealthCheck />
|
||||||
<DashboardDragChart type={MetricType.Broker} />
|
<DraggableCharts type={MetricType.Broker} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { AppContainer, Divider, Form, Input, List, message, Modal, Progress, Spin, Tooltip, Utils } from 'knowdesign';
|
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 { IconFont } from '@knowdesign/icons';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import API from '@src/api';
|
import API from '@src/api';
|
||||||
@@ -11,7 +12,7 @@ import { useIntl } from 'react-intl';
|
|||||||
import api, { MetricType } from '@src/api';
|
import api, { MetricType } from '@src/api';
|
||||||
import { getHealthClassName, getHealthProcessColor, getHealthText } from '../SingleClusterDetail/config';
|
import { getHealthClassName, getHealthProcessColor, getHealthText } from '../SingleClusterDetail/config';
|
||||||
import { ClustersPermissionMap } from '../CommonConfig';
|
import { ClustersPermissionMap } from '../CommonConfig';
|
||||||
import { getUnit, getDataNumberUnit } from '@src/constants/chartConfig';
|
import { getDataUnit } from '@src/constants/chartConfig';
|
||||||
import SmallChart from '@src/components/SmallChart';
|
import SmallChart from '@src/components/SmallChart';
|
||||||
import { SearchParams } from './HomePage';
|
import { SearchParams } from './HomePage';
|
||||||
|
|
||||||
@@ -235,14 +236,14 @@ const ClusterList = (props: { searchParams: SearchParams; showAccessCluster: any
|
|||||||
|
|
||||||
// 如果单位是 字节 ,进行单位换算
|
// 如果单位是 字节 ,进行单位换算
|
||||||
if (line.unit.toLowerCase().includes('byte')) {
|
if (line.unit.toLowerCase().includes('byte')) {
|
||||||
const [unit, size] = getUnit(line.value);
|
const [unit, size] = getDataUnit['Memory'](line.value);
|
||||||
line.value = Number((line.value / size).toFixed(2));
|
line.value = Number((line.value / size).toFixed(2));
|
||||||
line.unit = line.unit.toLowerCase().replace('byte', unit);
|
line.unit = line.unit.toLowerCase().replace('byte', unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Messages 指标值特殊处理
|
// Messages 指标值特殊处理
|
||||||
if (line.metricName === 'LeaderMessages') {
|
if (line.metricName === 'LeaderMessages') {
|
||||||
const [unit, size] = getDataNumberUnit(line.value);
|
const [unit, size] = getDataUnit['Num'](line.value);
|
||||||
line.value = Number((line.value / size).toFixed(2));
|
line.value = Number((line.value / size).toFixed(2));
|
||||||
line.unit = unit + line.unit;
|
line.unit = unit + line.unit;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const messagesInTooltipFormatter = (date: any, arr: any) => {
|
|||||||
<div style="display:flex;align-items:center;">
|
<div style="display:flex;align-items:center;">
|
||||||
<div style="margin-right:4px;width:8px;height:2px;background-color:${params.color};"></div>
|
<div style="margin-right:4px;width:8px;height:2px;background-color:${params.color};"></div>
|
||||||
<div style="flex:1;display:flex;justify-content:space-between;align-items:center;overflow: hidden;">
|
<div style="flex:1;display:flex;justify-content:space-between;align-items:center;overflow: hidden;">
|
||||||
<span style="flex: 1;font-size:12px;color:#74788D;pointer-events:auto;margin-left:2px;line-height: 18px;font-family: HelveticaNeue;overflow: hidden; text-overflow: ellipsis; white-space: no-wrap;">
|
<span style="flex: 1;font-size:12px;color:#74788D;pointer-events:auto;margin-left:2px;line-height: 18px;font-family: HelveticaNeue;overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||||
${params.seriesName}
|
${params.seriesName}
|
||||||
</span>
|
</span>
|
||||||
<span style="font-size:12px;color:#212529;line-height:18px;font-family:HelveticaNeue-Medium;margin-left: 10px;">
|
<span style="font-size:12px;color:#212529;line-height:18px;font-family:HelveticaNeue-Medium;margin-left: 10px;">
|
||||||
@@ -55,7 +55,7 @@ const messagesInTooltipFormatter = (date: any, arr: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getChartConfig = (props: any) => {
|
export const getChartConfig = (props: any) => {
|
||||||
const { metricName, lineColor, isDefaultMetric = false } = props;
|
const { lineColor, isDefaultMetric = false } = props;
|
||||||
return {
|
return {
|
||||||
option: getBasicChartConfig({
|
option: getBasicChartConfig({
|
||||||
// TODO: time 轴图表联动有问题,先切换为 category
|
// TODO: time 轴图表联动有问题,先切换为 category
|
||||||
@@ -63,7 +63,6 @@ export const getChartConfig = (props: any) => {
|
|||||||
title: { show: false },
|
title: { show: false },
|
||||||
legend: { show: false },
|
legend: { show: false },
|
||||||
grid: { top: 24, bottom: 12 },
|
grid: { top: 24, bottom: 12 },
|
||||||
lineColor: [lineColor],
|
|
||||||
tooltip: isDefaultMetric
|
tooltip: isDefaultMetric
|
||||||
? {
|
? {
|
||||||
formatter: function (params: any) {
|
formatter: function (params: any) {
|
||||||
@@ -87,6 +86,7 @@ export const getChartConfig = (props: any) => {
|
|||||||
smooth: 0.25,
|
smooth: 0.25,
|
||||||
symbol: 'emptyCircle',
|
symbol: 'emptyCircle',
|
||||||
symbolSize: 4,
|
symbolSize: 4,
|
||||||
|
color: '#556ee6',
|
||||||
// 面积图样式
|
// 面积图样式
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: lineColor,
|
color: lineColor,
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import { arrayMoveImmutable } from 'array-move';
|
|||||||
import api from '@src/api';
|
import api from '@src/api';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
MetricDefaultChartDataType,
|
OriginMetricData,
|
||||||
MetricChartDataType,
|
FormattedMetricData,
|
||||||
formatChartData,
|
formatChartData,
|
||||||
supplementaryPoints,
|
supplementaryPoints,
|
||||||
resolveMetricsRank,
|
resolveMetricsRank,
|
||||||
MetricInfo,
|
MetricInfo,
|
||||||
} from '@src/constants/chartConfig';
|
} from '@src/constants/chartConfig';
|
||||||
import { MetricType } from '@src/api';
|
import { MetricType } from '@src/api';
|
||||||
import { getDataNumberUnit, getUnit } from '@src/constants/chartConfig';
|
import { getDataUnit } from '@src/constants/chartConfig';
|
||||||
import SingleChartHeader, { KsHeaderOptions } from '@src/components/SingleChartHeader';
|
import ChartOperateBar, { KsHeaderOptions } from '@src/components/ChartOperateBar';
|
||||||
import RenderEmpty from '@src/components/RenderEmpty';
|
import RenderEmpty from '@src/components/RenderEmpty';
|
||||||
import DragGroup from '@src/components/DragGroup';
|
import DragGroup from '@src/components/DragGroup';
|
||||||
import { getChartConfig } from './config';
|
import { getChartConfig } from './config';
|
||||||
@@ -162,13 +162,13 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
|
|||||||
metricsNames: selectedMetricNames.filter((name) => name !== DEFAULT_METRIC),
|
metricsNames: selectedMetricNames.filter((name) => name !== DEFAULT_METRIC),
|
||||||
},
|
},
|
||||||
}).then(
|
}).then(
|
||||||
(res: MetricDefaultChartDataType[]) => {
|
(res: OriginMetricData[]) => {
|
||||||
// 如果当前请求不是最新请求,则不做任何操作
|
// 如果当前请求不是最新请求,则不做任何操作
|
||||||
if (curFetchingTimestamp.current.messagesIn !== curTimestamp) {
|
if (curFetchingTimestamp.current.messagesIn !== curTimestamp) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formattedMetricData: MetricChartDataType[] = formatChartData(
|
const formattedMetricData: FormattedMetricData[] = formatChartData(
|
||||||
res,
|
res,
|
||||||
global.getMetricDefine || {},
|
global.getMetricDefine || {},
|
||||||
MetricType.Cluster,
|
MetricType.Cluster,
|
||||||
@@ -224,7 +224,7 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
|
|||||||
let valueWithUnit = Number(value);
|
let valueWithUnit = Number(value);
|
||||||
let unit = ((global.getMetricDefine && global.getMetricDefine(MetricType.Cluster, key)?.unit) || '') as string;
|
let unit = ((global.getMetricDefine && global.getMetricDefine(MetricType.Cluster, key)?.unit) || '') as string;
|
||||||
if (unit.toLowerCase().includes('byte')) {
|
if (unit.toLowerCase().includes('byte')) {
|
||||||
const [unitName, unitSize]: [string, number] = getUnit(Number(value));
|
const [unitName, unitSize]: [string, number] = getDataUnit['Memory'](Number(value));
|
||||||
unit = unit.toLowerCase().replace('byte', unitName);
|
unit = unit.toLowerCase().replace('byte', unitName);
|
||||||
valueWithUnit /= unitSize;
|
valueWithUnit /= unitSize;
|
||||||
}
|
}
|
||||||
@@ -235,7 +235,7 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
|
|||||||
};
|
};
|
||||||
return returnValue;
|
return returnValue;
|
||||||
});
|
});
|
||||||
return [timeStamp, values.MessagesIn || '0', valuesWithUnit] as [number, number | string, typeof valuesWithUnit];
|
return [timeStamp, parsedValue || '0', valuesWithUnit] as [number, number | string, typeof valuesWithUnit];
|
||||||
});
|
});
|
||||||
result.sort((a, b) => (a[0] as number) - (b[0] as number));
|
result.sort((a, b) => (a[0] as number) - (b[0] as number));
|
||||||
const line = {
|
const line = {
|
||||||
@@ -244,9 +244,9 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
|
|||||||
data: result as any,
|
data: result as any,
|
||||||
};
|
};
|
||||||
if (maxValue > 0) {
|
if (maxValue > 0) {
|
||||||
const [unitName, unitSize]: [string, number] = getDataNumberUnit(maxValue);
|
const [unitName, unitSize]: [string, number] = getDataUnit['Num'](maxValue);
|
||||||
line.unit = `${unitName}${line.unit}`;
|
line.unit = `${unitName}${line.unit}`;
|
||||||
result.forEach((point) => ((point[1] as number) /= unitSize));
|
result.forEach((point) => parseFloat(((point[1] as number) /= unitSize).toFixed(3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.length) {
|
if (result.length) {
|
||||||
@@ -308,11 +308,11 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="chart-panel cluster-detail-container">
|
<div className="chart-panel cluster-detail-container">
|
||||||
<SingleChartHeader
|
<ChartOperateBar
|
||||||
onChange={ksHeaderChange}
|
onChange={ksHeaderChange}
|
||||||
hideNodeScope={true}
|
hideNodeScope={true}
|
||||||
hideGridSelect={true}
|
hideGridSelect={true}
|
||||||
indicatorSelectModule={{
|
metricSelect={{
|
||||||
hide: false,
|
hide: false,
|
||||||
metricType: MetricType.Cluster,
|
metricType: MetricType.Cluster,
|
||||||
tableData: metricList,
|
tableData: metricList,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/* eslint-disable react/display-name */
|
/* eslint-disable react/display-name */
|
||||||
import { Button, Divider, Drawer, Form, message, ProTable, Table, Utils } from 'knowdesign';
|
import { Button, Divider, Drawer, Form, ProTable, Table, Utils } from 'knowdesign';
|
||||||
|
import message from '@src/components/Message';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { getHealthySettingColumn } from './config';
|
import { getHealthySettingColumn } from './config';
|
||||||
@@ -34,8 +35,8 @@ const HealthySetting = React.forwardRef((props: any, ref): JSX.Element => {
|
|||||||
item.configItem.indexOf('Group Re-Balance') > -1
|
item.configItem.indexOf('Group Re-Balance') > -1
|
||||||
? 'ReBalance'
|
? 'ReBalance'
|
||||||
: item.configItem.includes('副本未同步')
|
: item.configItem.includes('副本未同步')
|
||||||
? 'UNDER_REPLICA'
|
? 'UNDER_REPLICA'
|
||||||
: item.configItem;
|
: item.configItem;
|
||||||
|
|
||||||
values[`weight_${item.configItemName}`] = itemValue?.weight;
|
values[`weight_${item.configItemName}`] = itemValue?.weight;
|
||||||
values[`value_${item.configItemName}`] = itemValue?.value;
|
values[`value_${item.configItemName}`] = itemValue?.value;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MetricType } from '@src/api';
|
import { MetricType } from '@src/api';
|
||||||
import TopicHealthCheck from '@src/components/CardBar/TopicHealthCheck';
|
import TopicHealthCheck from '@src/components/CardBar/TopicHealthCheck';
|
||||||
import DashboardDragChart from '@src/components/DashboardDragChart';
|
import DraggableCharts from '@src/components/DraggableCharts';
|
||||||
import { AppContainer } from 'knowdesign';
|
import { AppContainer } from 'knowdesign';
|
||||||
import DBreadcrumb from 'knowdesign/es/extend/d-breadcrumb';
|
import DBreadcrumb from 'knowdesign/es/extend/d-breadcrumb';
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ const TopicDashboard = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<TopicHealthCheck />
|
<TopicHealthCheck />
|
||||||
<DashboardDragChart type={MetricType.Topic} />
|
<DraggableCharts type={MetricType.Topic} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user