mirror of
https://github.com/prometheus/prometheus.git
synced 2025-08-06 22:27:17 +02:00
* Update all React app node modules I ran "yarn upgrade --latest" and then fixed items that caused errors with new linter settings in the React UI source. Signed-off-by: Julius Volz <julius.volz@gmail.com> * Fix more React UI lint errors that fail CI Signed-off-by: Julius Volz <julius.volz@gmail.com>
145 lines
4.2 KiB
TypeScript
145 lines
4.2 KiB
TypeScript
import React, { Component } from 'react';
|
|
|
|
import { Alert, Button, Col, Row } from 'reactstrap';
|
|
|
|
import Panel, { PanelOptions, PanelDefaultOptions } from './Panel';
|
|
import { decodePanelOptionsFromQueryString, encodePanelOptionsToQueryString } from './utils/urlParams';
|
|
|
|
interface PanelListState {
|
|
panels: {
|
|
key: string;
|
|
options: PanelOptions;
|
|
}[],
|
|
metricNames: string[];
|
|
fetchMetricsError: string | null;
|
|
timeDriftError: string | null;
|
|
}
|
|
|
|
class PanelList extends Component<any, PanelListState> {
|
|
private key: number = 0;
|
|
|
|
constructor(props: any) {
|
|
super(props);
|
|
|
|
const urlPanels = decodePanelOptionsFromQueryString(window.location.search);
|
|
|
|
this.state = {
|
|
panels: urlPanels.length !== 0 ? urlPanels : [
|
|
{
|
|
key: this.getKey(),
|
|
options: PanelDefaultOptions,
|
|
},
|
|
],
|
|
metricNames: [],
|
|
fetchMetricsError: null,
|
|
timeDriftError: null,
|
|
};
|
|
}
|
|
|
|
componentDidMount() {
|
|
fetch("../../api/v1/label/__name__/values", {cache: "no-store"})
|
|
.then(resp => {
|
|
if (resp.ok) {
|
|
return resp.json();
|
|
} else {
|
|
throw new Error('Unexpected response status when fetching metric names: ' + resp.statusText); // TODO extract error
|
|
}
|
|
})
|
|
.then(json => this.setState({ metricNames: json.data }))
|
|
.catch(error => this.setState({ fetchMetricsError: error.message }));
|
|
|
|
const browserTime = new Date().getTime() / 1000;
|
|
fetch("../../api/v1/query?query=time()", {cache: "no-store"})
|
|
.then(resp => {
|
|
if (resp.ok) {
|
|
return resp.json();
|
|
} else {
|
|
throw new Error('Unexpected response status when fetching metric names: ' + resp.statusText); // TODO extract error
|
|
}
|
|
})
|
|
.then(json => {
|
|
const serverTime = json.data.result[0];
|
|
const delta = Math.abs(browserTime - serverTime);
|
|
|
|
if (delta >= 30) {
|
|
throw new Error('Detected ' + delta + ' seconds time difference between your browser and the server. Prometheus relies on accurate time and time drift might cause unexpected query results.');
|
|
}
|
|
})
|
|
.catch(error => this.setState({ timeDriftError: error.message }));
|
|
|
|
window.onpopstate = () => {
|
|
const panels = decodePanelOptionsFromQueryString(window.location.search);
|
|
if (panels.length !== 0) {
|
|
this.setState({panels: panels});
|
|
}
|
|
}
|
|
}
|
|
|
|
getKey(): string {
|
|
return (this.key++).toString();
|
|
}
|
|
|
|
handleOptionsChanged(key: string, opts: PanelOptions): void {
|
|
const newPanels = this.state.panels.map(p => {
|
|
if (key === p.key) {
|
|
return {
|
|
key: key,
|
|
options: opts,
|
|
}
|
|
}
|
|
return p;
|
|
});
|
|
this.setState({panels: newPanels}, this.updateURL)
|
|
}
|
|
|
|
updateURL(): void {
|
|
const query = encodePanelOptionsToQueryString(this.state.panels);
|
|
window.history.pushState({}, '', query);
|
|
}
|
|
|
|
addPanel = (): void => {
|
|
const panels = this.state.panels.slice();
|
|
panels.push({
|
|
key: this.getKey(),
|
|
options: PanelDefaultOptions,
|
|
});
|
|
this.setState({panels: panels}, this.updateURL);
|
|
}
|
|
|
|
removePanel = (key: string): void => {
|
|
const panels = this.state.panels.filter(panel => {
|
|
return panel.key !== key;
|
|
});
|
|
this.setState({panels: panels}, this.updateURL);
|
|
}
|
|
|
|
render() {
|
|
return (
|
|
<>
|
|
<Row>
|
|
<Col>
|
|
{this.state.timeDriftError && <Alert color="danger"><strong>Warning:</strong> Error fetching server time: {this.state.timeDriftError}</Alert>}
|
|
</Col>
|
|
</Row>
|
|
<Row>
|
|
<Col>
|
|
{this.state.fetchMetricsError && <Alert color="danger"><strong>Warning:</strong> Error fetching metrics list: {this.state.fetchMetricsError}</Alert>}
|
|
</Col>
|
|
</Row>
|
|
{this.state.panels.map(p =>
|
|
<Panel
|
|
key={p.key}
|
|
options={p.options}
|
|
onOptionsChanged={(opts: PanelOptions) => this.handleOptionsChanged(p.key, opts)}
|
|
removePanel={() => this.removePanel(p.key)}
|
|
metricNames={this.state.metricNames}
|
|
/>
|
|
)}
|
|
<Button color="primary" className="add-panel-btn" onClick={this.addPanel}>Add Panel</Button>
|
|
</>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default PanelList;
|