Skip to content

Commit df299ed

Browse files
authored
feat: add metric detail (#263)
Signed-off-by: laixingyou <[email protected]>
1 parent 0f1322c commit df299ed

File tree

30 files changed

+5813
-105
lines changed

30 files changed

+5813
-105
lines changed

apps/web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"@types/qrcode": "^1.5.0",
3030
"ahooks": "^3.7.0",
3131
"axios": "^1.1.3",
32+
"antd": "^5.9.2",
3233
"big.js": "^6.2.1",
3334
"class-variance-authority": "^0.6.0",
3435
"classnames": "^2.3.1",
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React, { useEffect, useState, useRef } from 'react';
2+
import { Table, ConfigProvider } from 'antd';
3+
import getTableScroll from '@common/utils/getTableScroll';
4+
import getLocale from '@common/utils/getLocale';
5+
import zhCN from 'antd/locale/zh_CN';
6+
import enUS from 'antd/locale/en_US';
7+
8+
const MyTable = (props) => {
9+
const [scrollY, setScrollY] = useState<string | number>(400);
10+
let countRef = useRef(null);
11+
useEffect(() => {
12+
let scrolly = getTableScroll({ ref: countRef });
13+
if (countRef) setScrollY(scrolly);
14+
}, [countRef]);
15+
const [local, setLocale] = useState(enUS);
16+
useEffect(() => {
17+
const l = getLocale();
18+
setLocale(l === 'zh' ? zhCN : enUS);
19+
}, []);
20+
return (
21+
<div ref={countRef}>
22+
<ConfigProvider locale={local}>
23+
<Table
24+
{...props}
25+
rowClassName={(_record, i) => (i % 2 === 1 ? '!bg-[#fafafa]' : '')}
26+
bordered
27+
scroll={{ x: 'max-content', y: scrollY }}
28+
/>
29+
</ConfigProvider>
30+
</div>
31+
);
32+
};
33+
export default MyTable;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export default function getTableScroll({ extraHeight = null, ref }) {
2+
if (!extraHeight) {
3+
extraHeight = 108;
4+
}
5+
let tHeader = null;
6+
if (ref && ref.current) {
7+
tHeader = ref.current.getElementsByClassName('ant-table-thead')[0];
8+
} else {
9+
tHeader = document.getElementsByClassName('ant-table-thead')[0];
10+
}
11+
//表格内容距离顶部的距离
12+
let tHeaderBottom = 0;
13+
if (tHeader) {
14+
tHeaderBottom = tHeader.getBoundingClientRect().bottom;
15+
}
16+
// 窗体高度-表格内容顶部的高度-表格内容底部的高度
17+
// let height = document.body.clientHeight - tHeaderBottom - extraHeight
18+
console.log(tHeaderBottom);
19+
let height = `calc(100vh - ${tHeaderBottom + extraHeight}px)`;
20+
21+
return height;
22+
}

apps/web/src/modules/analyze/DataView/OverviewSummary/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import useMetricQueryData from '@modules//analyze/hooks/useMetricQueryData';
77
import { withErrorBoundary } from 'react-error-boundary';
88
import ErrorFallback from '@common/components/ErrorFallback';
99
import { Level } from '@modules/analyze/constant';
10+
import MetricDashboard from '@modules/analyze/components/MetricDetail/MetricDashboard';
1011

1112
const Overview: React.FC<{
1213
data: DeepReadonly<
@@ -18,6 +19,7 @@ const Overview: React.FC<{
1819
<>
1920
{data[0].level === Level.COMMUNITY && <CommunityRepos />}
2021
<LineChart />
22+
<MetricDashboard />
2123
</>
2224
);
2325
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from 'react';
2+
import LegacyLabelRedirect from './components/Container/LegacyLabelRedirect';
3+
import AnalyzeContainer from './components/Container/AnalyzeContainer';
4+
import { Main } from '@common/components/Layout';
5+
import MetricDetailMore from './components/MetricDetail/MetricDetailMore';
6+
import Header from '@common/components/Header';
7+
8+
const Analyze = () => {
9+
return (
10+
<LegacyLabelRedirect>
11+
<AnalyzeContainer>
12+
<Header />
13+
<Main>
14+
<MetricDetailMore />
15+
</Main>
16+
</AnalyzeContainer>
17+
</LegacyLabelRedirect>
18+
);
19+
};
20+
21+
export default Analyze;
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import React, { useRef, useEffect, useCallback } from 'react';
2+
import { useDeepCompareEffect } from 'ahooks';
3+
import { init, getInstanceByDom } from 'echarts';
4+
import type { CSSProperties } from 'react';
5+
import type { EChartsOption, ECharts, SetOptionOpts } from 'echarts';
6+
import { useResizeDetector } from 'react-resize-detector';
7+
import useInViewportDebounce from '@common/hooks/useInViewportDebounce';
8+
9+
export interface ReactEChartsProps {
10+
option: EChartsOption;
11+
style?: CSSProperties;
12+
settings?: SetOptionOpts;
13+
loading?: boolean;
14+
theme?: 'light' | 'dark';
15+
containerRef?: React.RefObject<HTMLElement>;
16+
legendselectchanged?: any;
17+
}
18+
19+
const MetricChart: React.FC<ReactEChartsProps> = ({
20+
option,
21+
style,
22+
settings = { notMerge: true },
23+
loading,
24+
theme,
25+
containerRef,
26+
legendselectchanged,
27+
}) => {
28+
const inView = useInViewportDebounce(containerRef);
29+
const chartRef = useRef<HTMLDivElement>(null);
30+
31+
useEffect(() => {
32+
// Update chart
33+
if (chartRef.current !== null) {
34+
const chart = getInstanceByDom(chartRef.current)!;
35+
if (inView) {
36+
loading === true ? chart?.showLoading() : chart?.hideLoading();
37+
}
38+
}
39+
}, [loading, inView]);
40+
41+
useEffect(() => {
42+
// init
43+
let chart: ECharts | undefined;
44+
if (chartRef.current !== null) {
45+
chart = init(chartRef.current, theme);
46+
}
47+
return () => {
48+
chart?.dispose();
49+
};
50+
}, [theme]);
51+
52+
useDeepCompareEffect(() => {
53+
// Update chart
54+
if (inView && chartRef.current !== null) {
55+
const chart = getInstanceByDom(chartRef.current)!;
56+
chart.setOption(option, settings);
57+
if (legendselectchanged) {
58+
const chart = getInstanceByDom(chartRef.current)!;
59+
chart.on('legendselectchanged', function (params: any) {
60+
let selected = params.selected!;
61+
let options = chart.getOption();
62+
let selectedList = Object.keys(selected).filter(
63+
(item) => selected[item]
64+
);
65+
options.series[1].data = legendselectchanged.filter((item) =>
66+
selectedList.includes(item.org)
67+
);
68+
this.setOption(options);
69+
});
70+
}
71+
}
72+
}, [option, settings, inView]);
73+
74+
// ----------------container resize------------------------------
75+
const onResize = useCallback((width?: number, height?: number) => {
76+
if (chartRef.current !== null) {
77+
const chart = getInstanceByDom(chartRef.current)!;
78+
chart?.resize({
79+
width: 'auto',
80+
height: Number(height) > 650 ? 650 : 350,
81+
});
82+
}
83+
}, []);
84+
85+
useResizeDetector({
86+
targetRef: containerRef,
87+
onResize,
88+
skipOnMount: true,
89+
});
90+
91+
return (
92+
<div ref={chartRef} style={{ width: '100%', height: '100%', ...style }} />
93+
);
94+
};
95+
96+
export default React.memo(MetricChart);

0 commit comments

Comments
 (0)