Skip to content

Commit 9a81a38

Browse files
zackyounghZzm0809Zzm0809
authored
[Optimization][metrics]fix_metrics_web_page (#3561)
Signed-off-by: Zzm0809 <[email protected]> Co-authored-by: zackyoungh <[email protected]> Co-authored-by: Zzm0809 <[email protected]> Co-authored-by: Zzm0809 <[email protected]>
1 parent 34eacc2 commit 9a81a38

File tree

25 files changed

+589
-217
lines changed

25 files changed

+589
-217
lines changed

dinky-web/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@
3636
],
3737
"dependencies": {
3838
"@andrewray/react-multi-split-pane": "^0.3.5",
39-
"@ant-design/charts": "^1.4.3",
39+
"@ant-design/charts": "^2.1.1",
4040
"@ant-design/icons": "^5.3.7",
4141
"@ant-design/pro-components": "^2.6.43",
4242
"@ant-design/pro-layout": "^7.17.16",
4343
"@ant-design/pro-table": "^3.13.11",
4444
"@ant-design/use-emotion-css": "^1.0.4",
45+
"@antv/layout": "^0.3.25",
4546
"@antv/x6": "^2.15.6",
4647
"@antv/x6-plugin-selection": "^2.2.1",
4748
"@antv/x6-react-shape": "^2.2.2",
@@ -65,9 +66,11 @@
6566
"react-countup": "^6.5.0",
6667
"react-dom": "^18.0.0",
6768
"react-helmet-async": "^2.0.1",
69+
"react-infinite-scroll-component": "^6.1.0",
6870
"react-lineage-dag": "^2.0.36",
6971
"react-markdown": "^9.0.1",
7072
"react-spring": "^9.7.3",
73+
"react-fast-marquee": "^1.6.4",
7174
"react-use-cookie": "^1.4.0",
7275
"redux-persist": "^6.0.0",
7376
"remark-gfm": "^4.0.0",
@@ -82,6 +85,7 @@
8285
"@types/classnames": "^2.3.1",
8386
"@types/express": "^4.17.21",
8487
"@types/history": "^5.0.0",
88+
"@types/js-cookie": "^3.0.6",
8589
"@types/lodash": "^4.14.199",
8690
"@types/react": "^18.2.39",
8791
"@types/react-dom": "^18.2.17",
@@ -95,6 +99,7 @@
9599
"lint-staged": "^13",
96100
"prettier": "^2",
97101
"react-dev-inspector": "^2.0.0",
102+
"react-fast-marquee": "^1.6.4",
98103
"react-inspector": "^6.0.2",
99104
"sql-formatter": "^13.0.1",
100105
"swagger-ui-dist": "^5.10.3",

dinky-web/src/components/Flink/FlinkChart/index.tsx

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@
1818
*/
1919

2020
import { ChartData } from '@/pages/Metrics/JobMetricsList/data';
21-
import { differenceDays } from '@/utils/function';
22-
import { Line } from '@ant-design/charts';
21+
import { THEME } from '@/types/Public/data';
22+
import { differenceDays, getChartThemeColor } from '@/utils/function';
23+
import { Line, LineConfig } from '@ant-design/charts';
2324
import { ExpandOutlined } from '@ant-design/icons';
2425
import { ProCard, StatisticCard } from '@ant-design/pro-components';
2526
import { Col, Modal, Radio, Segmented, Space } from 'antd';
2627
import Paragraph from 'antd/es/typography/Paragraph';
27-
import { useState } from 'react';
28+
import { useEffect, useState } from 'react';
2829

2930
type FlinkChartProps = {
3031
title: string;
@@ -51,6 +52,7 @@ const FlinkChart = (props: FlinkChartProps) => {
5152
titleWidth: '60%'
5253
});
5354

55+
const [themeColor, setThemeColor] = useState<string>(THEME.CHART_THEME_LIGHT);
5456
const [showExtra, setShowExtra] = useState<boolean>(false);
5557

5658
const getLineTimeMask = (charData: ChartData[]) => {
@@ -69,16 +71,23 @@ const FlinkChart = (props: FlinkChartProps) => {
6971
}
7072
};
7173

72-
const config = {
73-
animation: false,
74+
useEffect(() => {
75+
setThemeColor(getChartThemeColor());
76+
}, [getChartThemeColor()]);
77+
78+
const config: LineConfig = {
79+
animation: true,
80+
autoFit: true,
7481
data: data,
7582
smooth: true,
76-
xField: 'time',
83+
theme: themeColor,
7784
yField: 'value',
78-
xAxis: {
79-
type: 'time',
80-
mask: getLineTimeMask(data),
81-
tickCount: 40
85+
xField: (d: ChartData) => new Date(d.time),
86+
axis: {
87+
x: {
88+
tickCount: 10,
89+
mask: getLineTimeMask(data)
90+
}
8291
},
8392
...chartOptions
8493
};
@@ -163,7 +172,8 @@ const FlinkChart = (props: FlinkChartProps) => {
163172
) : (
164173
<StatisticCard.Group
165174
style={{
166-
minHeight: '100%',
175+
marginTop: '5%',
176+
minHeight: '95%',
167177
minWidth: '100%',
168178
display: 'flex',
169179
justifyContent: 'center',
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
*
3+
* Licensed to the Apache Software Foundation (ASF) under one or more
4+
* contributor license agreements. See the NOTICE file distributed with
5+
* this work for additional information regarding copyright ownership.
6+
* The ASF licenses this file to You under the Apache License, Version 2.0
7+
* (the "License"); you may not use this file except in compliance with
8+
* the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
*/
19+
20+
import { Pagination, Row } from 'antd';
21+
import React, { useEffect, useState } from 'react';
22+
23+
type ListPaginationProps<T, F> = {
24+
data: T[];
25+
defaultPageSize: number;
26+
layout: (data: T[]) => React.ReactNode;
27+
filter?: FilterProp<T, F>;
28+
};
29+
30+
type FilterProp<T, F> = {
31+
content: (data: T[], setFilter: React.Dispatch<F>) => React.ReactNode;
32+
filter: (data: T, filter: F) => boolean;
33+
};
34+
35+
const ListPagination = <T, F>(props: ListPaginationProps<T, F>) => {
36+
const [data, setData] = useState<T[]>(props.data);
37+
const [currentData, setCurrentData] = useState<T[]>([]);
38+
const [currentPage, setCurrentPage] = useState<number>(1);
39+
const [currentPageSize, setCurrentPageSize] = useState<number>(props.defaultPageSize);
40+
const [filter, setFilter] = useState<F>({} as F);
41+
42+
useEffect(() => {
43+
const newData = props.data.filter((item) => {
44+
if (props.filter) {
45+
return props.filter.filter(item, filter);
46+
}
47+
return true;
48+
});
49+
setCurrentData(
50+
newData.slice((currentPage - 1) * currentPageSize, currentPage * currentPageSize)
51+
);
52+
setData(newData);
53+
}, [currentPage, currentPageSize, filter, data]);
54+
55+
return (
56+
<>
57+
{props.filter && props.filter.content(props.data, setFilter)}
58+
<Row gutter={[8, 16]}>{props.layout(currentData)}</Row>
59+
<Pagination
60+
style={{ textAlign: 'center', marginTop: '16px' }}
61+
showTitle
62+
total={data.length}
63+
hideOnSinglePage
64+
showTotal={(total, range) => `${range[0]}-${range[1]} of ${total} Items`}
65+
defaultPageSize={props.defaultPageSize}
66+
responsive
67+
showLessItems
68+
defaultCurrent={currentPage}
69+
onChange={(page, pageSize) => {
70+
setCurrentPage(page);
71+
setCurrentPageSize(pageSize);
72+
}}
73+
/>
74+
</>
75+
);
76+
};
77+
78+
export default ListPagination;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import {Alert, Result} from "antd";
2+
import Marquee from "react-fast-marquee";
3+
import React from "react";
4+
5+
6+
interface MetricsProps {
7+
tips: string | React.ReactNode
8+
type: 'success' | 'info' | 'warning' | 'error';
9+
showIcon?: boolean;
10+
banner?: boolean;
11+
play?: boolean;
12+
}
13+
14+
15+
/**
16+
* The scrolling message prompt component is only used for long text, but its width may exceed the width of the container, so scrolling display is required
17+
* @param props
18+
*/
19+
export default (props: MetricsProps) => {
20+
21+
const {tips, type, banner = false, showIcon = true, play = true} = props;
22+
23+
const renderMarquee = () => {
24+
return <>
25+
<Marquee style={{alignContent: 'center'}} play={play} speed={50} gradient={false} gradientWidth={0}>
26+
{tips}
27+
</Marquee>
28+
</>
29+
}
30+
31+
32+
return <><Alert style={{width: '50vw'}} message={renderMarquee()} type={type} banner={banner} showIcon={showIcon}/></>
33+
};

dinky-web/src/locales/en-US/pages.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ export default {
203203
'devops.jobinfo.job.keyConfirm': '{key} this Job?',
204204
'devops.jobinfo.metrics.configMetrics': 'Metrics Config',
205205
'devops.jobinfo.metrics.metricsItems': 'Metrics Items',
206+
'devops.jobinfo.metrics.vertices': 'Vertices',
207+
'devops.jobinfo.metrics.name': 'Metrics Name',
206208
'devops.jobinfo.metrics.selected': 'Selected',
207209
'devops.jobinfo.offline': 'Offline',
208210
'devops.jobinfo.recently.job.status': 'View recently saved job status information',
@@ -359,7 +361,7 @@ export default {
359361
'metrics.flink.subTask.placeholder': 'Please select a SubTask Name',
360362
'metrics.flink.taskId': 'Dinky Job ID',
361363
'metrics.dinky.not.open':
362-
'Dinky Server monitoring is not enabled, please go to the Setting Center -> Global Settings -> Metrics Configuration -> Dinky JVM Monitor switch to open',
364+
'The monitoring function is not enabled, and the Dinky Server and Flink task monitoring functions cannot be used. \nPlease go to the Configuration Center -> Global Configuration -> Metrics Configuration -> Dinky JVM Monitor switch to enable it',
363365
'metrics.flink.deleteConfirm':
364366
'Are you sure to delete the monitoring data under this task? \nAttention: This operation will synchronously affect the monitoring data of the operation and maintenance center for this task!! \nPlease operate with caution, this operation is irreversible!',
365367

dinky-web/src/locales/zh-CN/pages.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ export default {
194194
'devops.jobinfo.job.keyConfirm': '确定 {key} 该作业吗?',
195195
'devops.jobinfo.metrics.configMetrics': '任务监控配置',
196196
'devops.jobinfo.metrics.metricsItems': '监控项列表',
197+
'devops.jobinfo.metrics.vertices': '顶点',
198+
'devops.jobinfo.metrics.name': '监控项名称',
197199
'devops.jobinfo.metrics.selected': '已选择',
198200
'devops.jobinfo.offline': '下线',
199201
'devops.jobinfo.recently.job.status': '查看最近保存的作业状态信息',
@@ -346,7 +348,7 @@ export default {
346348
'metrics.flink.subTask.placeholder': '请选择子任务名称',
347349
'metrics.flink.taskId': 'Dinky 任务ID',
348350
'metrics.dinky.not.open':
349-
'暂未开启 Dinky Server 监控, 请前往 配置中心 -> 全局配置 -> Metrics 配置 -> Dinky JVM Monitor 开关 进行开启',
351+
'未开启监控功能,Dinky Server 和 Flink 任务监控功能无法使用. \n请前往 配置中心 -> 全局配置 -> Metrics 配置 -> Dinky JVM Monitor 开关 进行开启',
350352
'metrics.flink.deleteConfirm':
351353
'确认删除该任务下的监控数据吗? \n注意:该操作会同步影响运维中心该任务的监控数据!!\n请谨慎操作,该操作不可撤消!',
352354
/**

dinky-web/src/pages/DataStudio/FooterContainer/index.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,16 @@ const FooterContainer: React.FC<FooterContainerProps & StateType> = (props) => {
6262
useEffect(() => {
6363
const eventSource = getSseData(API_CONSTANTS.BASE_URL + API_CONSTANTS.GET_JVM_INFO);
6464
eventSource.onmessage = (event) => {
65-
const data = JSON.parse(event.data).data;
66-
setMemDetailInfo(
67-
Number(data['heapUsed'] / 1024 / 1024).toFixed(0) +
68-
'/' +
69-
Number(data['max'] / 1024 / 1024).toFixed(0) +
70-
'M'
71-
);
65+
const respData = JSON.parse(event.data);
66+
const data = respData.data;
67+
if (respData['topic'] != 'HEART_BEAT') {
68+
setMemDetailInfo(
69+
Number(data['heapUsed'] / 1024 / 1024).toFixed(0) +
70+
'/' +
71+
Number(data['max'] / 1024 / 1024).toFixed(0) +
72+
'M'
73+
);
74+
}
7275
};
7376
return () => {
7477
eventSource.close();

dinky-web/src/pages/DevOps/JobDetail/JobMetrics/JobChart/JobChart.tsx

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,19 @@
1818
*/
1919

2020
import FlinkChart from '@/components/Flink/FlinkChart';
21+
import ListPagination from '@/components/Flink/ListPagination';
2122
import useHookRequest from '@/hooks/useHookRequest';
2223
import { SseData } from '@/models/Sse';
2324
import { SSE_TOPIC } from '@/pages/DevOps/constants';
2425
import { JobMetricsItem, MetricsTimeFilter } from '@/pages/DevOps/JobDetail/data';
25-
import { getMetricsData } from '@/pages/DevOps/JobDetail/srvice';
26+
import { getMetricsData } from '@/pages/DevOps/JobDetail/service';
27+
import { Filter, isBlank } from '@/pages/Metrics/JobMetricsList';
2628
import { ChartData } from '@/pages/Metrics/JobMetricsList/data';
2729
import { MetricsDataType } from '@/pages/Metrics/Server/data';
2830
import { Jobs } from '@/types/DevOps/data';
29-
import { Empty, Row, Spin } from 'antd';
31+
import { l } from '@/utils/intl';
32+
import { ProFormSelect, ProFormText, QueryFilter } from '@ant-design/pro-components';
33+
import { Empty, Spin } from 'antd';
3034
import { useEffect, useState } from 'react';
3135
import { useModel } from 'umi';
3236

@@ -44,7 +48,7 @@ const JobChart = (props: JobChartProps) => {
4448
subscribeTopic: model.subscribeTopic
4549
}));
4650

47-
const { loading } = useHookRequest(getMetricsData, {
51+
const { loading, refresh: refreshMetricsData } = useHookRequest(getMetricsData, {
4852
defaultParams: [timeRange, jobDetail.instance.jid],
4953
refreshDeps: [timeRange, metricsList],
5054
onSuccess: (result) => {
@@ -102,7 +106,62 @@ const JobChart = (props: JobChartProps) => {
102106
};
103107
return (
104108
<Spin spinning={loading} delay={500}>
105-
<Row gutter={[8, 16]}>{renderMetricsCardList(metricsList ?? {}, chartDatas)}</Row>
109+
{metricsList && (
110+
<ListPagination<JobMetricsItem, Filter>
111+
data={metricsList}
112+
layout={(data) => renderMetricsCardList(data, chartDatas)}
113+
defaultPageSize={12}
114+
filter={{
115+
content: (data: JobMetricsItem[], setFilter) => {
116+
return (
117+
<QueryFilter<Filter>
118+
labelWidth={'auto'}
119+
span={8}
120+
defaultCollapsed
121+
split
122+
onFinish={async (values) => setFilter(values)}
123+
onReset={async () => {
124+
// 清空筛选条件
125+
setFilter({
126+
vertices: '',
127+
metrics: ''
128+
});
129+
await refreshMetricsData();
130+
}}
131+
>
132+
<ProFormSelect
133+
name='vertices'
134+
colProps={{ md: 12, xl: 8 }}
135+
label={l('devops.jobinfo.metrics.vertices')}
136+
valueEnum={[...new Set(data.map((item) => item.vertices))].reduce(
137+
(accumulator, item) => {
138+
accumulator[item] = item;
139+
return accumulator;
140+
},
141+
{} as Record<string, string>
142+
)}
143+
/>
144+
<ProFormText
145+
colProps={{ md: 12, xl: 8 }}
146+
name='metrics'
147+
label={l('devops.jobinfo.metrics.name')}
148+
/>
149+
</QueryFilter>
150+
);
151+
},
152+
filter: (item: JobMetricsItem, filter: Filter) => {
153+
let rule = true;
154+
if (!isBlank(filter.vertices)) {
155+
rule = rule && item.vertices.includes(filter.vertices);
156+
}
157+
if (!isBlank(filter.metrics)) {
158+
rule = rule && item.metrics.includes(filter.metrics);
159+
}
160+
return rule;
161+
}
162+
}}
163+
/>
164+
)}
106165
</Spin>
107166
);
108167
};

dinky-web/src/pages/DevOps/JobDetail/JobMetrics/MetricsForm/MetricsConfigTab.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import useHookRequest from '@/hooks/useHookRequest';
2121
import { JobMetricsItem } from '@/pages/DevOps/JobDetail/data';
22-
import { getFLinkVertices } from '@/pages/DevOps/JobDetail/srvice';
22+
import { getFLinkVertices } from '@/pages/DevOps/JobDetail/service';
2323
import { Jobs } from '@/types/DevOps/data';
2424
import { l } from '@/utils/intl';
2525
import { Transfer } from 'antd';

0 commit comments

Comments
 (0)