diff --git a/api/metrics-api-jaxrs/src/main/webapp/static/css/main.css b/api/metrics-api-jaxrs/src/main/webapp/static/css/main.css
index 6e43655b3..4527b9702 100644
--- a/api/metrics-api-jaxrs/src/main/webapp/static/css/main.css
+++ b/api/metrics-api-jaxrs/src/main/webapp/static/css/main.css
@@ -1,19 +1,3 @@
-/*
- * Copyright 2014-2017 Red Hat, Inc. and/or its affiliates
- * and other contributors as indicated by the @author tags.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
.navbar .brand-name {
font-size: 18pt;
padding-top: 15px;
@@ -27,6 +11,80 @@
color: #f5f5f5;
}
+.navbar-sidebar {
+ background: #292e33;
+ border: 0;
+ border-radius: 0;
+ bottom: 0;
+ left: -240px;
+ margin: 0;
+ padding: 0;
+ position: fixed;
+ top: 58px;
+ width: 240px;
+ z-index: 1029;
+}
+
+@media (min-width: 992px) {
+ .navbar-sidebar {
+ box-shadow: none!important;
+ left: 0;
+ overflow-x: hidden;
+ overflow-y: auto;
+ padding-right: 0;
+ }
+}
+
+.navbar-sidebar {
+ text-align: initial;
+}
+
+.navbar-sidebar .section {
+ color: #fff;
+ display: block;
+ padding: 0 20px 20px 20px;
+ border-bottom: 1px solid #393f44;
+ margin-bottom: 10px;
+}
+
+.navbar-sidebar .title {
+ font-size: 16px;
+ line-height: 60px;
+}
+
+.navbar-sidebar ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+.navbar-sidebar ul li a {
+ text-decoration: none;
+ cursor: pointer;
+ color: #fff;
+ line-height: 24px;
+}
+
+.navbar-sidebar input {
+ width: 200px;
+ color: #363636;
+}
+
+.container-fluid {
+ padding-left: 45px;
+}
+
+.container-fluid {
+ padding-bottom: 50px;
+ padding-top: 58px;
+}
+
+@media (min-width: 992px) {
+ .container-fluid {
+ padding-left: 260px;
+ }
+}
+
.content {
background-color: #f5f5f5;
width: 100%;
@@ -53,3 +111,7 @@ h1, h3 {
text-align: center;
word-wrap:break-word;
}
+
+#line-chart {
+ margin-top: 50px;
+}
diff --git a/api/metrics-api-jaxrs/src/main/webapp/static/index.html b/api/metrics-api-jaxrs/src/main/webapp/static/index.html
index f19139285..927eabc7d 100644
--- a/api/metrics-api-jaxrs/src/main/webapp/static/index.html
+++ b/api/metrics-api-jaxrs/src/main/webapp/static/index.html
@@ -1,3 +1,20 @@
+
+
Hawkular Metrics
@@ -5,12 +22,18 @@
-
+ -->
+
+
+
+
+
+
diff --git a/api/metrics-api-jaxrs/src/main/webapp/static/js/navigation.js b/api/metrics-api-jaxrs/src/main/webapp/static/js/navigation.js
index 3800d3838..06c56ad27 100644
--- a/api/metrics-api-jaxrs/src/main/webapp/static/js/navigation.js
+++ b/api/metrics-api-jaxrs/src/main/webapp/static/js/navigation.js
@@ -21,11 +21,159 @@ const { Router,
hashHistory,
Link } = ReactRouter;
-const Metrics = () => (
-
-
Metrics
-
-)
+class Chart extends React.Component {
+ constructor(props) {
+ super(props);
+ console.log("ctor Chart");
+ }
+
+ render() {
+ console.log("render Chart");
+ let title, notice;
+ if (this.props.tenant && this.props.type && this.props.metric) {
+ title = "Tenant '" + this.props.tenant + "', " + this.props.type + " '" + this.props.metric + "'";
+ } else if (this.props.tenant) {
+ title = "Tenant '" + this.props.tenant + "'";
+ notice = "Select a metric from the left menu"
+ } else {
+ notice = "Select a tenant and a metric from the left menu"
+ }
+ return (
+
+ );
+ }
+
+ componentDidMount() {
+ console.log("did mount Chart");
+ const config = $().c3ChartDefaults().getDefaultSingleLineConfig();
+ config.bindto = '#line-chart';
+ config.data = {
+ x: 'x',
+ columns: [['x'],['data1']],
+ type: 'line'
+ };
+ config.axis.x = {
+ type: 'timeseries',
+ tick: {
+ format: '%I:%M:%S'
+ }
+ };
+ const chart = c3.generate(config);
+ if (this.props.tenant && this.props.type && this.props.metric) {
+ let typeForUrl = this.props.type;
+ if (typeForUrl != "availability") {
+ typeForUrl += "s";
+ }
+ // FIXME: manage non numeric types
+ // Fetch datapoints
+ $.ajax({
+ url: "/hawkular/metrics/" + typeForUrl + "/" + encodeURI(this.props.metric) + "/raw?order=ASC",
+ contentType: "application/json",
+ headers: {"Hawkular-Tenant": this.props.tenant},
+ success: (datapoints, textStatus, xhr) => {
+ if (datapoints) {
+ chart.load({
+ columns: [
+ ['x'].concat(datapoints.map(dp => dp.timestamp)),
+ ['data1'].concat(datapoints.map(dp => dp.value))
+ ]
+ });
+ }
+ }
+ });
+ }
+ }
+}
+
+class Metrics extends React.Component {
+ constructor(props) {
+ super(props);
+ this.onTenantChanged = this.onTenantChanged.bind(this);
+ this.state = {
+ tenant: this.props.params.tenant || "",
+ message: "",
+ metrics: []
+ };
+ if (this.props.params && this.props.params.tenant) {
+ this.state.metrics = ["Loading..."];
+ this.fetchMetrics();
+ }
+ }
+
+ render() {
+ console.log("Rendering Metrics");
+ return (
+
+
+
+
+
+
+ )
+ }
+
+ onTenantChanged(event) {
+ this.setState({tenant: event.target.value});
+ if (this.tenantChangeHandle) {
+ clearTimeout(this.tenantChangeHandle);
+ }
+ this.tenantChangeHandle = setTimeout(() => {
+ this.fetchMetrics();
+ this.tenantChangeHandle = null;
+ }, 200);
+ }
+
+ fetchMetrics() {
+ $.ajax({
+ url: "/hawkular/metrics/metrics",
+ contentType: "application/json",
+ headers: {"Hawkular-Tenant": this.state.tenant},
+ success: (metrics, textStatus, xhr) => {
+ if (metrics.length > 0) {
+ this.setState({metrics: metrics.sort((a,b) => {
+ return a.id < b.id ? -1 : 1;
+ }), message: ""});
+ } else {
+ this.setState({
+ message: "No metric found for this tenant"
+ });
+ }
+ },
+ complete: (xhr, textStatus) => {
+ if (xhr.status === 404 || xhr.status === 503) {
+ this.setState({
+ message: "The server is not available"
+ });
+ } else if (xhr.status != 200) {
+ this.setState({
+ message: "An error occured while accessing the server: " + textStatus
+ });
+ }
+ }
+ });
+ }
+}
class Status extends React.Component {
constructor(props) {
@@ -40,59 +188,56 @@ class Status extends React.Component {
render() {
return (
-
-
-
-
Hawkular Metrics
-
A time series metrics engine based on Cassandra
+
+
+
+
+
+
Hawkular Metrics
+
A time series metrics engine based on Cassandra
-
{this.state.version}
-
{this.state.gitref}
-
{this.state.status}
+
{this.state.version}
+
{this.state.gitref}
+
{this.state.status}
+
)
}
componentDidMount() {
- var httpRequest;
-
- if (window.XMLHttpRequest) {
- httpRequest = new XMLHttpRequest();
- } else if (window.ActiveXObject) {
- try {
- httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
- } catch (e) {
- httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
- }
- }
-
- httpRequest.onreadystatechange = () => {
- if (httpRequest.readyState === 4) {
- if (httpRequest.status === 200) {
- const statusJson = JSON.parse(httpRequest.responseText);
- this.setState({
- version: statusJson["Implementation-Version"],
- gitref: "(Git SHA1 - " + statusJson["Built-From-Git-SHA1"] + ")",
- status: "Metrics Service: " + statusJson.MetricsService
- });
- } else if (httpRequest.status === 404 || httpRequest.status === 503) {
+ $.ajax({
+ url: "/hawkular/metrics/status",
+ success: (data, textStatus, xhr) => {
+ const statusJson = JSON.parse(textStatus);
+ this.setState({
+ version: statusJson["Implementation-Version"],
+ gitref: "(Git SHA1 - " + statusJson["Built-From-Git-SHA1"] + ")",
+ status: "Metrics Service: " + statusJson.MetricsService
+ });
+ },
+ complete: (xhr, textStatus) => {
+ if (xhr.status === 404 || xhr.status === 503) {
this.setState({
status: "The server is not available"
});
- } else {
+ } else if (xhr != 200) {
this.setState({
- status: "An error occured while accessing the server :" + httpRequest.responseText
+ status: "An error occured while accessing the server: " + textStatus
});
}
}
- };
- httpRequest.open("GET", "/hawkular/metrics/status");
- httpRequest.send();
+ });
}
}
const Menu = (
-