mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Convert Graph to TS
Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
parent
461b022a77
commit
d9c6bb299e
36
package-lock.json
generated
36
package-lock.json
generated
|
@ -925,6 +925,15 @@
|
||||||
"loader-utils": "^1.1.0"
|
"loader-utils": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/flot": {
|
||||||
|
"version": "0.0.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/flot/-/flot-0.0.31.tgz",
|
||||||
|
"integrity": "sha512-X+RcMQCqPlQo8zPT6cUFTd/PoYBShMQlHUeOXf05jWlfYnvLuRmluB9z+2EsOKFgUzqzZve5brx+gnFxBaHEUw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/jquery": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/jest": {
|
"@types/jest": {
|
||||||
"version": "24.0.4",
|
"version": "24.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.4.tgz",
|
||||||
|
@ -5375,6 +5384,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz",
|
||||||
"integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I="
|
"integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I="
|
||||||
},
|
},
|
||||||
|
"flot": {
|
||||||
|
"version": "2.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/flot/-/flot-2.1.6.tgz",
|
||||||
|
"integrity": "sha512-W82uI2eoYCOTcFuRX71kYTde1k8BZO/l0ueLcFELCPuB3Vl0GvXMsDCiAeAHhc53pPsNp1GJ5ckwcM7yn+AsZQ=="
|
||||||
|
},
|
||||||
"flush-write-stream": {
|
"flush-write-stream": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz",
|
||||||
|
@ -8549,6 +8563,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
|
||||||
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
|
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
|
||||||
},
|
},
|
||||||
|
"jquery.flot.tooltip": {
|
||||||
|
"version": "0.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jquery.flot.tooltip/-/jquery.flot.tooltip-0.9.0.tgz",
|
||||||
|
"integrity": "sha1-rha/lLJsLtmrTbFnu6Ut/bYVwd8="
|
||||||
|
},
|
||||||
"js-levenshtein": {
|
"js-levenshtein": {
|
||||||
"version": "1.1.6",
|
"version": "1.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
|
||||||
|
@ -16931,23 +16950,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-5.1.2.tgz",
|
||||||
"integrity": "sha512-7kEBKwU9R8fKnZJBRa5RSIfay4KJwnYvKB6gODGicUmDSAhQJ7Tdnll5S0RLtYrzRfMVXlqYw61rzrSpP4ThLQ=="
|
"integrity": "sha512-7kEBKwU9R8fKnZJBRa5RSIfay4KJwnYvKB6gODGicUmDSAhQJ7Tdnll5S0RLtYrzRfMVXlqYw61rzrSpP4ThLQ=="
|
||||||
},
|
},
|
||||||
"react-flot": {
|
|
||||||
"version": "1.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-flot/-/react-flot-1.3.0.tgz",
|
|
||||||
"integrity": "sha1-Q9LeNvY5RZnS/vt+jWsD1MViDno=",
|
|
||||||
"requires": {
|
|
||||||
"@types/react": "^15.0.38",
|
|
||||||
"deep-equal": "^1.0.1",
|
|
||||||
"jquery": "^3.1.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@types/react": {
|
|
||||||
"version": "15.6.21",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-15.6.21.tgz",
|
|
||||||
"integrity": "sha512-XpKrM3ohs7pPOWpwPnaAoxbXMI5REcBTZm/c+WTLpfaAoDf99pnQAkTkg6DyPpnkmBbykhowaBd0sHP0+K7n0g=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.8.1",
|
"version": "16.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.1.tgz",
|
||||||
|
|
|
@ -13,16 +13,17 @@
|
||||||
"@types/react-dom": "^16.8.0",
|
"@types/react-dom": "^16.8.0",
|
||||||
"bootstrap": "^4.2.1",
|
"bootstrap": "^4.2.1",
|
||||||
"downshift": "^3.2.2",
|
"downshift": "^3.2.2",
|
||||||
|
"flot": "^2.1.6",
|
||||||
"fuzzy": "^0.1.3",
|
"fuzzy": "^0.1.3",
|
||||||
"i": "^0.3.6",
|
"i": "^0.3.6",
|
||||||
"jquery": "^3.3.1",
|
"jquery": "^3.3.1",
|
||||||
|
"jquery.flot.tooltip": "^0.9.0",
|
||||||
"jsdom": "^9.6.0",
|
"jsdom": "^9.6.0",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"moment-timezone": "^0.5.23",
|
"moment-timezone": "^0.5.23",
|
||||||
"npm": "^6.7.0",
|
"npm": "^6.7.0",
|
||||||
"react": "^16.7.0",
|
"react": "^16.7.0",
|
||||||
"react-dom": "^16.7.0",
|
"react-dom": "^16.7.0",
|
||||||
"react-flot": "^1.3.0",
|
|
||||||
"react-scripts": "2.1.3",
|
"react-scripts": "2.1.3",
|
||||||
"reactstrap": "^7.1.0",
|
"reactstrap": "^7.1.0",
|
||||||
"tempusdominus-bootstrap-4": "^5.1.2",
|
"tempusdominus-bootstrap-4": "^5.1.2",
|
||||||
|
@ -45,6 +46,7 @@
|
||||||
"not op_mini all"
|
"not op_mini all"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/flot": "0.0.31",
|
||||||
"@types/moment-timezone": "^0.5.10",
|
"@types/moment-timezone": "^0.5.10",
|
||||||
"@types/reactstrap": "^7.1.3"
|
"@types/reactstrap": "^7.1.3"
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,12 @@ div.endtime-input {
|
||||||
margin: 0 5px 0 5px;
|
margin: 0 5px 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graph .flot-overlay {
|
.graph-chart {
|
||||||
|
height: 500px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-chart .flot-overlay {
|
||||||
cursor: crosshair;
|
cursor: crosshair;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
|
import $ from 'jquery';
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
|
|
||||||
import { Alert } from 'reactstrap';
|
import { Alert } from 'reactstrap';
|
||||||
|
|
||||||
import ReactFlot from 'react-flot';
|
require('flot');
|
||||||
import '../node_modules/react-flot/flot/jquery.flot.time.min';
|
require('flot/source/jquery.flot.crosshair');
|
||||||
import '../node_modules/react-flot/flot/jquery.flot.crosshair.min';
|
require('flot/source/jquery.flot.legend');
|
||||||
import '../node_modules/react-flot/flot/jquery.flot.tooltip.min';
|
require('flot/source/jquery.flot.time');
|
||||||
import '../node_modules/react-flot/flot/jquery.flot.stack.min';
|
require('flot/source/jquery.flot.hover');
|
||||||
|
require('jquery.flot.tooltip');
|
||||||
|
|
||||||
import metricToSeriesName from './MetricFomat';
|
import metricToSeriesName from './MetricFomat';
|
||||||
|
|
||||||
|
@ -16,17 +18,23 @@ function getGraphID() {
|
||||||
return graphID++;
|
return graphID++;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Graph extends PureComponent {
|
interface GraphProps {
|
||||||
constructor(props) {
|
data: any; // TODO: Type this.
|
||||||
super(props);
|
stacked: boolean;
|
||||||
this.state = {
|
queryParams: {
|
||||||
legendRef: null,
|
startTime: number,
|
||||||
};
|
endTime: number,
|
||||||
this.id = getGraphID();
|
resolution: number,
|
||||||
}
|
} | null;
|
||||||
|
}
|
||||||
|
|
||||||
escapeHTML(string) {
|
class Graph extends PureComponent<GraphProps> {
|
||||||
var entityMap = {
|
private id: number = getGraphID();
|
||||||
|
private chartRef = React.createRef<HTMLDivElement>();
|
||||||
|
private legendRef = React.createRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
escapeHTML(str: string) {
|
||||||
|
var entityMap: {[key: string]: string} = {
|
||||||
'&': '&',
|
'&': '&',
|
||||||
'<': '<',
|
'<': '<',
|
||||||
'>': '>',
|
'>': '>',
|
||||||
|
@ -35,42 +43,22 @@ class Graph extends PureComponent {
|
||||||
'/': '/'
|
'/': '/'
|
||||||
};
|
};
|
||||||
|
|
||||||
return String(string).replace(/[&<>"'/]/g, function (s) {
|
return String(str).replace(/[&<>"'/]/g, function (s) {
|
||||||
return entityMap[s];
|
return entityMap[s];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLabels(labels) {
|
renderLabels(labels: {[key: string]: string}) {
|
||||||
let labelStrings = [];
|
let labelStrings: string[] = [];
|
||||||
for (let label in labels) {
|
for (let label in labels) {
|
||||||
if (label !== '__name__') {
|
if (label !== '__name__') {
|
||||||
labelStrings.push('<strong>' + label + '</strong>: ' + this.escapeHTML(labels[label]));
|
labelStrings.push('<strong>' + label + '</strong>: ' + this.escapeHTML(labels[label]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return labels = '<div class="labels">' + labelStrings.join('<br>') + '</div>';
|
return '<div class="labels">' + labelStrings.join('<br>') + '</div>';
|
||||||
};
|
};
|
||||||
|
|
||||||
// axisUnits = [
|
formatValue = (y: number): string => {
|
||||||
// {unit: 'Y', factor: 1e24},
|
|
||||||
// {unit: 'Z', factor: 1e21},
|
|
||||||
// {unit: 'E', factor: 1e18},
|
|
||||||
// {unit: 'P', factor: 1e15},
|
|
||||||
// {unit: 'T', factor: 1e12},
|
|
||||||
// {unit: 'G', factor: 1e9},
|
|
||||||
// {unit: 'M', factor: 1e6},
|
|
||||||
// {unit: 'K', factor: 1e3},
|
|
||||||
// {unit: null,factor: 1},
|
|
||||||
// {unit: 'm', factor: 1e-3},
|
|
||||||
// {unit: 'µ', factor: 1e-6},
|
|
||||||
// {unit: 'n', factor: 1e-9},
|
|
||||||
// {unit: 'p', factor: 1e-12},
|
|
||||||
// {unit: 'f', factor: 1e-15},
|
|
||||||
// {unit: 'a', factor: 1e-18},
|
|
||||||
// {unit: 'z', factor: 1e-21},
|
|
||||||
// {unit: 'y', factor: 1e-24},
|
|
||||||
// ]
|
|
||||||
|
|
||||||
formatValue = (y) => {
|
|
||||||
var abs_y = Math.abs(y);
|
var abs_y = Math.abs(y);
|
||||||
if (abs_y >= 1e24) {
|
if (abs_y >= 1e24) {
|
||||||
return (y / 1e24).toFixed(2) + "Y";
|
return (y / 1e24).toFixed(2) + "Y";
|
||||||
|
@ -111,68 +99,11 @@ class Graph extends PureComponent {
|
||||||
} else if (abs_y <= 1) {
|
} else if (abs_y <= 1) {
|
||||||
return y.toFixed(2)
|
return y.toFixed(2)
|
||||||
}
|
}
|
||||||
|
throw Error("couldn't format a value, this is a bug");
|
||||||
}
|
}
|
||||||
|
|
||||||
getOptions() {
|
getOptions(): any {
|
||||||
return {
|
return {
|
||||||
// colors: [
|
|
||||||
// '#7EB26D', // 0: pale green
|
|
||||||
// '#EAB839', // 1: mustard
|
|
||||||
// '#6ED0E0', // 2: light blue
|
|
||||||
// '#EF843C', // 3: orange
|
|
||||||
// '#E24D42', // 4: red
|
|
||||||
// '#1F78C1', // 5: ocean
|
|
||||||
// '#BA43A9', // 6: purple
|
|
||||||
// '#705DA0', // 7: violet
|
|
||||||
// '#508642', // 8: dark green
|
|
||||||
// '#CCA300', // 9: dark sand
|
|
||||||
// '#447EBC',
|
|
||||||
// '#C15C17',
|
|
||||||
// '#890F02',
|
|
||||||
// '#0A437C',
|
|
||||||
// '#6D1F62',
|
|
||||||
// '#584477',
|
|
||||||
// '#B7DBAB',
|
|
||||||
// '#F4D598',
|
|
||||||
// '#70DBED',
|
|
||||||
// '#F9BA8F',
|
|
||||||
// '#F29191',
|
|
||||||
// '#82B5D8',
|
|
||||||
// '#E5A8E2',
|
|
||||||
// '#AEA2E0',
|
|
||||||
// '#629E51',
|
|
||||||
// '#E5AC0E',
|
|
||||||
// '#64B0C8',
|
|
||||||
// '#E0752D',
|
|
||||||
// '#BF1B00',
|
|
||||||
// '#0A50A1',
|
|
||||||
// '#962D82',
|
|
||||||
// '#614D93',
|
|
||||||
// '#9AC48A',
|
|
||||||
// '#F2C96D',
|
|
||||||
// '#65C5DB',
|
|
||||||
// '#F9934E',
|
|
||||||
// '#EA6460',
|
|
||||||
// '#5195CE',
|
|
||||||
// '#D683CE',
|
|
||||||
// '#806EB7',
|
|
||||||
// '#3F6833',
|
|
||||||
// '#967302',
|
|
||||||
// '#2F575E',
|
|
||||||
// '#99440A',
|
|
||||||
// '#58140C',
|
|
||||||
// '#052B51',
|
|
||||||
// '#511749',
|
|
||||||
// '#3F2B5B',
|
|
||||||
// '#E0F9D7',
|
|
||||||
// '#FCEACA',
|
|
||||||
// '#CFFAFF',
|
|
||||||
// '#F9E2D2',
|
|
||||||
// '#FCE2DE',
|
|
||||||
// '#BADFF4',
|
|
||||||
// '#F9D9F9',
|
|
||||||
// '#DEDAF7',
|
|
||||||
// ],
|
|
||||||
grid: {
|
grid: {
|
||||||
hoverable: true,
|
hoverable: true,
|
||||||
clickable: true,
|
clickable: true,
|
||||||
|
@ -180,15 +111,13 @@ class Graph extends PureComponent {
|
||||||
mouseActiveRadius: 100,
|
mouseActiveRadius: 100,
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
container: this.state.legendRef,
|
container: $(this.legendRef.current as any),
|
||||||
labelFormatter: (s) => {return ' ' + s}
|
labelFormatter: (s: string) => {return ' ' + s}
|
||||||
},
|
},
|
||||||
xaxis: {
|
xaxis: {
|
||||||
mode: 'time',
|
mode: 'time',
|
||||||
showTicks: true,
|
showTicks: true,
|
||||||
showMinorTicks: true,
|
showMinorTicks: true,
|
||||||
// min: (new Date()).getTime(),
|
|
||||||
// max: (new Date(2000, 1, 1)).getTime(),
|
|
||||||
},
|
},
|
||||||
yaxis: {
|
yaxis: {
|
||||||
tickFormatter: this.formatValue,
|
tickFormatter: this.formatValue,
|
||||||
|
@ -200,8 +129,8 @@ class Graph extends PureComponent {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
show: true,
|
show: true,
|
||||||
cssClass: 'graph-tooltip',
|
cssClass: 'graph-tooltip',
|
||||||
content: (label, xval, yval, flotItem) => {
|
content: (label: string, xval: number, yval: number, flotItem: any) => {
|
||||||
const series = flotItem.series;
|
const series = flotItem.series; // TODO: type this.
|
||||||
var date = '<span class="date">' + new Date(xval).toUTCString() + '</span>';
|
var date = '<span class="date">' + new Date(xval).toUTCString() + '</span>';
|
||||||
var swatch = '<span class="detail-swatch" style="background-color: ' + series.color + '"></span>';
|
var swatch = '<span class="detail-swatch" style="background-color: ' + series.color + '"></span>';
|
||||||
var content = swatch + (series.labels.__name__ || 'value') + ": <strong>" + yval + '</strong>';
|
var content = swatch + (series.labels.__name__ || 'value') + ": <strong>" + yval + '</strong>';
|
||||||
|
@ -223,11 +152,12 @@ class Graph extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
getData() {
|
getData() {
|
||||||
return this.props.data.result.map(ts => {
|
return this.props.data.result.map((ts: any /* TODO: Type this*/) => {
|
||||||
// Insert nulls for all missing steps.
|
// Insert nulls for all missing steps.
|
||||||
let data = [];
|
let data = [];
|
||||||
let pos = 0;
|
let pos = 0;
|
||||||
const params = this.props.queryParams;
|
const params = this.props.queryParams!;
|
||||||
|
console.log(this.props.queryParams);
|
||||||
for (let t = params.startTime; t <= params.endTime; t += params.resolution) {
|
for (let t = params.startTime; t <= params.endTime; t += params.resolution) {
|
||||||
// Allow for floating point inaccuracy.
|
// Allow for floating point inaccuracy.
|
||||||
if (ts.values.length > pos && ts.values[pos][0] < t + params.resolution / 100) {
|
if (ts.values.length > pos && ts.values[pos][0] < t + params.resolution / 100) {
|
||||||
|
@ -246,16 +176,31 @@ class Graph extends PureComponent {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
parseValue(value) {
|
parseValue(value: string) {
|
||||||
var val = parseFloat(value);
|
var val = parseFloat(value);
|
||||||
if (isNaN(val)) {
|
if (isNaN(val)) {
|
||||||
// "+Inf", "-Inf", "+Inf" will be parsed into NaN by parseFloat(). The
|
// "+Inf", "-Inf", "+Inf" will be parsed into NaN by parseFloat(). They
|
||||||
// can't be graphed, so show them as gaps (null).
|
// can't be graphed, so show them as gaps (null).
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.plot();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
this.plot();
|
||||||
|
}
|
||||||
|
|
||||||
|
plot() {
|
||||||
|
if (this.chartRef.current === null || this.legendRef.current === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.plot($(this.chartRef.current!), this.getData(), this.getOptions());
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.props.data === null) {
|
if (this.props.data === null) {
|
||||||
return <Alert color="light">No data queried yet</Alert>;
|
return <Alert color="light">No data queried yet</Alert>;
|
||||||
|
@ -271,18 +216,8 @@ class Graph extends PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="graph">
|
<div className="graph">
|
||||||
{this.state.legendRef &&
|
<div className="graph-chart" ref={this.chartRef} />
|
||||||
<ReactFlot
|
<div className="graph-legend" ref={this.legendRef} />
|
||||||
id={this.id.toString()}
|
|
||||||
data={this.getData()}
|
|
||||||
options={this.getOptions()}
|
|
||||||
height="500px"
|
|
||||||
width="100%"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
|
|
||||||
{/* Really nasty hack below with setState to trigger a second render after the legend div starts to exist. */}
|
|
||||||
<div className="graph-legend" ref={ref => {!this.state.legendRef && this.setState({legendRef: ref})}}></div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
Loading…
Reference in a new issue