Add metrics fetching and stuff

Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
Julius Volz 2019-02-03 22:47:56 +01:00
parent 3bd2fdaa97
commit 9a910701fa
2 changed files with 109 additions and 27 deletions

41
package-lock.json generated
View file

@ -5660,7 +5660,8 @@
}, },
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true "bundled": true,
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -5678,11 +5679,13 @@
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true "bundled": true,
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -5695,15 +5698,18 @@
}, },
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true "bundled": true,
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true "bundled": true,
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true "bundled": true,
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -5806,7 +5812,8 @@
}, },
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true "bundled": true,
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -5816,6 +5823,7 @@
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -5828,17 +5836,20 @@
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
}, },
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true "bundled": true,
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.2.4", "version": "2.2.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.1", "safe-buffer": "^5.1.1",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -5855,6 +5866,7 @@
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -5927,7 +5939,8 @@
}, },
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true "bundled": true,
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -5937,6 +5950,7 @@
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -6012,7 +6026,8 @@
}, },
"safe-buffer": { "safe-buffer": {
"version": "5.1.1", "version": "5.1.1",
"bundled": true "bundled": true,
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -6042,6 +6057,7 @@
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -6059,6 +6075,7 @@
"strip-ansi": { "strip-ansi": {
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -6097,11 +6114,13 @@
}, },
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true "bundled": true,
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.2", "version": "3.0.2",
"bundled": true "bundled": true,
"optional": true
} }
} }
}, },

View file

@ -1,5 +1,20 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Alert, Button, Col, Container, InputGroup, InputGroupAddon, Input, Nav, NavItem, NavLink, Row, TabContent, TabPane, Table } from 'reactstrap'; import {
Alert,
Button,
Col,
Container,
InputGroup,
InputGroupAddon,
Input,
Nav,
NavItem,
NavLink,
Row,
TabContent,
TabPane,
Table
} from 'reactstrap';
import ReactFlot from 'react-flot'; import ReactFlot from 'react-flot';
import '../node_modules/react-flot/flot/jquery.flot.time.min'; import '../node_modules/react-flot/flot/jquery.flot.time.min';
import './App.css'; import './App.css';
@ -19,6 +34,7 @@ class PanelList extends Component {
super(props); super(props);
this.state = { this.state = {
panels: [], panels: [],
metrics: [],
}; };
this.key = 0; this.key = 0;
@ -28,6 +44,24 @@ class PanelList extends Component {
componentDidMount() { componentDidMount() {
this.addPanel(); this.addPanel();
fetch("http://demo.robustperception.io:9090/api/v1/label/__name__/values")
.then(resp => {
if (resp.ok) {
return resp.json();
} else {
console.log(resp);
throw new Error('Unexpected response status when fetching metric names: ' + resp.statusText); // TODO extract error
}
})
.then(json =>
this.setState({
metrics: json.data,
})
)
.catch(error => {
this.setState({error})
});
} }
getKey() { getKey() {
@ -37,7 +71,7 @@ class PanelList extends Component {
addPanel() { addPanel() {
const panels = this.state.panels.slice(); const panels = this.state.panels.slice();
const key = this.getKey(); const key = this.getKey();
panels.push(<Panel key={key} removePanel={() => this.removePanel(key)}/>); panels.push({key: key});
this.setState({panels: panels}); this.setState({panels: panels});
} }
@ -51,7 +85,9 @@ class PanelList extends Component {
render() { render() {
return ( return (
<> <>
{this.state.panels} {this.state.panels.map(p =>
<Panel key={p.key} removePanel={() => this.removePanel(p.key)} metrics={this.state.metrics}/>
)}
<Button color="primary" onClick={this.addPanel}>Add Panel</Button> <Button color="primary" onClick={this.addPanel}>Add Panel</Button>
</> </>
); );
@ -63,7 +99,7 @@ class Panel extends Component {
super(props); super(props);
this.state = { this.state = {
expr: '', expr: 'rate(node_cpu_seconds_total[1m])',
type: 'table', // TODO enum? type: 'table', // TODO enum?
range: 3600, range: 3600,
endTime: null, endTime: null,
@ -78,6 +114,16 @@ class Panel extends Component {
this.handleExpressionChange = this.handleExpressionChange.bind(this); this.handleExpressionChange = this.handleExpressionChange.bind(this);
} }
componentDidUpdate(prevProps, prevState) {
if (prevState.type !== this.state.type) {
this.execute();
}
}
componentDidMount() {
this.execute();
}
execute() { execute() {
if (this.state.expr === "") { if (this.state.expr === "") {
return; return;
@ -85,7 +131,7 @@ class Panel extends Component {
this.setState({loading: true}); this.setState({loading: true});
let url = new URL('http://localhost:9090/');//window.location.href); let url = new URL('http://demo.robustperception.io:9090/');//window.location.href);
let params = { let params = {
'query': this.state.expr, 'query': this.state.expr,
}; };
@ -119,7 +165,7 @@ class Panel extends Component {
throw new Error('Unexpected response status: ' + resp.statusText); throw new Error('Unexpected response status: ' + resp.statusText);
} }
}) })
.then(json => .then(json =>
this.setState({ this.setState({
error: null, error: null,
data: json.data, data: json.data,
@ -144,6 +190,9 @@ class Panel extends Component {
<Row> <Row>
<Col> <Col>
<ExpressionInput value={this.state.expr} onChange={this.handleExpressionChange} execute={this.execute}/> <ExpressionInput value={this.state.expr} onChange={this.handleExpressionChange} execute={this.execute}/>
{/*<Input type="select" name="selectMetric">
{this.props.metrics.map(m => <option key={m}>{m}</option>)}
</Input>*/}
</Col> </Col>
</Row> </Row>
<Row> <Row>
@ -177,17 +226,22 @@ class Panel extends Component {
</NavItem> </NavItem>
</Nav> </Nav>
<TabContent activeTab={this.state.type}> <TabContent activeTab={this.state.type}>
// TODO: Only render this pane when it's selected.
<TabPane tabId="graph"> <TabPane tabId="graph">
<GraphControls {this.state.type === 'graph' &&
range={this.state.range} <>
endTime={this.state.endTime} <GraphControls
step={this.state.step} range={this.state.range}
/> endTime={this.state.endTime}
<Graph data={this.state.data} /> step={this.state}
/>
<Graph data={this.state.data} />
</>
}
</TabPane> </TabPane>
<TabPane tabId="table"> <TabPane tabId="table">
<DataTable data={this.state.data} /> {this.state.type === 'table' &&
<DataTable data={this.state.data} />
}
</TabPane> </TabPane>
</TabContent> </TabContent>
</Col> </Col>
@ -267,7 +321,7 @@ function DataTable(props) {
break; break;
default: default:
// TODO // TODO
} }
} }
return ( return (
@ -281,6 +335,9 @@ function DataTable(props) {
class GraphControls extends Component { class GraphControls extends Component {
// TODO // TODO
render() {
return null;
}
} }
var graphID = 0; var graphID = 0;
@ -340,7 +397,13 @@ class Graph extends Component {
} }
return ( return (
<div> <div>
<ReactFlot id={getGraphID()} data={this.getData()} options={this.getOptions()} width="1900px" height="500px" /> <ReactFlot
id={getGraphID().toString()}
data={this.getData()}
options={this.getOptions()}
width="1900px"
height="500px"
/>
<div ref={ref => { this.legend = ref; }}></div> <div ref={ref => { this.legend = ref; }}></div>
</div> </div>
); );