Added a fancy crosshair and did some refactoring

This commit is contained in:
Yuqiu Wang
2021-03-19 13:03:52 -04:00
parent 2f2fa0fa2f
commit dfa00caf92
4 changed files with 130 additions and 74 deletions
+1 -1
View File
@@ -64,7 +64,7 @@ export default class Menu extends Base<MenuProps, MenuStates> {
)}
{canView(rules, api.namespace) && (
<MenuItem title='PrometheusGraph' path='prometheusgraph' resource='Node' onClick={onClick} />
<MenuItem title='PrometheusGraphs' path='prometheusgraphs' resource='Node' onClick={onClick} />
)}
</Group>
+2 -2
View File
@@ -26,7 +26,7 @@ import PersistentVolumeClaims from './views/persistentVolumeClaims';
import PersistentVolumes from './views/persistentVolumes';
import Pod from './views/pod';
import Pods from './views/pods';
import PrometheusGraph from './views/prometheusgraph';
import PrometheusGraphs from './views/prometheusgraphs';
import ReplicaSet from './views/replicaSet';
import ReplicaSets from './views/replicaSets';
import Role from './views/role';
@@ -110,7 +110,7 @@ registerRoute('storageclass', () => <StorageClasses />);
registerRoute('storageclass/:name', params => <StorageClass {...params} />);
registerRoute('workload', () => <Workloads />);
registerRoute('prometheusgraph', () => <PrometheusGraph />);
registerRoute('prometheusgraphs', () => <PrometheusGraphs />);
// @ts-ignore
registerRoute('workload/cronjob/:namespace/:name', params => <CronJob {...params} />);
// @ts-ignore
+86 -71
View File
@@ -1,96 +1,111 @@
import React from 'react';
import {XYPlot, XAxis, YAxis, HorizontalGridLines, LineSeries} from 'react-vis';
import {XYPlot, XAxis, YAxis, HorizontalGridLines, LineSeries, Crosshair} from 'react-vis';
import Base from '../components/base';
const BASE_HTTP_URL = 'http://localhost:4654/prom';
const GRAPH_QUERIES = [
['instance:node_cpu:ratio', 'Node CPU Usage'],
['instance:node_memory_utilisation:ratio', 'Node Memory Usage'],
];
type Props = {
queryString: string;
title: string;
}
type State = {
metric: string;
data: Map<string, Array<Array<any>>>;
data: Array<any>;
crosshairValues: any[];
}
export default class PrometheusGraph extends Base<Props, State> {
/**
* Event handler for onMouseLeave.
* @private
*/
onMouseLeave = () => {
this.setState({crosshairValues: []});
};
/**
* Event handler for onNearestX.
* @param {Object} value Selected value.
* @param {index} index Index of the value in the data array.
* @private
*/
onNearestX = (value: any, {index} : any) => {
this.setState((prevState => ({
...prevState,
crosshairValues: [value],
})));
};
componentDidMount() {
// TODO: use proxy if ready
const url = `${BASE_HTTP_URL}/api/v1/query_range`;
this.setState((prevState => ({
...prevState,
data: new Map(),
data: new Array<any>(),
crosshairValues: [],
})));
for (let i = 0; i < GRAPH_QUERIES.length; i++) {
const query = GRAPH_QUERIES[i][0];
const params = {
query,
start: (Date.now() / 1000 - 60 * 60).toString(),
end: (Date.now() / 1000).toString(), // One hour range
step: '1',
};
fetch(`${url}?${new URLSearchParams(params).toString()}`)
.then(result => result.json())
.then((json) => {
const jsonData = json.data;
const graphData : Array<Array<any>> = jsonData.result[0]?.values.map((value: any) => ({x: value[0], y: +value[1]}));
this.state.data.set(query, graphData);
this.setState(prevState => ({
...prevState,
}));
});
}
const params = {
query: this.props.queryString,
start: (Date.now() / 1000 - 60 * 60).toString(),
end: (Date.now() / 1000).toString(), // One hour range
step: '1',
};
fetch(`${url}?${new URLSearchParams(params).toString()}`)
.then(result => result.json())
.then((json) => {
const jsonData = json.data;
const graphData : Array<any> = jsonData.result[0]?.values.map((value: any) => ({x: value[0], y: +value[1]}));
this.setState(prevState => ({
...prevState,
data: graphData,
}));
});
}
render() {
return <div>
{this.state?.data && GRAPH_QUERIES.map((value) => {
const query = value[0];
const title = value[1];
if (!this.state.data.get(query)) {
return <div>
<span style={{fontWeight: 'bold'}}>{title}</span>
<div>Pending...</div>
</div>;
}
return this.state.data.get(query)
&& <div>
<div style={{fontWeight: 'bold'}}>{title}</div>
<XYPlot
yPadding={60}
width={600}
height={600}
xType="time">
<HorizontalGridLines />
<LineSeries
data={this.state.data.get(query)}
color={'#6822aa'}
/>
<XAxis
tickFormat={function tickFormat(d) {
const date = new Date(d * 1000);
return date.toLocaleTimeString();
}}
tickLabelAngle={30}
tickTotal={5}
/>
<YAxis
tickFormat={function tickFormet(d) {
return `${(d * 100).toFixed(2)}%`;
}}
tickLabelAngle={30}
tickPadding={-5}
/>
</XYPlot>
</div>;
})}
</div>;
if (!this.state || !this.state.data) {
return <div>
<span style={{fontWeight: 'bold'}}>{this.props.title}</span>
<div>Pending...</div>
</div>;
}
return this.state.data
&& <div>
<div style={{fontWeight: 'bold'}}>{this.props.title}</div>
<XYPlot
yPadding={60}
width={600}
height={600}
xType="time"
onMouseLeave={this.onMouseLeave}>
<HorizontalGridLines />
<LineSeries
data={this.state.data}
color={'#6822aa'}
onNearestX={this.onNearestX}
/>
<Crosshair
values={this.state.crosshairValues}
className={'test-class-name'}
/>
<XAxis
tickFormat={function tickFormat(d) {
const date = new Date(d * 1000);
return date.toLocaleTimeString();
}}
tickLabelAngle={30}
tickTotal={5}
/>
<YAxis
tickFormat={function tickFormet(d) {
return `${(d * 100).toFixed(2)}%`;
}}
tickLabelAngle={30}
tickPadding={-5}
/>
</XYPlot>
</div>;
}
}
+41
View File
@@ -0,0 +1,41 @@
import React from 'react';
import PrometheusGraph from './prometheusgraph';
import Base from '../components/base';
type Props = {
}
type State = {
metric: string;
data: Map<string, Array<Array<any>>>;
crosshairValues: [];
}
export default class PrometheusGraphs extends Base<Props, State> {
// GRAPH_QUERIES = [
// ['instance:node_cpu:ratio', 'Node CPU Usage'],
// ['instance:node_memory_utilisation:ratio', 'Node Memory Usage'],
// ];
GRAPH_QUERIES = [
{
queryString: 'instance:node_cpu:ratio',
title: 'Node CPU Usage',
},
{
queryString: 'instance:node_memory_utilisation:ratio',
title: 'Node Memory Usage',
},
]
render() {
return <div>
{/* eslint-disable-next-line react/jsx-key */}
{this.GRAPH_QUERIES.map(query => <PrometheusGraph
queryString={query.queryString}
title={query.title}
/>)}
</div>;
}
}