Skip to content

Commit be293b0

Browse files
author
yaojiping
committed
chore: remove repeated code
1 parent 825faab commit be293b0

File tree

5 files changed

+400
-1091
lines changed

5 files changed

+400
-1091
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
import request from "@/utils/request";
2+
import { cloneDeep } from "lodash";
3+
import { useEffect, useRef, useState } from "react";
4+
import { formatMessage } from "umi/locale";
5+
import styles from "./Metrics.scss";
6+
import { Empty, Icon, message, Spin, Tooltip } from "antd";
7+
import {
8+
Axis,
9+
Chart,
10+
CurveType,
11+
LineSeries,
12+
BarSeries,
13+
niceTimeFormatByDay,
14+
Position,
15+
ScaleType,
16+
Settings,
17+
timeFormatter,
18+
} from "@elastic/charts";
19+
import { formatter, getFormatter, getNumFormatter } from "@/utils/format";
20+
import { CopyToClipboard } from "react-copy-to-clipboard";
21+
import moment from "moment";
22+
import { ESPrefix } from "@/services/common";
23+
24+
export default (props) => {
25+
26+
const {
27+
timezone,
28+
timeRange,
29+
handleTimeChange,
30+
fetchUrl,
31+
metricKey,
32+
title,
33+
queryParams,
34+
className,
35+
style,
36+
formatMetric
37+
} = props;
38+
39+
const [loading, setLoading] = useState(false)
40+
41+
const [metric, setMetric] = useState()
42+
43+
const [isInView, setIsInView] = useState(false);
44+
45+
const observerRef = useRef({ isInView: false })
46+
47+
const containerRef = useRef(null)
48+
49+
const firstFetchRef = useRef(true)
50+
51+
const fetchData = async (queryParams, fetchUrl, metricKey) => {
52+
if (!observerRef.current.isInView) return;
53+
if (firstFetchRef.current) {
54+
setLoading(true)
55+
}
56+
const res = await request(fetchUrl, {
57+
method: 'GET',
58+
queryParams: {
59+
...queryParams,
60+
key: metricKey
61+
},
62+
})
63+
if (res && !res.error) {
64+
const { metrics = {} } = res || {};
65+
const metric = metrics[metricKey]
66+
setMetric(formatMetric ? formatMetric(metric) : metric);
67+
}
68+
if (firstFetchRef.current) {
69+
setLoading(false)
70+
firstFetchRef.current = false
71+
}
72+
}
73+
74+
useEffect(() => {
75+
observerRef.current.deps = cloneDeep([queryParams, fetchUrl, metricKey])
76+
fetchData(queryParams, fetchUrl, metricKey)
77+
}, [JSON.stringify(queryParams), fetchUrl, metricKey])
78+
79+
useEffect(() => {
80+
const observer = new IntersectionObserver(
81+
entries => {
82+
entries.forEach(entry => {
83+
if (entry.isIntersecting) {
84+
observerRef.current.isInView = true
85+
if (JSON.stringify(observerRef.current.deps) !== JSON.stringify(observerRef.current.lastDeps)) {
86+
observerRef.current.lastDeps = cloneDeep(observerRef.current.deps)
87+
fetchData(...observerRef.current.deps)
88+
}
89+
} else {
90+
observerRef.current.isInView = false
91+
}
92+
});
93+
},
94+
{
95+
root: null,
96+
threshold: 0,
97+
}
98+
);
99+
100+
if (containerRef.current) {
101+
observer.observe(containerRef.current);
102+
}
103+
104+
return () => {
105+
if (containerRef.current) {
106+
observer.unobserve(containerRef.current);
107+
}
108+
};
109+
}, [isInView]);
110+
111+
const chartRef = useRef();
112+
113+
const pointerUpdate = (event) => {
114+
if (chartRef.current) {
115+
chartRef.current.dispatchExternalPointerEvent(event);
116+
}
117+
};
118+
119+
const handleChartBrush = ({ x }) => {
120+
if (!x) {
121+
return;
122+
}
123+
let [from, to] = x;
124+
if (typeof handleTimeChange == "function") {
125+
if (to - from < 20 * 1000) {
126+
from -= 10 * 1000;
127+
to += 10 * 1000;
128+
}
129+
handleTimeChange({
130+
start: moment(from).toISOString(),
131+
end: moment(to).toISOString(),
132+
});
133+
}
134+
};
135+
136+
const axis = metric?.axis || [];
137+
const lines = metric?.lines || [];
138+
let disableHeaderFormat = false;
139+
const chartTitle = { title };
140+
if (metricKey == "cluster_health") {
141+
chartTitle.units = "%";
142+
} else {
143+
if (lines[0]?.metric) {
144+
if (lines[0].metric.formatType.toLowerCase == "bytes") {
145+
chartTitle.units = lines[0].metric.formatType;
146+
} else {
147+
chartTitle.units = lines[0].metric.units;
148+
}
149+
}
150+
}
151+
152+
return (
153+
<div key={metricKey} ref={containerRef} className={className} style={style}>
154+
<Spin spinning={loading}>
155+
<div className={styles.vizChartItemTitle}>
156+
<span>
157+
{chartTitle.title}
158+
{chartTitle.units ? `(${chartTitle.units})` : ""}
159+
</span>
160+
{
161+
metric?.request && (
162+
<span>
163+
<CopyToClipboard text={metric.request}>
164+
<Tooltip title={formatMessage({id: "cluster.metrics.dsl.copy"})}>
165+
<Icon
166+
className={styles.copy}
167+
type="copy"
168+
onClick={() => message.success(formatMessage({id: "cluster.metrics.dsl.copy.success"}))}
169+
/>
170+
</Tooltip>
171+
</CopyToClipboard>
172+
</span>
173+
)
174+
}
175+
</div>
176+
{
177+
lines.every((item) => !item.data || item.data.length === 0) ? (
178+
<Empty style={{ height: 200, margin: 0, paddingTop: 64 }} image={Empty.PRESENTED_IMAGE_SIMPLE} />
179+
) : (
180+
<Chart
181+
size={[, 200]}
182+
className={styles.vizChartItem}
183+
ref={chartRef}
184+
>
185+
<Settings
186+
pointerUpdateDebounce={0}
187+
pointerUpdateTrigger="x"
188+
// externalPointerEvents={{
189+
// tooltip: { visible: true },
190+
// }}
191+
onPointerUpdate={pointerUpdate}
192+
// theme={theme}
193+
showLegend
194+
legendPosition={Position.Bottom}
195+
onBrushEnd={handleChartBrush}
196+
tooltip={{
197+
headerFormatter: disableHeaderFormat
198+
? undefined
199+
: ({ value }) =>
200+
`${formatter.full_dates(value)}`,
201+
}}
202+
debug={false}
203+
/>
204+
<Axis
205+
id={`${metricKey}-bottom`}
206+
position={Position.Bottom}
207+
showOverlappingTicks
208+
labelFormat={timeRange.timeFormatter}
209+
tickFormat={timeRange.timeFormatter}
210+
/>
211+
{metricKey == "cluster_health" ? (
212+
<Axis
213+
id="cluster_health"
214+
position={Position.Left}
215+
tickFormat={(d) => Number(d).toFixed(0) + "%"}
216+
/>
217+
) : null}
218+
219+
{axis.map((item) => {
220+
return (
221+
<Axis
222+
key={metricKey + "-" + item.id}
223+
id={metricKey + "-" + item.id}
224+
showGridLines={item.showGridLines}
225+
groupId={item.group}
226+
position={item.position}
227+
ticks={item.ticks}
228+
labelFormat={getFormatter(
229+
item.formatType,
230+
item.labelFormat
231+
)}
232+
tickFormat={getFormatter(
233+
item.formatType,
234+
item.tickFormat
235+
)}
236+
/>
237+
);
238+
})}
239+
240+
{lines.map((item) => {
241+
if (item.type == "Bar") {
242+
return (
243+
<BarSeries
244+
key={item.metric.label}
245+
xScaleType={ScaleType.Time}
246+
yScaleType={ScaleType.Linear}
247+
xAccessor="x"
248+
yAccessors={["y"]}
249+
stackAccessors={["x"]}
250+
splitSeriesAccessors={["g"]}
251+
data={item.data}
252+
color={({ specId, yAccessor, splitAccessors }) => {
253+
const g = splitAccessors.get("g");
254+
if (
255+
yAccessor === "y"
256+
257+
) {
258+
if( ["red", "yellow", "green"].includes(g)){
259+
return g;
260+
}
261+
if(g == "online" || g == "available"){
262+
return "green";
263+
}
264+
if(g == "offline" || g == "unavailable" || g == "N/A"){
265+
return "gray";
266+
}
267+
268+
}
269+
return null;
270+
}}
271+
/>
272+
);
273+
}
274+
return (
275+
<LineSeries
276+
key={item.metric.label}
277+
id={item.metric.label}
278+
groupId={item.metric.group}
279+
timeZone={timezone}
280+
color={item.color}
281+
xScaleType={ScaleType.Time}
282+
yScaleType={ScaleType.Linear}
283+
xAccessor={0}
284+
tickFormat={getFormatter(
285+
item.metric.formatType,
286+
item.metric.tickFormat,
287+
item.metric.units
288+
)}
289+
yAccessors={[1]}
290+
data={item.data}
291+
curve={CurveType.CURVE_MONOTONE_X}
292+
/>
293+
);
294+
})}
295+
</Chart>
296+
)
297+
}
298+
</Spin>
299+
</div>
300+
);
301+
}

0 commit comments

Comments
 (0)