accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ctubb...@apache.org
Subject [11/54] [abbrv] accumulo git commit: ACCUMULO-2181/3005 Porting Monitor
Date Thu, 06 Jul 2017 20:43:05 GMT
http://git-wip-us.apache.org/repos/asf/accumulo/blob/0ca5cd33/server/monitor/src/main/resources/resources/screen.css
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/resources/screen.css b/server/monitor/src/main/resources/resources/screen.css
new file mode 100644
index 0000000..9f8f2b6
--- /dev/null
+++ b/server/monitor/src/main/resources/resources/screen.css
@@ -0,0 +1,507 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You 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.
+*/
+/* basic screen style for all pages */
+html,body {
+  height: 100%;
+  margin: 0;
+  padding: 0;
+  color: #333333;
+  font-size: 10pt;
+  font-family: verdana, arial, sans-serif;
+  text-align: center;
+}
+
+#banner {
+  height: 1.5em;
+  font-size: 1.0em;
+}
+
+#content-wrapper {
+  position: relative;
+  min-height: 95%;
+}
+
+* #content-wrapper {
+  height: 95%;
+}
+
+#content {
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 1.5em;
+  padding-bottom: 0;
+}
+
+#header {
+  position: absolute;
+  padding-top: 0;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 5em;
+  color: #c4c4c4;
+  background-color: #304065;
+  text-align: center;
+}
+
+#headertitle {
+  /*position: absolute;
+  top: -1.0em;
+  left: 0.5em;
+  right: 1.0em;*/
+  font-size: 20pt;
+}
+
+#sidebar {
+  text-align: left;
+}
+
+#subheader {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  font-size: .92em;
+}
+
+#footer {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  padding: 0;
+  /*height: 1.5em;*/
+  font-size: 1.0em;
+}
+
+#main {
+  position: absolute;
+  top: 5.0em;
+  /*left: 11em;*/
+  left: 0;
+  right: 0;
+  bottom: 0;
+  padding: 0.6em;
+  /*overflow: scroll;*/
+  margin-left: auto;
+  margin-right: auto;
+  width: 90%;
+}
+
+#nav {
+  position: absolute;
+  top: 0.5em;
+  /*left: 0;*/
+  right: 0;
+  /*bottom: 0;*/
+  padding: 0.5em;
+  /*width: 10em;*/
+  /*color: #304065;*/
+  /*background-color: #c4c4c4;*/
+  /*text-align: left;*/
+  /*height: 3.0em;*/
+}
+
+#nav-title {
+  margin-left: auto;
+  margin-right: auto;
+  text-align: center;
+  font-size: 1.1em;
+}
+
+h1 {
+  font-size: 2.2em;
+  font-variant: small-caps;
+  text-align: center;
+}
+
+h2 {
+  width: 100%;
+  font-size: 1.3em;
+  text-align: center;
+}
+
+h2.error {
+  width: 100%;
+  color: #ff0000;
+  background-color: #000000;
+}
+
+h2.error a {
+  color: #ff0000;
+  background-color: #000000;
+}
+
+caption {
+  margin-left: auto;
+  margin-right: auto;
+}
+
+caption.error {
+  color: #ff0000;
+  background-color: #000000;
+}
+
+hr {
+  border: 0;
+  height: 1px;
+  background-color: #304065;
+  color: #304065;
+}
+
+table {
+  /*margin-left: auto;
+  margin-right: auto;
+  min-width: 60%;*/
+  /*border: 1px #333333 solid;
+  border-spacing-top: 0;
+  border-spacing-bottom: 0;*/
+  font-size: 9pt;
+  /*border: 1px #333333 solid;
+  border: 1px #333333 solid;*/
+}
+
+/*
+The following is to avoid a problem with the flot
+javascript library.  This file sets min-width to 60% 
+for all tables.  This make the html generated by
+flot.js not work.  Flot creates a class called legend
+used in a div that has a child table.  This sets 
+min-width to 0 for that child table enabling it
+to render correctly.  
+*/
+div.legend > table {
+  min-width: 0%;
+}
+
+table.sortable {
+  border-left: 0;
+  border-right: 0;
+  border-top: 1px #333333 dotted;
+  border-bottom: 1px #333333 dotted;
+}
+
+/*
+table.sortable tbody tr:nth-child(2n) td {
+  background: #ffffff;
+}
+
+table.sortable tbody tr:nth-child(2n+1) td {
+  background: #cef4b5;
+}*/
+
+td {
+  border-top: 0;
+  border-bottom: 0;
+  border-left: 0;
+  border-right: 0;
+  border-spacing-top: 0;
+  border-spacing-bottom: 0;
+  padding-left: 0.5em;
+  padding-right: 0.5em;
+  padding-top: 0.15em;
+  padding-bottom: 0.15em;
+  color: #333333;
+}
+
+th {
+  border-top: 0;
+  border-bottom: 3px #333333 solid;
+  border-left: 1px #333333 dotted;
+  border-right: 0;
+  border-spacing-top: 0;
+  border-spacing-bottom: 0;
+  text-align: center;
+  font-variant: small-caps;
+  padding-left: 0.5em;
+  padding-right: 0.5em;
+  padding-top: 0.2em;
+  padding-bottom: 0.2em;
+  color: #333333;
+  font-size: 10pt;
+  vertical-align: bottom;
+}
+
+td.firstcell {
+  border-left: 0;
+}
+
+th.sortable {
+  color: blue;
+}
+
+a {
+  text-decoration: none;
+  color: #0000ff;
+  line-height: 1.5em;
+}
+
+a:hover {
+  color: #004400;
+  text-decoration: underline;
+}
+
+a img {
+  border: 0px;
+}
+
+div.show {
+  display: block;
+}
+
+div.hide {
+  display: none;
+}
+
+div.progress-chart {
+  border: 1px solid #333333;
+  border-spacing: 0;
+  width: 150px;
+  float: left;
+}
+
+div.progress-chart>div {
+  height: 20px;
+  background-color: #0000ff;
+}
+
+pre.logevent {
+  margin: 0;
+}
+
+.noborder {
+  border: 0;
+  border-spacing: 0;
+  border-bottom: 0;
+  border-right: 0;
+}
+
+.overview-table {
+    width: 100%;
+    border: 0;
+    border-spacing: 0;
+    border-bottom: 0;
+    border-right: 0;
+}
+
+.overview-table td {
+  vertical-align: top;
+  width: 50%;
+}
+
+/**
+ * Need this to only apply the previous CSS to the top child
+ * could probably do a selector
+ */
+.overview-table td td {
+  vertical-align: inherit;
+  width: 0;
+}
+
+.table-caption {
+  font-size: 2em;
+  font-variant: small-caps;
+  text-align: center;
+}
+
+.table-subcaption {
+  font-size: 0.9em;
+}
+
+.left {
+  text-align: left;
+}
+
+.right {
+  text-align: right;
+  margin-right: 0;
+}
+
+.error, .error a {
+  color: #ffffff;
+  background-color: #d9534f;
+}
+
+.error-inv, .error-inv a {
+  color: #d9534f;
+}
+
+.warning, .warning a {
+  background-color: #f0ad4e;
+}
+
+.warning-inv, .warning-inv a {
+  color: #f0ad4e;
+}
+
+.normal, .normal a {
+  background-color: #5cb85c;
+}
+
+.normal-inv, .normal-inv a {
+  color: #5cb85c;
+}
+
+.highlight {
+  background-color: #cef4b5;
+}
+
+.icon-dot {
+  display: inline-block;
+  min-width: 1em;
+  height: 1em;
+  padding: 3px 7px;
+  font-size: @font-size-small;
+  font-weight: @badge-font-weight;
+  color: @badge-color;
+  line-height: @badge-line-height;
+  vertical-align: middle;
+  white-space: nowrap;
+  text-align: center;
+  background-color: @badge-bg;
+  border-radius: 1em;
+}
+
+.smalltext {
+  font-size: 0.8em;
+}
+
+.center {
+  text-align: center;
+  padding: 0.5em;
+}
+
+.plotHeading {
+  text-align: center;
+  font-size: 1.5em;
+}
+.nowrap {
+  white-space:nowrap;
+}
+
+.viscontrol {
+  border: 1px solid #c4c4c4;
+  padding: 5px;
+}
+
+#vishoverinfo {
+  visibility: hidden;
+  position: absolute;
+  border: 1px solid #c4c4c4;
+  background-color: #ffffff;
+}
+
+#shell {
+  text-align: left;
+  color: #55d839;
+  border: 1px;
+  padding-left: 5px;
+  background-color: #000000;
+  height: 40em;
+  overflow: auto;
+  font-family: Monaco, monospace;
+  font-size: 100%;
+}
+
+#shell span {
+  display: inline;
+}
+
+#shell input {
+  display: inline;
+  border: none;
+  width: 60%;
+  color: #55d839;
+  background-color: #000000;
+  font-family: Monaco, monospace;
+  font-size: 100%;
+}
+
+#shell pre {
+  font-family: Monaco, monospace;
+  font-size: 100%;
+}
+
+#login {
+  text-align: left;
+}
+
+#login table {
+  margin-left: 0;
+  min-width: 0%;
+}
+
+#loginError {
+  text-align: left;
+  color: red;
+}
+
+#filters, #tables {
+  /*overflow-y: scroll;*/
+  /*height: 100%;*/
+  width: 80%;
+  margin-left: 15%;
+  /*float: left;*/
+}
+
+.center-block {
+  width: 100%;
+}
+
+.nav-pills > li > a {
+  color: #c4c4c4;
+}
+
+.nav-pills > li > a:hover, .dropdown.open > a:hover, .dropdown.open > a, .dropdown.open > a:focus {
+  background-color: #101010;
+}
+
+.dropdown-menu {
+  right: 0;
+  left: unset;
+}
+
+.axis path, .axis line
+{
+  fill: none;
+  stroke: #777;
+  shape-rendering: crispEdges;
+}
+
+.axis text
+{
+  font-family: 'Arial';
+  font-size: 13px;
+}
+.tick
+{
+  stroke-dasharray: 1, 2;
+}
+.bar
+{
+  fill: FireBrick;
+}
+
+.legend
+{
+  /*padding: 5px;*/
+  font: 10px sans-serif;
+  /*background: yellow;
+  box-shadow: 2px 2px 1px #888;*/
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0ca5cd33/server/monitor/src/main/resources/resources/server.js
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/resources/server.js b/server/monitor/src/main/resources/resources/server.js
new file mode 100644
index 0000000..d9b4f79
--- /dev/null
+++ b/server/monitor/src/main/resources/resources/server.js
@@ -0,0 +1,429 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You 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.
+*/
+
+var serv;
+/**
+ * Makes the REST calls, generates the tables with the new information
+ */
+function refreshServer() {
+  $.ajaxSetup({
+    async: false
+  });
+  getTServer(serv);
+  $.ajaxSetup({
+    async: true
+  });
+  refreshDetailTable();
+  refreshHistoryTable();
+  refreshCurrentTable();
+  refreshResultsTable();
+}
+
+/**
+ * Used to redraw the page
+ */
+function refresh() {
+  refreshServer();
+}
+
+/**
+ * Generates the server details table
+ */
+function refreshDetailTable() {
+
+  $('#tServerDetail tr:gt(0)').remove();
+
+  var data = sessionStorage.server === undefined ?
+      [] : JSON.parse(sessionStorage.server);
+
+  var items = [];
+
+  if (data.length === 0 || data.details === undefined) {
+    items.push('<td class="center" colspan="5"><i>Empty</i></td>');
+  } else {
+    items.push('<td class="firstcell right" data-value="' +
+        data.details.hostedTablets + '">' +
+        bigNumberForQuantity(data.details.hostedTablets) + '</td>');
+
+    items.push('<td class="right" data-value="' +
+        data.details.entries + '">' +
+        bigNumberForQuantity(data.details.entries) + '</td>');
+
+    items.push('<td class="right" data-value="' +
+        data.details.minors + '">' +
+        bigNumberForQuantity(data.details.minors) + '</td>');
+
+    items.push('<td class="right" data-value="' +
+        data.details.majors + '">' +
+        bigNumberForQuantity(data.details.majors) + '</td>');
+
+    items.push('<td class="right" data-value="' +
+        data.details.splits + '">' +
+        bigNumberForQuantity(data.details.splits) + '</td>');
+  }
+
+  $('<tr/>', {
+    html: items.join('')
+  }).appendTo('#tServerDetail');
+}
+
+/**
+ * Generates the server history table
+ */
+function refreshHistoryTable() {
+
+  $('#opHistoryDetails tr:gt(0)').remove();
+
+  var data = sessionStorage.server === undefined ?
+      [] : JSON.parse(sessionStorage.server);
+
+  if (data.length === 0 || data.allTimeTabletResults === undefined) {
+    var row = [];
+
+    row.push('<td class="center" colspan="8"><i>Empty</i></td>');
+
+    $('<tr/>', {
+      html: row.join('')
+    }).appendTo('#opHistoryDetails');
+  } else {
+    var totalTimeSpent = 0;
+    $.each(data.allTimeTabletResults, function(key, val) {
+      totalTimeSpent += val.timeSpent;
+    });
+
+    var count = 0;
+    $.each(data.allTimeTabletResults, function(key, val) {
+      var row = [];
+
+      row.push('<td class="firstcell left" data-value="' + val.operation +
+          '">' + val.operation + '</td>');
+
+      row.push('<td class="right" data-value="' + val.success +
+          '">' + bigNumberForQuantity(val.success) + '</td>');
+
+      row.push('<td class="right" data-value="' + val.failure +
+          '">' + bigNumberForQuantity(val.failure) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.avgQueueTime == null ? '-' : val.avgQueueTime * 1000.0) +
+          '">' + (val.avgQueueTime == null ?
+          '&mdash;' : timeDuration(val.avgQueueTime * 1000.0)) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.queueStdDev == null ? '-' : val.queueStdDev * 1000.0) +
+          '">' + (val.queueStdDev == null ?
+          '&mdash;' : timeDuration(val.queueStdDev * 1000.0)) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.avgTime == null ? '-' : val.avgTime * 1000.0) +
+          '">' + (val.avgTime == null ?
+          '&mdash;' : timeDuration(val.avgTime * 1000.0)) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.stdDev == null ? '-' : val.stdDev * 1000.0) +
+          '">' + (val.stdDev == null ?
+          '&mdash;' : timeDuration(val.stdDev * 1000.0)) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          ((val.timeSpent / totalTimeSpent) * 100) +
+          '"><div class="progress"><div class="progress-bar"' +
+          ' role="progressbar" style="min-width: 2em; width:' +
+          Math.floor((val.timeSpent / totalTimeSpent) * 100) +
+          '%;">' + Math.floor((val.timeSpent / totalTimeSpent) * 100) + '%</div></div></td>');
+
+      $('<tr/>', {
+        html: row.join('')
+      }).appendTo('#opHistoryDetails');
+
+    });
+  }
+}
+
+/**
+ * Generates the current server table
+ */
+function refreshCurrentTable() {
+
+  $('#currentTabletOps tr:gt(0)').remove();
+
+  var data = sessionStorage.server === undefined ?
+      [] : JSON.parse(sessionStorage.server);
+
+  var items = [];
+  if (data.length === 0 || data.currentTabletOperationResults === undefined) {
+    items.push('<td class="center" colspan="4"><i>Empty</i></td>');
+  } else {
+    var current = data.currentTabletOperationResults;
+
+    items.push('<td class="firstcell right" data-value="' +
+        (current.currentMinorAvg == null ?
+        '-' : current.currentMinorAvg * 1000.0) + '">' +
+        (current.currentMinorAvg == null ?
+        '&mdash;' : timeDuration(current.currentMinorAvg * 1000.0)) +
+        '</td>');
+
+    items.push('<td class="right" data-value="' +
+        (current.currentMinorStdDev == null ?
+        '-' : current.currentMinorStdDev * 1000.0) + '">' +
+        (current.currentMinorStdDev == null ?
+        '&mdash;' : timeDuration(current.currentMinorStdDev * 1000.0)) +
+        '</td>');
+
+    items.push('<td class="right" data-value="' +
+        (current.currentMajorAvg == null ?
+        '-' : current.currentMajorAvg * 1000.0) + '">' +
+        (current.currentMajorAvg == null ?
+        '&mdash;' : timeDuration(current.currentMajorAvg * 1000.0)) +
+        '</td>');
+
+    items.push('<td class="right" data-value="' +
+        (current.currentMajorStdDev == null ?
+        '-' : current.currentMajorStdDev * 1000.0) + '">' +
+        (current.currentMajorStdDev == null ?
+        '&mdash;' : timeDuration(current.currentMajorStdDev * 1000.0)) +
+        '</td>');
+  }
+
+  $('<tr/>', {
+      html: items.join('')
+  }).appendTo('#currentTabletOps');
+
+}
+
+/**
+ * Generates the server results table
+ */
+function refreshResultsTable() {
+
+  $('#perTabletResults tr:gt(0)').remove();
+
+  var data = sessionStorage.server === undefined ?
+      [] : JSON.parse(sessionStorage.server);
+
+  if (data.length === 0 || data.currentOperations === undefined) {
+    var row = [];
+
+    row.push('<td class="center" colspan="11"><i>Empty</i></td>');
+
+    $('<tr/>', {
+      html: row.join('')
+    }).appendTo('#perTabletResults');
+  } else {
+    $.each(data.currentOperations, function(key, val) {
+      var row = [];
+
+      row.push('<td class="firstcell left" data-value="' + val.name +
+          '"><a href="/tables/' + val.tableID + '">' + val.name + '</a></td>');
+
+      row.push('<td class="left" data-value="' + val.tablet + '"><code>' +
+          val.tablet + '</code></td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.entries == null ? 0 : val.entries) + '">' +
+          bigNumberForQuantity(val.entries) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.ingest == null ? 0 : val.ingest) + '">' +
+          bigNumberForQuantity(Math.floor(val.ingest)) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.query == null ? 0 : val.query) + '">' +
+          bigNumberForQuantity(Math.floor(val.query)) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.minorAvg == null ? '-' : val.minorAvg * 1000.0) + '">' +
+          (val.minorAvg == null ?
+          '&mdash;' : timeDuration(val.minorAvg * 1000.0)) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.minorStdDev == null ? '-' : val.minorStdDev * 1000.0) + '">' +
+          (val.minorStdDev == null ?
+          '&mdash;' : timeDuration(val.minorStdDev * 1000.0)) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.minorAvgES == null ? 0 : val.minorAvgES) + '">' +
+          bigNumberForQuantity(Math.floor(val.minorAvgES)) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.majorAvg == null ? '-' : val.majorAvg * 1000.0) + '">' +
+          (val.majorAvg == null ?
+          '&mdash;' : timeDuration(val.majorAvg * 1000.0)) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.majorStdDev == null ? '-' : val.majorStdDev * 1000.0) + '">' +
+          (val.majorStdDev == null ?
+          '&mdash;' : timeDuration(val.majorStdDev * 1000.0)) + '</td>');
+
+      row.push('<td class="right" data-value="' +
+          (val.majorAvgES == null ? 0 : val.majorAvgES) + '">' +
+          bigNumberForQuantity(Math.floor(val.majorAvgES)) + '</td>');
+
+      $('<tr/>', {
+        html: row.join('')
+      }).appendTo('#perTabletResults');
+    });
+  }
+}
+
+/**
+ * Sorts the different server status tables on the selected column
+ *
+ * @param {string} table Table ID to sort
+ * @param {number} n Column number to sort by
+ */
+function sortTable(table, n) {
+  var tableIDs = ['tServerDetail', 'opHistoryDetails',
+      'currentTabletOps', 'perTabletResults'];
+
+  if (sessionStorage.tableColumnSort !== undefined &&
+      sessionStorage.tableColumnSort == n &&
+      sessionStorage.direction !== undefined) {
+    direction = sessionStorage.direction === 'asc' ? 'desc' : 'asc';
+  } else {
+    direction = sessionStorage.direction === undefined ?
+        'asc' : sessionStorage.direction;
+  }
+  sessionStorage.tableColumn = tableIDs[table];
+  sessionStorage.tableColumnSort = n;
+
+  sortTables(tableIDs[table], direction, n);
+}
+
+/**
+ * Creates the server detail header
+ *
+ * @param {string} server Server name
+ */
+function createDetailHeader(server) {
+  var caption = [];
+  serv = server;
+
+  caption.push('<span class="table-caption">Details</span><br />');
+  caption.push('<span class="table-subcaption">' + server + '</span><br />');
+
+  $('<caption/>', {
+    html: caption.join('')
+  }).appendTo('#tServerDetail');
+
+  var items = [];
+
+  items.push('<th class="firstcell" onclick="sortTable(0,0)">Hosted&nbsp;' +
+      'Tablets&nbsp;</th>');
+  items.push('<th onclick="sortTable(0,1)">Entries&nbsp;</th>');
+  items.push('<th onclick="sortTable(0,2)">Minor&nbsp;Compacting&nbsp;</th>');
+  items.push('<th onclick="sortTable(0,3)">Major&nbsp;Compacting&nbsp;</th>');
+  items.push('<th onclick="sortTable(0,4)">Splitting&nbsp;</th>');
+
+  $('<tr/>', {
+    html: items.join('')
+  }).appendTo('#tServerDetail');
+}
+
+/**
+ * Creates the server history header
+ */
+function createHistoryHeader() {
+  var caption = [];
+
+  caption.push('<span class="table-caption">All-Time&nbsp;Tablet&nbsp;' +
+      'Operation&nbsp;Results</span><br />');
+
+  $('<caption/>', {
+    html: caption.join('')
+  }).appendTo('#opHistoryDetails');
+
+  var items = [];
+
+  items.push('<th class="firstcell" onclick="sortTable(1,0)">' +
+      'Operation&nbsp;</th>');
+  items.push('<th onclick="sortTable(1,1)">Success&nbsp;</th>');
+  items.push('<th onclick="sortTable(1,2)">Failure&nbsp;</th>');
+  items.push('<th onclick="sortTable(1,3)">Average<br />Queue&nbsp;' +
+      'Time&nbsp;</th>');
+  items.push('<th onclick="sortTable(1,4)">Std.&nbsp;Dev.<br />Queue&nbsp;' +
+      'Time&nbsp;</th>');
+  items.push('<th onclick="sortTable(1,5)">Average<br />Time&nbsp;</th>');
+  items.push('<th onclick="sortTable(1,6)">Std.&nbsp;Dev.<br />Time' +
+      '&nbsp;</th>');
+  items.push('<th onclick="sortTable(1,7)">Percentage&nbsp;Time&nbsp;' +
+      'Spent&nbsp;');
+
+  $('<tr/>', {
+    html: items.join('')
+  }).appendTo('#opHistoryDetails');
+}
+
+/**
+ * Creates the current server header
+ */
+function createCurrentHeader() {
+  var caption = [];
+
+  caption.push('<span class="table-caption">Current&nbsp;Tablet&nbsp;' +
+      'Operation&nbsp;Results</span><br />');
+
+  $('<caption/>', {
+    html: caption.join('')
+  }).appendTo('#currentTabletOps');
+
+  var items = [];
+
+  items.push('<th class="firstcell" onclick="sortTable(2,0)">Minor&nbsp;' +
+      'Average&nbsp;</th>');
+  items.push('<th onclick="sortTable(2,1)">Minor&nbsp;Std&nbsp;Dev&nbsp;</th>');
+  items.push('<th onclick="sortTable(2,2)">Major&nbsp;Avg&nbsp;</th>');
+  items.push('<th onclick="sortTable(2,3)">Major&nbsp;Std&nbsp;Dev&nbsp;</th>');
+
+  $('<tr/>', {
+    html: items.join('')
+  }).appendTo('#currentTabletOps');
+}
+
+/**
+ * Creates the server result header
+ */
+function createResultsHeader() {
+  var caption = [];
+
+  caption.push('<span class="table-caption">Detailed&nbsp;Current&nbsp;' +
+      'Operations</span><br />');
+  caption.push('<span class="table-subcaption">Per-tablet&nbsp;' +
+      'Details</span><br />');
+
+  $('<caption/>', {
+    html: caption.join('')
+  }).appendTo('#perTabletResults');
+
+  var items = [];
+
+  items.push('<th class="firstcell" onclick="sortTable(3,0)">Table&nbsp;</th>');
+  items.push('<th onclick="sortTable(3,1)">Tablet&nbsp;</th>');
+  items.push('<th onclick="sortTable(3,2)">Entries&nbsp;</th>');
+  items.push('<th onclick="sortTable(3,3)">Ingest&nbsp;</th>');
+  items.push('<th onclick="sortTable(3,4)">Query&nbsp;</th>');
+  items.push('<th onclick="sortTable(3,5)">Minor&nbsp;Avg&nbsp;</th>');
+  items.push('<th onclick="sortTable(3,6)">Minor&nbsp;Std&nbsp;Dev&nbsp;</th>');
+  items.push('<th onclick="sortTable(3,7)">Minor&nbsp;Avg&nbsp;e/s&nbsp;</th>');
+  items.push('<th onclick="sortTable(3,8)">Major&nbsp;Avg&nbsp;</th>');
+  items.push('<th onclick="sortTable(3,9)">Major&nbsp;Std&nbsp;Dev&nbsp;</th>');
+  items.push('<th onclick="sortTable(3,10)">Major&nbsp;' +
+      'Avg&nbsp;e/s&nbsp;</th>');
+
+  $('<tr/>', {
+    html: items.join('')
+  }).appendTo('#perTabletResults');
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0ca5cd33/server/monitor/src/main/resources/resources/show.js
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/resources/show.js b/server/monitor/src/main/resources/resources/show.js
new file mode 100644
index 0000000..bae71f8
--- /dev/null
+++ b/server/monitor/src/main/resources/resources/show.js
@@ -0,0 +1,165 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You 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.
+*/
+var id;
+/**
+ * Makes the REST calls, generates the tables with the new information
+ */
+function refreshTraceShow() {
+  $.ajaxSetup({
+    async: false
+  });
+  getTraceShow(id);
+  $.ajaxSetup({
+    async: true
+  });
+  refreshTraceShowTable();
+}
+
+/**
+ * Used to redraw the page
+ */
+function refresh() {
+  refreshTraceShow();
+}
+
+/**
+ * Generates the trace show table
+ */
+function refreshTraceShowTable() {
+  clearTable('trace');
+  $('#trace caption span span').remove();
+  var data = sessionStorage.traceShow === undefined ?
+      [] : JSON.parse(sessionStorage.traceShow);
+
+  if (data.traces.length !== 0) {
+    var date = new Date(data.start);
+    $('#caption').append('<span>' + date.toLocaleString() + '</span>');
+
+    $.each(data.traces, function(key, val) {
+      var id = val.spanID.toString(16);
+      var items = [];
+
+      items.push('<tr>');
+      items.push('<td class="right">' + val.time + '+</td>');
+      items.push('<td class="left">' + val.start + '</td>');
+      items.push('<td style="text-indent: ' + val.level + '0px">' +
+          val.location + '</td>');
+      items.push('<td>' + val.name + '</td>');
+
+      if (val.addlData.data.length !== 0 ||
+          val.addlData.annotations.length !== 0) {
+
+        items.push('<td><input type="checkbox" id="' + id +
+            '_checkbox" onclick="toggle(\'' + id + '\')"></td>');
+        items.push('</tr>');
+        items.push('<tr id="' + id + '" style="display:none">');
+        items.push('<td colspan="5">');
+        items.push('<table class="table table-bordered table-striped' +
+            ' table-condensed">');
+
+        if (val.addlData.data.length !== 0) {
+          items.push('<tr><th>Key</th><th>Value</th></tr>');
+
+          $.each(val.addlData.data, function(key2, val2) {
+            items.push('<tr><td>' + val2.key + '</td><td>' + val2.value +
+                '</td></tr>');
+          });
+        }
+
+        if (val.addlData.annotations.length !== 0) {
+          items.push('<tr><th>Annotation</th><th>Time Offset</th></tr>');
+
+          $.each(val.addlData.annotations, function(key2, val2) {
+            items.push('<tr><td>' + val2.annotation + '</td><td>' + val2.time +
+                '</td></tr>');
+          });
+        }
+
+        items.push('</table>');
+        items.push('</td>');
+      } else {
+        items.push('<td></td>');
+      }
+
+      items.push('</tr>');
+
+      $('#trace').append(items.join(''));
+    });
+  } else {
+      var items = [];
+      items.push('<tr>');
+      items.push('<td class="center" colspan="5"><i>No trace information for ID ' +
+      id + '</i></td>');
+      items.push('</tr>');
+      $('#trace').append(items.join(''));
+  }
+
+}
+
+/**
+ * Sorts the trace table on the selected column
+ *
+ * @param {number} n Column number to sort by
+ */
+function sortTable(n) {
+  if (sessionStorage.tableColumnSort !== undefined &&
+      sessionStorage.tableColumnSort == n &&
+      sessionStorage.direction !== undefined) {
+    direction = sessionStorage.direction === 'asc' ? 'desc' : 'asc';
+  } else {
+    direction = sessionStorage.direction === undefined ?
+        'asc' : sessionStorage.direction;
+  }
+  sessionStorage.tableColumnSort = n;
+  sortTables('trace', direction, n);
+}
+
+/**
+ * Create tooltip for table column information
+ */
+$(function() {
+  $(document).tooltip();
+});
+
+/**
+ * Creates the trace show header
+ *
+ * @param {string} ID ID of the trace
+ */
+function createHeader(ID) {
+  id = ID;
+  var caption = [];
+
+  caption.push('<span id="caption" class="table-caption">Trace ' + id +
+      ' started at<br></span>');
+
+  $('<caption/>', {
+    html: caption.join('')
+  }).appendTo('#trace');
+
+  var items = [];
+
+  items.push('<th>Time&nbsp;</th>');
+  items.push('<th>Start&nbsp;</th>');
+  items.push('<th>Service@Location&nbsp;</th>');
+  items.push('<th>Name&nbsp;</th>');
+  items.push('<th>Addl&nbsp;Data&nbsp;</th>');
+
+  $('<tr/>', {
+    html: items.join('')
+  }).appendTo('#trace');
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0ca5cd33/server/monitor/src/main/resources/resources/sidebar.js
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/resources/sidebar.js b/server/monitor/src/main/resources/resources/sidebar.js
new file mode 100644
index 0000000..ca8aa7c
--- /dev/null
+++ b/server/monitor/src/main/resources/resources/sidebar.js
@@ -0,0 +1,133 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You 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.
+*/
+
+/**
+ * Creates the initial sidebar
+ */
+$(document).ready(function() {
+  refreshSidebar();
+});
+
+/**
+ * Makes the REST calls, generates the sidebar with the new information
+ */
+function refreshSidebar() {
+  $.ajaxSetup({
+    async: false
+  });
+  getStatus();
+  $.ajaxSetup({
+    async: true
+  });
+  refreshSideBarNotifications();
+}
+
+/**
+ * Used to redraw the navbar
+ */
+function refreshNavBar() {
+  refreshSidebar();
+}
+
+/**
+ * Generates the sidebar notifications for servers and logs
+ */
+function refreshSideBarNotifications() {
+
+  $('#currentDate').html(Date());
+
+  var data = sessionStorage.status === undefined ?
+      undefined : JSON.parse(sessionStorage.status);
+
+  // Setting individual status notification
+  if (data.masterStatus == 'OK') {
+    $('#masterStatusNotification').removeClass('error').addClass('normal');
+  } else {
+    $('#masterStatusNotification').removeClass('normal').addClass('error');
+  }
+  if (data.tServerStatus == 'OK') {
+    $('#serverStatusNotification').removeClass('error').removeClass('warning').
+        addClass('normal');
+  } else if (data.tServerStatus == 'WARN') {
+    $('#serverStatusNotification').removeClass('error').removeClass('normal').
+        addClass('warning');
+  } else {
+    $('#serverStatusNotification').removeClass('normal').removeClass('warning').
+        addClass('error');
+  }
+  if (data.gcStatus == 'OK') {
+    $('#gcStatusNotification').removeClass('error').addClass('normal');
+  } else {
+    $('#gcStatusNotification').addClass('error').removeClass('normal');
+  }
+
+  // Setting overall status notification
+  if (data.masterStatus == 'OK' &&
+      data.tServerStatus == 'OK' &&
+      data.gcStatus == 'OK') {
+    $('#statusNotification').removeClass('error').removeClass('warning').
+        addClass('normal');
+  } else if (data.masterStatus == 'ERROR' ||
+      data.tServerStatus == 'ERROR' ||
+      data.gcStatus == 'ERROR') {
+    $('#statusNotification').removeClass('normal').removeClass('warning').
+        addClass('error');
+  } else if (data.tServerStatus == 'WARN') {
+    $('#statusNotification').removeClass('normal').removeClass('error').
+        addClass('warning');
+  }
+
+  // Setting individual logs notifications
+  // Color
+  if (data.logNumber > 0) {
+    if (data.logsHaveError) {
+      $('#recentLogsNotifications').removeClass('warning').addClass('error');
+    } else {
+      $('#recentLogsNotifications').removeClass('error').addClass('warning');
+    }
+  } else {
+    $('#recentLogsNotifications').removeClass('error').removeClass('warning');
+  }
+  // Number
+  var logNumber = data.logNumber > 99 ? '99+' : data.logNumber;
+  $('#recentLogsNotifications').html(logNumber);
+  // Color
+  if (data.problemNumber > 0) {
+    $('#tableProblemsNotifications').addClass('error');
+  } else {
+    $('#tableProblemsNotifications').removeClass('error');
+  }
+  // Number
+  var problemNumber = data.problemNumber > 99 ? '99+' : data.problemNumber;
+  $('#tableProblemsNotifications').html(problemNumber);
+  // Setting overall logs notifications
+  // Color
+  if (data.logNumber > 0 || data.problemNumber > 0) {
+    if (data.logsHaveError || data.problemNumber > 0) {
+      $('#errorsNotification').removeClass('warning').addClass('error');
+    } else {
+      $('#errorsNotification').removeClass('error').addClass('warning');
+    }
+  } else {
+    $('#errorsNotification').removeClass('error').removeClass('warning');
+  }
+
+  // Number
+  var totalNumber = data.logNumber + data.problemNumber > 99 ?
+      '99+' : data.logNumber + data.problemNumber;
+  $('#errorsNotification').html(totalNumber);
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0ca5cd33/server/monitor/src/main/resources/resources/summary.js
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/resources/summary.js b/server/monitor/src/main/resources/resources/summary.js
new file mode 100644
index 0000000..a451f2f
--- /dev/null
+++ b/server/monitor/src/main/resources/resources/summary.js
@@ -0,0 +1,152 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You 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.
+*/
+var minutes;
+/**
+ * Makes the REST calls, generates the tables with the new information
+ */
+function refreshSummary() {
+  $.ajaxSetup({
+    async: false
+  });
+  getTraceSummary(minutes);
+  $.ajaxSetup({
+    async: true
+  });
+  refreshTraceSummaryTable(minutes);
+}
+
+/**
+ * Used to redraw the page
+ */
+function refresh() {
+  refreshSummary();
+}
+
+/**
+ * Generates the trace summary table
+ *
+ * @param {string} minutes Minutes to display traces
+ */
+function refreshTraceSummaryTable(minutes) {
+  clearTable('traceSummary');
+
+  var data = sessionStorage.traceSummary === undefined ?
+      [] : JSON.parse(sessionStorage.traceSummary);
+
+  if (data.length === 0 || data.recentTraces.length === 0) {
+    var items = [];
+    items.push('<td class="center" colspan="6"><i>No traces in the last ' +
+        minutes + ' minute(s)</i></td>');
+    $('<tr/>', {
+      html: items.join('')
+    }).appendTo('#traceSummary');
+  } else {
+    $.each(data.recentTraces, function(key, val) {
+
+      var items = [];
+
+      items.push('<td class="firstcell left"><a href="/trace/listType?type=' +
+          val.type + '&minutes=' + minutes + '">' + val.type + '</a></td>');
+      items.push('<td class ="right">' + bigNumberForQuantity(val.total) +
+          '</td>');
+      items.push('<td class="right">' + timeDuration(val.min) + '</td>');
+      items.push('<td class="right">' + timeDuration(val.max) + '</td>');
+      items.push('<td class="right">' + timeDuration(val.avg) + '</td>');
+      items.push('<td class="left">');
+      items.push('<table>');
+      items.push('<tr>');
+
+      $.each(val.histogram, function(key2, val2) {
+        items.push('<td style="width:5em">' + (val2 == 0 ? '-' : val2) +
+            '</td>');
+      });
+      items.push('</tr>');
+      items.push('</table>');
+      items.push('</td>');
+
+      $('<tr/>', {
+        html: items.join('')
+      }).appendTo('#traceSummary');
+
+    });
+  }
+}
+
+/**
+ * Sorts the traceSummary table on the selected column
+ *
+ * @param {number} n Column number to sort by
+ */
+function sortTable(n) {
+  if (sessionStorage.tableColumnSort !== undefined &&
+      sessionStorage.tableColumnSort == n &&
+      sessionStorage.direction !== undefined) {
+    direction = sessionStorage.direction === 'asc' ? 'desc' : 'asc';
+  } else {
+    direction = sessionStorage.direction === undefined ?
+        'asc' : sessionStorage.direction;
+  }
+  sessionStorage.tableColumnSort = n;
+  sortTables('traceSummary', direction, n);
+}
+
+/**
+ * Create tooltip for table column information
+ */
+$(function() {
+  $(document).tooltip();
+});
+
+/**
+ * Creates the trace summary header
+ *
+ * @param {string} min Minutes to display trace
+ */
+function createHeader(min) {
+  minutes = min;
+  var caption = [];
+
+  caption.push('<span class="table-caption">All Traces</span><br />');
+
+  $('<caption/>', {
+    html: caption.join('')
+  }).appendTo('#traceSummary');
+
+  var items = [];
+
+  items.push('<th class="firstcell" title="' + descriptions['Trace Type'] +
+      '">Type&nbsp;</th>');
+
+  items.push('<th title="' + descriptions['Total Spans'] +
+      '">Total&nbsp;</th>');
+
+  items.push('<th title="' + descriptions['Short Span'] +
+      '">min&nbsp;</th>');
+
+  items.push('<th title="' + descriptions['Long Span'] +
+      '">max&nbsp;</th>');
+
+  items.push('<th title="' + descriptions['Avg Span'] +
+      '">avg&nbsp;</th>');
+
+  items.push('<th title="' + descriptions['Histogram'] +
+      '">Histogram&nbsp;</th>');
+
+  $('<tr/>', {
+    html: items.join('')
+  }).appendTo('#traceSummary');
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0ca5cd33/server/monitor/src/main/resources/resources/table.js
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/resources/table.js b/server/monitor/src/main/resources/resources/table.js
new file mode 100644
index 0000000..6e22b72
--- /dev/null
+++ b/server/monitor/src/main/resources/resources/table.js
@@ -0,0 +1,208 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You 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.
+*/
+
+var tableID;
+/**
+ * Makes the REST calls, generates the tables with the new information
+ */
+function refreshTable() {
+  $.ajaxSetup({
+    async: false
+  });
+  getTableServers(tableID);
+  $.ajaxSetup({
+    async: true
+  });
+  refreshTableServersTable();
+}
+
+/**
+ * Used to redraw the page
+ */
+function refresh() {
+  refreshTable();
+}
+
+/**
+ * Generates the table servers table
+ */
+function refreshTableServersTable() {
+  $('#participatingTServers tr:gt(0)').remove();
+
+  var data = sessionStorage.tableServers === undefined ?
+      [] : JSON.parse(sessionStorage.tableServers);
+
+  if (data.length === 0 || data.servers.length === 0) {
+    var items = [];
+    items.push('<td class="center" colspan="13"><i>Empty</i></td>');
+    $('<tr/>', {
+      html: items.join('')
+    }).appendTo('#participatingTServers');
+  } else {
+
+    $.each(data.servers, function(key, val) {
+      var items = [];
+      items.push('<td class="firstcell left" data-value="' + val.hostname +
+          '"><a href="/tservers?s=' + val.id +
+          '">' + val.hostname + '</a></td>');
+
+      items.push('<td class="right" data-value="' + val.tablets +
+          '">' + bigNumberForQuantity(val.tablets) + '</td>');
+
+      items.push('<td class="right" data-value="' + val.lastContact +
+          '">' + timeDuration(val.lastContact) + '</td>');
+
+      items.push('<td class="right" data-value="' + val.entries +
+          '">' + bigNumberForQuantity(val.entries) + '</td>');
+
+      items.push('<td class="right" data-value="' + val.ingest +
+          '">' + bigNumberForQuantity(Math.floor(val.ingest)) + '</td>');
+
+      items.push('<td class="right" data-value="' + val.query +
+          '">' + bigNumberForQuantity(Math.floor(val.query)) + '</td>');
+
+      items.push('<td class="right" data-value="' + val.holdtime +
+          '">' + timeDuration(val.holdtime) + '</td>');
+
+      items.push('<td class="right" data-value="' +
+          (val.compactions.scans.running + val.compactions.scans.queued) +
+          '">' + bigNumberForQuantity(val.compactions.scans.running) +
+          '&nbsp;(' + bigNumberForQuantity(val.compactions.scans.queued) +
+          ')</td>');
+
+      items.push('<td class="right" data-value="' +
+          (val.compactions.minor.running + val.compactions.minor.queued) +
+          '">' + bigNumberForQuantity(val.compactions.minor.running) +
+          '&nbsp;(' + bigNumberForQuantity(val.compactions.minor.queued) +
+          ')</td>');
+
+      items.push('<td class="right" data-value="' +
+          (val.compactions.major.running + val.compactions.major.queued) +
+          '">' + bigNumberForQuantity(val.compactions.major.running) +
+          '&nbsp;(' + bigNumberForQuantity(val.compactions.major.queued) +
+          ')</td>');
+
+      items.push('<td class="right" data-value="' +
+          val.indexCacheHitRate * 100 +
+          '">' + Math.round(val.indexCacheHitRate * 100) + '%</td>');
+
+      items.push('<td class="right" data-value="' + val.dataCacheHitRate * 100 +
+          '">' + Math.round(val.dataCacheHitRate * 100) + '%</td>');
+
+      items.push('<td class="right" data-value="' + val.osload +
+          '">' + bigNumberForQuantity(val.osload) + '</td>');
+
+      $('<tr/>', {
+        html: items.join('')
+      }).appendTo('#participatingTServers');
+
+    });
+    if (data.servers.length === 0) {
+      var items = [];
+      items.push('<td class="center" colspan="13"><i>Empty</i></td>');
+
+      $('<tr/>', {
+        html: items.join('')
+      }).appendTo('#participatingTServers');
+    }
+  }
+}
+
+/**
+ * Sorts the participatingTServers table on the selected column
+ *
+ * @param {number} n Column number to sort by
+ */
+function sortTable(n) {
+  if (!JSON.parse(sessionStorage.namespaceChanged)) {
+    if (sessionStorage.tableColumnSort !== undefined &&
+        sessionStorage.tableColumnSort == n &&
+        sessionStorage.direction !== undefined) {
+      direction = sessionStorage.direction === 'asc' ? 'desc' : 'asc';
+    }
+  } else {
+    direction = sessionStorage.direction === undefined ?
+        'asc' : sessionStorage.direction;
+  }
+  sessionStorage.tableColumnSort = n;
+  sortTables('participatingTServers', direction, n);
+}
+
+/**
+ * Creates the table servers header
+ *
+ * @param {string} table Table Name
+ * @param {string} tabID Table ID
+ */
+function createHeader(table, tabID) {
+  tableID = tabID;
+  var caption = [];
+
+  caption.push('<span class="table-caption">Participating&nbsp;' +
+      'Tablet&nbsp;Servers</span><br />');
+  caption.push('<span class="table-subcaption">' + table + '</span><br />');
+
+  $('<caption/>', {
+    html: caption.join('')
+  }).appendTo('#participatingTServers');
+
+  var items = [];
+
+  items.push('<th class="firstcell" onclick="sortTable(0)">Server&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(1)">Hosted&nbsp;Tablets&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(2)">Last&nbsp;Contact&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(3)" title="' + descriptions['Entries'] +
+      '">Entries&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(4)" title="' + descriptions['Ingest'] +
+      '">Ingest&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(5)" title="' + descriptions['Query'] +
+      '">Query&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(6)" title="' + descriptions['Hold Time'] +
+      '">Hold&nbsp;Time&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(7)" title="' +
+      descriptions['Running Scans'] + '">Running<br />Scans&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(8)" title="' +
+      descriptions['Minor Compactions'] +
+      '">Minor<br />Compactions&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(9)" title="' +
+      descriptions['Major Compactions'] +
+      '">Major<br />Compactions&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(10)" title="' +
+      descriptions['Index Cache Hit Rate'] +
+      '">Index Cache<br />Hit Rate&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(11)" title="' +
+      descriptions['Data Cache Hit Rate'] +
+      '">Data Cache<br />Hit Rate&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(12)" title="' +
+      descriptions['OS Load'] + '">OS&nbsp;Load&nbsp;</th>');
+
+  $('<tr/>', {
+    html: items.join('')
+  }).appendTo('#participatingTServers');
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0ca5cd33/server/monitor/src/main/resources/resources/tables.js
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/resources/tables.js b/server/monitor/src/main/resources/resources/tables.js
new file mode 100644
index 0000000..842f38c
--- /dev/null
+++ b/server/monitor/src/main/resources/resources/tables.js
@@ -0,0 +1,355 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You 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.
+*/
+
+/**
+ * Makes the REST calls, generates the tables with the new information
+ */
+function refreshTables() {
+  $.ajaxSetup({
+    async: false
+  });
+  getNamespaces();
+  $.ajaxSetup({
+    async: true
+  });
+  createNamespacesDropdown();
+  // If the namespaces in sessionStorage is undefined, select all namespaces
+  if (sessionStorage.namespaces === undefined) {
+    sessionStorage.namespaces = '[]';
+    populateTable('*');
+  }
+  populateTable(undefined);
+  sortTable(sessionStorage.tableColumnSort === undefined ?
+      0 : sessionStorage.tableColumnSort);
+}
+
+/**
+ * Used to redraw the page
+ */
+function refresh() {
+  // If tables are in master page, refresh master and tables
+  if (!hasMaster) {
+    refreshTables();
+  } else {
+    refreshMaster();
+    refreshTables();
+  }
+}
+
+var hasMaster = false;
+function toggleMaster(master) {
+  hasMaster = master
+}
+
+/**
+ * Creates listeners for when the namespaces are selected or unselected
+ */
+function namespaceChanged() {
+  var $namespaceSelect = $('#namespaces');
+
+  $namespaceSelect.off();
+
+  $namespaceSelect.on('select2:select', function(e) {
+    var id = e.params === null ? undefined : e.params['data']['id'];
+    populateTable(id);
+  });
+
+  $namespaceSelect.on('select2:unselect', function(e) {
+    var id = e.params === null ? undefined : e.params['data']['id'];
+    populateTable(id);
+  });
+}
+
+/**
+ * Creates the namespaces dropdown menu
+ */
+function createNamespacesDropdown() {
+  var data = JSON.parse(NAMESPACES).namespaces;
+  var caption = [];
+
+  caption.push('<span class="table-caption">Table&nbsp;List</span><br />');
+
+  $('<caption/>', {
+    html: caption.join('')
+  }).appendTo('#filters');
+
+  var data2 = [{ id: '*', text: '* (All Tables)'}];
+  $.each(data, function(key, val) {
+    var namespace = val === '' ? '- (DEFAULT)' : val;
+    data2.push({id: val === '' ? '-' : val, text: namespace});
+  });
+
+  $('#namespaces').select2({
+    data: data2,
+    allowClear: true
+  });
+  namespaceChanged();
+}
+
+/**
+ * Creates the tables table with the selected namespace
+ *
+ * @param {string} ns Selected namespace
+ */
+function populateTable(ns) {
+  var tmpArr = sessionStorage.namespaces === undefined ?
+      [] : JSON.parse(sessionStorage.namespaces);
+  sessionStorage.namespaceChanged = true;
+  var namespaces = JSON.parse(NAMESPACES).namespaces;
+
+  // If there is a selected namespace, change the displayed tables
+  if (ns !== undefined) {
+    /*
+     * If the namespace has not been selected,
+     * add it to the namespace array, otherwise remove it
+     */
+    if (tmpArr.indexOf(ns) == -1) {
+      /* If the namespace is *, add all namespaces to the array,
+       * otherwise just add the selected namespace
+       */
+      if (ns === '*') {
+        tmpArr = [];
+
+        tmpArr.push('*');
+        $.each(namespaces, function(key, val) {
+          tmpArr.push(val === '' ? '-' : val);
+        });
+      } else {
+        tmpArr.push(ns);
+        /*
+         * If the namespace array is the same size
+         * as the total number of namespaces, add *
+         */
+        if (tmpArr.length == namespaces.length) {
+          tmpArr.push('*');
+        }
+      }
+    } else {
+      /*
+       * If * is in the array, and the selected
+       * namespace is not *, remove * from array
+       */
+      if (tmpArr.indexOf('*') !== -1 && ns !== '*') {
+        tmpArr.splice(tmpArr.indexOf('*'), 1);
+      }
+      /*
+       * If the selected namespace is not *,
+       * remove it from array, otherwise, remove all
+       */
+      if (ns !== '*') {
+        tmpArr.splice(tmpArr.indexOf(ns), 1);
+      } else {
+        tmpArr = [];
+      }
+    }
+  }
+
+  $('#namespaces').select2().val(tmpArr).trigger('change'); // TODO Fix this, causes null dataAdapter
+
+  sessionStorage.namespaces = JSON.stringify(tmpArr);
+
+  $.ajaxSetup({
+    async: false
+  });
+  getNamespaceTables(tmpArr);
+  $.ajaxSetup({
+    async: true
+  });
+
+  var data = sessionStorage.tables === undefined ?
+      [] : JSON.parse(sessionStorage.tables);
+  clearTable('tableList');
+
+  var numTables = 0;
+
+  $.each(data.tables, function(keyT, tab) {
+    // Only add tables that are part of the array, or all if * is in the array
+    if (tmpArr.indexOf(tab.namespace === '' ? '-' : tab.namespace) !== -1 ||
+        tmpArr.indexOf('*') !== -1) {
+      $.each(tab.table, function(key, val) {
+
+        var row = [];
+        row.push('<td class="firstcell left" data-value="' + val.tablename +
+            '"><a href="/tables/' + val.tableId +
+            '">' + val.tablename + '</a></td>');
+        row.push('<td class="center" data-value="' + val.tableState +
+            '"><span>' + val.tableState + '</span></td>');
+
+        if (val.tableState === 'ONLINE') {
+          row.push('<td class="right" data-value="' + val.tablets +
+              '">' + bigNumberForQuantity(val.tablets) + '</td>');
+
+          row.push('<td class="right" data-value="' + val.offlineTablets +
+              '">' + bigNumberForQuantity(val.offlineTablets) + '</td>');
+
+          row.push('<td class="right" data-value="' + val.recs + '">' +
+              bigNumberForQuantity(val.recs) + '</td>');
+
+          row.push('<td class="right" data-value="' + val.recsInMemory +
+              '">' + bigNumberForQuantity(val.recsInMemory) + '</td>');
+
+          row.push('<td class="right" data-value="' + val.ingest +
+              '">' + bigNumberForQuantity(Math.floor(val.ingest)) + '</td>');
+
+          row.push('<td class="right" data-value="' + val.entriesRead +
+              '">' + bigNumberForQuantity(Math.floor(val.entriesRead)) +
+              '</td>');
+
+          row.push('<td class="right" data-value="' + val.entriesReturned +
+              '">' + bigNumberForQuantity(Math.floor(val.entriesReturned)) +
+              '</td>');
+
+          row.push('<td class="right" data-value="' + val.holdTime + '">' +
+              timeDuration(val.holdTime) + '</td>');
+
+          if (val.scans === null) {
+            row.push('<td class="right" data-value="-">-</td>');
+          } else {
+            row.push('<td class="right" data-value="' +
+                (val.scans.running + val.scans.queued) + '">' +
+                bigNumberForQuantity(val.scans.running) + '&nbsp;(' +
+                bigNumberForQuantity(val.scans.queued) + ')</td>');
+          }
+          if (val.minorCompactions === null) {
+            row.push('<td class="right" data-value="-">-</td>');
+          } else {
+            row.push('<td class="right" data-value="' +
+                (val.minorCompactions.running + val.minorCompactions.queued) +
+                '">' + bigNumberForQuantity(val.minorCompactions.running) +
+                '&nbsp;(' + bigNumberForQuantity(val.minorCompactions.queued) +
+                ')</td>');
+          }
+          if (val.majorCompactions === null) {
+            row.push('<td class="right" data-value="-">-</td>');
+          } else {
+            row.push('<td class="right" data-value="' +
+                (val.majorCompactions.running + val.majorCompactions.queued) +
+                '">' + bigNumberForQuantity(val.majorCompactions.running) +
+                '&nbsp;(' + bigNumberForQuantity(val.majorCompactions.queued) +
+                ')</td>');
+          }
+        } else {
+          row.push('<td class="right" data-value="-">-</td>');
+          row.push('<td class="right" data-value="-">-</td>');
+          row.push('<td class="right" data-value="-">-</td>');
+          row.push('<td class="right" data-value="-">-</td>');
+          row.push('<td class="right" data-value="-">-</td>');
+          row.push('<td class="right" data-value="-">-</td>');
+          row.push('<td class="right" data-value="-">-</td>');
+          row.push('<td class="right" data-value="-">&mdash;</td>');
+          row.push('<td class="right" data-value="-">-</td>');
+          row.push('<td class="right" data-value="-">-</td>');
+          row.push('<td class="right" data-value="-">-</td>');
+        }
+
+        $('<tr/>', {
+          html: row.join(''),
+          id: tab.namespace === '' ? '-' : tab.namespace
+        }).appendTo('#tableList');
+
+        numTables++;
+      });
+    }
+  });
+  /*
+   * If there are no selected namespaces,
+   * or selected namespaces result in no tables, display empty
+   */
+  if (numTables === 0) {
+    var item = '<td class="center" colspan="13"><i>Empty</i></td>';
+
+    $('<tr/>', {
+      html: item
+    }).appendTo('#tableList');
+  }
+}
+
+/**
+ * Sorts the tableList table on the selected column
+ *
+ * @param {number} n Column number to sort by
+ */
+function sortTable(n) {
+  if (!JSON.parse(sessionStorage.namespaceChanged)) {
+    if (sessionStorage.tableColumnSort !== undefined &&
+        sessionStorage.tableColumnSort == n &&
+        sessionStorage.direction !== undefined) {
+      direction = sessionStorage.direction === 'asc' ? 'desc' : 'asc';
+    } else {
+      direction = sessionStorage.direction === undefined ?
+          'asc' : sessionStorage.direction;
+    }
+  } else {
+    direction = sessionStorage.direction === undefined ?
+        'asc' : sessionStorage.direction;
+  }
+
+  sessionStorage.tableColumnSort = n;
+
+  sortTables('tableList', direction, n);
+  sessionStorage.namespaceChanged = false;
+}
+
+/**
+ * Create tooltip for table column information
+ */
+$(function() {
+  $(document).tooltip();
+});
+
+/**
+ * Creates the tables header
+ */
+function createTablesHeader() {
+  var items = [];
+
+  items.push('<th class="firstcell" onclick="sortTable(0)">' +
+      'Table&nbsp;Name&nbsp;</th>');
+
+  items.push('<th onclick="sortTable(1)">State&nbsp;</th>');
+  items.push('<th onclick="sortTable(2)" title="' +
+      descriptions['# Tablets'] + '">#&nbsp;Tablets&nbsp;</th>');
+  items.push('<th onclick="sortTable(3)" title="' +
+      descriptions['# Offline Tablets'] +
+      '">#&nbsp;Offline<br />Tablets&nbsp;</th>');
+  items.push('<th onclick="sortTable(4)" title="' +
+      descriptions['Entries'] + '">Entries&nbsp;</th>');
+  items.push('<th onclick="sortTable(5)" title="' +
+      descriptions['Entries in Memory'] +
+      '">Entries<br />In&nbsp;Memory&nbsp;</th>');
+  items.push('<th onclick="sortTable(6)" title="' +
+      descriptions['Ingest'] + '">Ingest&nbsp;</th>');
+  items.push('<th onclick="sortTable(7)" title="' +
+      descriptions['Entries Read'] + '">Entries<br />Read&nbsp;</th>');
+  items.push('<th onclick="sortTable(8)" title="' +
+      descriptions['Entries Returned'] +
+      '">Entries<br />Returned&nbsp;</th>');
+  items.push('<th onclick="sortTable(9)" title="' +
+      descriptions['Hold Time'] + '">Hold&nbsp;Time&nbsp;</th>');
+  items.push('<th onclick="sortTable(10)" title="' +
+      descriptions['Running Scans'] + '">Running<br />Scans&nbsp;</th>');
+  items.push('<th onclick="sortTable(11)" title="' +
+      descriptions['Minor Compactions'] +
+      '">Minor<br />Compactions&nbsp;</th>');
+  items.push('<th onclick="sortTable(12)" title="' +
+      descriptions['Major Compactions'] +
+      '">Major<br />Compactions&nbsp;</th>');
+
+  $('<tr/>', {
+    html: items.join('')
+  }).appendTo('#tableList');
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0ca5cd33/server/monitor/src/main/resources/resources/tservers.js
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/resources/tservers.js b/server/monitor/src/main/resources/resources/tservers.js
new file mode 100644
index 0000000..d8c109a
--- /dev/null
+++ b/server/monitor/src/main/resources/resources/tservers.js
@@ -0,0 +1,320 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You 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.
+*/
+
+/**
+ * Creates tservers initial table
+ */
+$(document).ready(function() {
+  createHeader();
+  refreshTServers();
+});
+
+/**
+ * Makes the REST calls, generates the tables with the new information
+ */
+function refreshTServers() {
+  $.ajaxSetup({
+    async: false
+  });
+  getTServers();
+  $.ajaxSetup({
+    async: true
+  });
+  refreshBadTServersTable();
+  refreshDeadTServersTable();
+  refreshTServersTable();
+}
+
+/**
+ * Used to redraw the page
+ */
+function refresh() {
+  refreshTServers();
+}
+
+/**
+ * Generates the tservers table
+ */
+function refreshBadTServersTable() {
+  var data = sessionStorage.tservers === undefined ?
+      [] : JSON.parse(sessionStorage.tservers);
+
+  $('#badtservers tr').remove();
+  $('#badtservers caption').remove();
+
+  if (data.length === 0 || data.badServers.length === 0) {
+
+    $('#badtservers').hide();
+  } else {
+
+    $('#badtservers').show();
+
+    var caption = [];
+
+    caption.push('<span class="table-caption">Non-Functioning&nbsp;' +
+        'Tablet&nbsp;Servers</span><br />');
+    caption.push('<span class="table-subcaption">The following tablet' +
+        ' servers reported a status other than Online</span><br />');
+
+    $('<caption/>', {
+      html: caption.join('')
+    }).appendTo('#badtservers');
+
+    var items = [];
+
+    items.push('<th class="firstcell" onclick="sortTable(0)">' +
+        'Tablet&nbsp;Server&nbsp;</th>');
+    items.push('<th onclick="sortTable(1)">Tablet&nbsp;Server&nbsp;' +
+        'Status&nbsp;</th>');
+
+    $('<tr/>', {
+      html: items.join('')
+    }).appendTo('#badtservers');
+
+    $.each(data.badServers, function(key, val) {
+      var items = [];
+      items.push('<td class="firstcell left" data-value="' + val.id +
+          '">' + val.id + '</td>');
+      items.push('<td class="right" data-value="' + val.status +
+          '">' + val.status + '</td>');
+
+      $('<tr/>', {
+        html: items.join('')
+      }).appendTo('#badtservers');
+    });
+  }
+}
+
+/**
+ * Generates the deadtservers table
+ */
+function refreshDeadTServersTable() {
+  var data = sessionStorage.tservers === undefined ?
+      [] : JSON.parse(sessionStorage.tservers);
+
+  $('#deadtservers tr').remove();
+  $('#deadtservers caption').remove();
+
+  if (data.length === 0 || data.deadServers.length === 0) {
+
+    $('#deadtservers').hide();
+  } else {
+
+    $('#deadtservers').show();
+
+
+    var caption = [];
+
+    caption.push('<span class="table-caption">Dead&nbsp;' +
+        'Tablet&nbsp;Servers</span><br />');
+    caption.push('<span class="table-subcaption">The following' +
+        ' tablet servers are no longer reachable.</span><br />');
+
+    $('<caption/>', {
+      html: caption.join('')
+    }).appendTo('#deadtservers');
+
+    var items = [];
+
+    items.push('<th class="firstcell" onclick="sortTable(0)">' +
+        'Server&nbsp;</th>');
+    items.push('<th onclick="sortTable(1)">Last&nbsp;Updated&nbsp;</th>');
+    items.push('<th onclick="sortTable(2)">Event&nbsp;</th>');
+    items.push('<th>Clear</th>');
+
+    $('<tr/>', {
+      html: items.join('')
+    }).appendTo('#deadtservers');
+
+    $.each(data.deadServers, function(key, val) {
+      var items = [];
+      items.push('<td class="firstcell left" data-value="' + val.server +
+          '">' + val.server + '</td>');
+
+      var date = new Date(val.lastStatus);
+      date = date.toLocaleString().split(' ').join('&nbsp;');
+      items.push('<td class="right" data-value="' + val.lastStatus +
+          '">' + date + '</td>');
+      items.push('<td class="right" data-value="' + val.status +
+          '">' + val.status + '</td>');
+      items.push('<td class="right"> ' +
+          '<a href="javascript:clearDeadTServers(\'' +
+          val.server + '\');">clear</a></td>');
+
+      $('<tr/>', {
+        html: items.join('')
+      }).appendTo('#deadtservers');
+    });
+  }
+}
+
+/**
+ * Makes the REST POST call to clear dead table server
+ *
+ * @param {string} server Dead TServer to clear
+ */
+function clearDeadTServers(server) {
+  clearDeadServers(server);
+  refreshTServers();
+  refreshNavBar();
+}
+
+/**
+ * Generates the tserver table
+ */
+function refreshTServersTable() {
+  var data = sessionStorage.tservers === undefined ?
+      [] : JSON.parse(sessionStorage.tservers);
+
+  $('#tservers tr:gt(0)').remove();
+
+  if (data.length === 0 || data.servers.length === 0) {
+    var item = '<td class="center" colspan="13"><i>Empty</i></td>';
+
+    $('<tr/>', {
+      html: item
+    }).appendTo('#tservers');
+  } else {
+
+    $.each(data.servers, function(key, val) {
+      var items = [];
+      items.push('<td class="firstcell left" data-value="' + val.hostname +
+          '"><a href="/tservers?s=' + val.id + '">' + val.hostname +
+          '</a></td>');
+
+      items.push('<td class="right" data-value="' + val.tablets +
+          '">' + bigNumberForQuantity(val.tablets) + '</td>');
+
+      items.push('<td class="right" data-value="' + val.lastContact +
+          '">' + timeDuration(val.lastContact) + '</td>');
+
+      items.push('<td class="right" data-value="' + val.entries +
+          '">' + bigNumberForQuantity(val.entries) + '</td>');
+
+      items.push('<td class="right" data-value="' + val.ingest +
+          '">' + bigNumberForQuantity(Math.floor(val.ingest)) + '</td>');
+
+      items.push('<td class="right" data-value="' + val.query +
+          '">' + bigNumberForQuantity(Math.floor(val.query)) + '</td>');
+
+      items.push('<td class="right" data-value="' + val.holdtime +
+          '">' + timeDuration(val.holdtime) + '</td>');
+
+      items.push('<td class="right" data-value="' +
+          (val.compactions.scans.running + val.compactions.scans.queued) +
+          '">' + bigNumberForQuantity(val.compactions.scans.running) +
+          '&nbsp;(' + bigNumberForQuantity(val.compactions.scans.queued) +
+          ')</td>');
+
+      items.push('<td class="right" data-value="' +
+          (val.compactions.minor.running + val.compactions.minor.queued) +
+          '">' + bigNumberForQuantity(val.compactions.minor.running) +
+          '&nbsp;(' + bigNumberForQuantity(val.compactions.minor.queued) +
+          ')</td>');
+
+      items.push('<td class="right" data-value="' +
+          (val.compactions.major.running + val.compactions.major.queued) +
+          '">' + bigNumberForQuantity(val.compactions.major.running) +
+          '&nbsp;(' + bigNumberForQuantity(val.compactions.major.queued) +
+          ')</td>');
+
+      items.push('<td class="right" data-value="' +
+          val.indexCacheHitRate * 100 + '">' +
+          Math.round(val.indexCacheHitRate * 100) +
+          '%</td>');
+
+      items.push('<td class="right" data-value="' + val.dataCacheHitRate * 100 +
+          '">' + Math.round(val.dataCacheHitRate * 100) +
+          '%</td>');
+
+      items.push('<td class="right" data-value="' + val.osload +
+          '">' + bigNumberForQuantity(val.osload) + '</td>');
+
+      $('<tr/>', {
+        html: items.join('')
+      }).appendTo('#tservers');
+    });
+  }
+}
+
+/**
+ * Sorts the tservers table on the selected column
+ *
+ * @param {number} n Column number to sort by
+ */
+function sortTable(n) {
+  if (sessionStorage.tableColumnSort !== undefined &&
+      sessionStorage.tableColumnSort == n &&
+      sessionStorage.direction !== undefined) {
+    direction = sessionStorage.direction === 'asc' ? 'desc' : 'asc';
+  } else {
+    direction = sessionStorage.direction === undefined ?
+        'asc' : sessionStorage.direction;
+  }
+  sessionStorage.tableColumnSort = n;
+  sortTables('tservers', direction, n);
+}
+
+/**
+ * Creates the tservers header
+ */
+function createHeader() {
+  var caption = [];
+
+  caption.push('<span class="table-caption">Tablet&nbsp;Servers</span><br />');
+  caption.push('<span class="table-subcaption">Click on the ' +
+      '<span style="color: #0000ff;">server address</span> to ' +
+      'view detailed performance statistics for that server.</span><br />');
+
+  $('<caption/>', {
+    html: caption.join('')
+  }).appendTo('#tservers');
+
+  var items = [];
+
+  items.push('<th class="firstcell" onclick="sortTable(0)">Server&nbsp;</th>');
+  items.push('<th onclick="sortTable(1)">Hosted&nbsp;Tablets&nbsp;</th>');
+  items.push('<th onclick="sortTable(2)">Last&nbsp;Contact&nbsp;</th>');
+  items.push('<th onclick="sortTable(3)" title="' +
+      descriptions['Entries'] + '">Entries&nbsp;</th>');
+  items.push('<th onclick="sortTable(4)" title="' +
+      descriptions['Ingest'] + '">Ingest&nbsp;</th>');
+  items.push('<th onclick="sortTable(5)" title="' +
+      descriptions['Query'] + '">Query&nbsp;</th>');
+  items.push('<th onclick="sortTable(6)" title="' +
+      descriptions['Hold Time'] + '">Hold&nbsp;Time&nbsp;</th>');
+  items.push('<th onclick="sortTable(7)" title="' +
+      descriptions['Running Scans'] + '">Running<br />Scans&nbsp;</th>');
+  items.push('<th onclick="sortTable(8)" title="' +
+      descriptions['Minor Compactions'] +
+      '">Minor<br />Compactions&nbsp;</th>');
+  items.push('<th onclick="sortTable(9)" title="' +
+      descriptions['Major Compactions'] +
+      '">Major<br />Compactions&nbsp;</th>');
+  items.push('<th onclick="sortTable(10)" title="' +
+      descriptions['Index Cache Hit Rate'] +
+      '">Index Cache<br />Hit Rate&nbsp;</th>');
+  items.push('<th onclick="sortTable(11)" title="' +
+      descriptions['Data Cache Hit Rate'] +
+      '">Data Cache<br />Hit Rate&nbsp;</th>');
+  items.push('<th onclick="sortTable(12)" title="' +
+      descriptions['OS Load'] + '">OS&nbsp;Load&nbsp;</th>');
+
+  $('<tr/>', {
+    html: items.join('')
+  }).appendTo('#tservers');
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0ca5cd33/server/monitor/src/main/resources/resources/up.gif
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/resources/up.gif b/server/monitor/src/main/resources/resources/up.gif
new file mode 100644
index 0000000..b272cbb
Binary files /dev/null and b/server/monitor/src/main/resources/resources/up.gif differ

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0ca5cd33/server/monitor/src/main/resources/resources/vis.js
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/resources/vis.js b/server/monitor/src/main/resources/resources/vis.js
new file mode 100644
index 0000000..bcf5327
--- /dev/null
+++ b/server/monitor/src/main/resources/resources/vis.js
@@ -0,0 +1,506 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+// Server Stats
+var statNames = {}, maxStatValues = {}, adjustMax = {}, significance = {};
+
+/**
+ * Sets the options for the server visualization
+ *
+ * @param {string} shape Circle or Square
+ * @param {number} size Size of shape
+ * @param {string} motion Stat to display motion
+ * @param {string} color Stat to display color
+ */
+function setOptions(shape, size, motion, color) {
+  var data = sessionStorage.serverStats === undefined ?
+      {} : JSON.parse(sessionStorage.serverStats);
+  $('#motion').empty();
+  $('#color').empty();
+
+  $.each(data.serverStats, function(key, val) {
+    var item = val.description;
+
+    $('#motion').append('<option ' + (motion === val.name ? 'selected' : '') +
+        '>' + item + '</option>');
+    $('#color').append('<option ' + (color === val.name ? 'selected' : '') +
+        '>' + item + '</option>');
+
+  });
+  if (speedStatType === undefined) {
+    speedStatType = motion !== undefined || motion !== '' ? motion : '';
+    speedDisabled = motion !== '' ? false : true;
+  }
+  if (speedStatType !== motion && motion !== undefined &&
+      motion !== 'osload' && motion !== '') {
+    speedStatType = motion;
+    speedDisabled = false;
+  }
+  if (colorStatType === undefined) {
+    colorStatType = color !== undefined ? color : 'osload';
+  }
+  if (colorStatType !== color && color !== undefined) {
+    colorStatType = color;
+  }
+}
+
+/**
+ * Sets the stats values from the REST call
+ */
+function setStats() {
+
+  var data = JSON.parse(sessionStorage.serverStats);
+
+  $.each(data.serverStats, function(key, val) {
+    statNames[val.name] = val.derived;
+    maxStatValues[val.name] = val.max;
+    adjustMax[val.name] = val.adjustMax;
+    significance[val.name] = val.significance;
+  });
+
+  var numNormalStats = 8;
+}
+
+// size and spacing variables
+var dotSpacing = 10; // spacing between centers of dots (radius)
+var dotPadding = 0.5; // dot padding
+var minDotRadius = 3; // min dot radius
+var maxDotRadius = dotSpacing - dotPadding;
+
+// arrays of information about each dot
+var stats = {'servers': []};
+var dots = new Array(0); // current sizes and change directions
+var mousedDot = -1; // the dot currently under the mouse
+
+var colorPalette = ['#0000CC', '#0014B8', '#0029A3', '#003D8F', '#00527A',
+    '#006666', '#007A52', '#008F3D', '#00A329', '#00B814', '#00CC00',
+    '#14D100', '#29D600', '#3DDB00', '#52E000', '#66E600', '#7AEB00',
+    '#8FF000', '#A3F500', '#B8FA00', '#CCFF00', '#CCFF00', '#CCF200',
+    '#CCE600', '#CCD900', '#CCCC00', '#CCBF00', '#CCB200', '#CCA600',
+    '#CC9900', '#CC8C00', '#CC8000', '#CC7300', '#CC6600', '#CC5900',
+    '#CC4C00', '#CC4000', '#CC3300', '#CC2600', '#CC1A00', '#CC0D00',
+    '#CC0000'];
+
+var nullColor = '#F5F8FA';
+var deadColor = '#B000CC';
+
+// animation variables
+var drawing = false;
+var canvas = document.getElementById('visCanvas');
+var context = canvas.getContext('2d');
+
+// mouse handling for server information display
+document.getElementById('hoverable').addEventListener('mouseover',
+    showId, false);
+document.getElementById('hoverable').addEventListener('mousemove',
+    showId, false);
+document.getElementById('hoverable').addEventListener('mouseout',
+    hideId, false);
+document.getElementById('vishoverinfo').addEventListener('click',
+    goToServer, false);
+canvas.addEventListener('click', goToServer, false);
+
+// initialize settings based on request parameters
+var main = document.getElementById('main');
+var speedStatType;
+var colorStatType;
+var speedDisabled = true;
+var useCircles = true;
+setShape(document.getElementById('shape'));
+setSize(document.getElementById('size'));
+setMotion(document.getElementById('motion'));
+setColor(document.getElementById('color'));
+
+// xml loading variables
+var xmlReturned = true;
+// don't bother allowing for IE 5 or 6 since canvas won't work
+var xmlhttp = new XMLHttpRequest();
+xmlhttp.onreadystatechange = function() {
+  handleNewData();
+};
+
+self.setInterval('getXML()', 5000);
+
+//self.setInterval('drawDots()',20);
+
+window.requestAnimFrame = (function(callback) {
+  return window.requestAnimationFrame ||
+  window.webkitRequestAnimationFrame ||
+  window.mozRequestAnimationFrame ||
+  window.oRequestAnimationFrame ||
+  window.msRequestAnimationFrame ||
+  function(callback) {
+    window.setTimeout(callback, 1000 / 60);
+  };
+})();
+
+function handleNewData() {
+  if (xmlhttp.readyState != 4) {
+    return;
+  }
+  if (xmlhttp.status != 200 || xmlhttp.responseText == null) {
+    xmlReturned = true;
+    return;
+  }
+  var newstats = JSON.parse(xmlhttp.responseText);
+  for (var i in newstats.servers) {
+    for (var s in statNames) {
+      if (statNames[s])
+        continue;
+      newstats.servers[i][s] = Math.max(0, Math.floor(significance[s] *
+          newstats.servers[i][s]) / significance[s]);
+      if (adjustMax[s])
+        maxStatValues[s] = Math.max(newstats.servers[i][s], maxStatValues[s]);
+    }
+  }
+
+  initDerivedInfo(newstats);
+  var oldstats = stats;
+  while (drawing) {}
+  stats = newstats;
+  delete oldstats;
+  xmlReturned = true;
+}
+
+// set max and average
+function setDerivedStats(serverStats) {
+  var avgStat = 0;
+  var maxStat = 0;
+  var maxIndex = 0;
+  for (var s in statNames) {
+    if (statNames[s])
+      continue;
+    normStat = serverStats[s] / maxStatValues[s];
+    if (normStat > 0)
+      avgStat += normStat;
+    if (maxStat < normStat) {
+      maxStat = normStat;
+      maxIndex = s;
+    }
+  }
+  serverStats.allmax = Math.floor(significance.allmax *
+      Math.min(1, maxStat)) / significance.allmax;
+  serverStats.allavg = Math.floor(significance.allavg *
+      avgStat / numNormalStats) / significance.allavg;
+  serverStats.maxStat = maxIndex;
+}
+
+function initDerivedInfo(newstats) {
+  for (var i in newstats.servers) {
+    if ('dead' in newstats.servers[i] || 'bad' in newstats.servers[i]) {
+      continue;
+    }
+    if (i >= dots.length) {
+      dots.push({'size': maxDotRadius, 'growing': false});
+    }
+    setDerivedStats(newstats.servers[i]);
+  }
+}
+
+// construct server info for hover
+function getInfo(serverStats) {
+  var extra = '<strong>' + serverStats.ip + '</strong>';
+  if ('dead' in serverStats || 'bad' in serverStats)
+    return extra;
+  extra = extra + ' (' + serverStats.hostname + ')';
+  var j = 0;
+  for (var s in statNames) {
+    if (j % 4 == 0)
+      extra = extra + '<br>\n';
+    extra = extra + '&nbsp;&nbsp;' + s + ': <strong>' +
+        serverStats[s] + '</strong>';
+    j++;
+  }
+  extra = extra + ' (' + serverStats.maxStat + ')';
+  return extra;
+}
+
+// reload xml
+function getXML() {
+  if (xmlReturned == true) {
+    xmlReturned = false;
+    xmlhttp.open('GET', jsonurl, true);
+    xmlhttp.send();
+  }
+}
+
+// redraw
+function drawDots() {
+  requestAnimFrame(drawDots);
+  var width = Math.ceil(Math.sqrt(stats.servers.length));
+  var height = Math.ceil(stats.servers.length / width);
+  var x;
+  var y;
+  var server;
+  var sizeChange;
+  drawing = true;
+  for (var i in stats.servers) {
+    server = stats.servers[i];
+    x = i % width;
+    y = Math.floor(i / width);
+    if ('bad' in server || 'dead' in server) {
+      strokeDot(x, y, maxDotRadius - 1, deadColor);
+      continue;
+    }
+    if (speedDisabled || Math.floor(dots[i].size) > maxDotRadius) {
+      // check for resize by the user
+      dots[i].size = maxDotRadius;
+    } else if (server[speedStatType] <= 0) {
+      // if not changing size, increase to max radius
+      if (dots[i].size < maxDotRadius)
+        dots[i].size = dots[i].size + 1;
+      if (dots[i].size > maxDotRadius)
+        dots[i].size = maxDotRadius;
+    } else {
+      sizeChange = getStat(i, speedStatType);
+      if (dots[i].growing) {
+        dots[i].size = dots[i].size + sizeChange;
+        if (dots[i].size + sizeChange > maxDotRadius) {
+          dots[i].growing = false;
+        }
+      }
+      else {
+        dots[i].size = dots[i].size - sizeChange;
+        if (dots[i].size - sizeChange < minDotRadius) {
+          dots[i].growing = true;
+        }
+      }
+    }
+    drawDot(x, y, Math.floor(dots[i].size),
+        getColor(getStat(i, colorStatType)));
+  }
+  /*
+   * mousedDot shouldn't be set to an invalid dot,
+   * but stats might have changed since then
+   */
+  if (mousedDot >= 0 && mousedDot < stats.servers.length)
+    document.getElementById('vishoverinfo').innerHTML =
+        getInfo(stats.servers[mousedDot]);
+  drawing = false;
+}
+
+// fill in a few grey dots
+function drawGrid() {
+  context.clearRect(0, 0, canvas.width, canvas.height);
+  for (var i = 0, k = 0; i < canvas.width; i += dotSpacing * 2, k++) {
+    for (var j = 0, l = 0; j < canvas.height; j += dotSpacing * 2, l++) {
+      drawDot(k, l, maxDotRadius, nullColor);
+    }
+  }
+}
+
+// fill a dot specified by indices into dot grid
+function drawDot(i, j, r, c) {
+  var x = i * dotSpacing * 2 + dotSpacing;
+  var y = j * dotSpacing * 2 + dotSpacing;
+  context.clearRect(x - dotSpacing, y - dotSpacing, dotSpacing * 2,
+      dotSpacing * 2);
+  if (useCircles)
+    fillCircle(x, y, r - dotPadding, c);
+  else
+    fillSquare(x - r, y - r, (r - dotPadding) * 2, c);
+}
+
+// stroke a dot specified by indices into dot grid
+function strokeDot(i, j, r, c) {
+  var x = i * dotSpacing * 2 + dotSpacing;
+  var y = j * dotSpacing * 2 + dotSpacing;
+  context.clearRect(x - dotSpacing, y - dotSpacing, dotSpacing * 2,
+      dotSpacing * 2);
+  if (useCircles)
+    strokeCircle(x, y, r - dotPadding, c);
+  else
+    strokeSquare(x - r, y - r, (r - dotPadding) * 2, c);
+}
+
+function getStat(dotIndex, statIndex) {
+  return Math.min(1, stats.servers[dotIndex][statIndex] /
+      maxStatValues[statIndex]);
+}
+
+// translate color between 0 and maxObservedColor into an html color code
+function getColor(normColor) {
+  return colorPalette[Math.round((colorPalette.length - 1) * normColor)];
+}
+
+function strokeCircle(x, y, r, c) {
+  context.strokeStyle = c;
+  context.lineWidth = 2;
+  context.beginPath();
+  context.arc(x, y, r, 0, Math.PI * 2, true);
+  context.closePath();
+  context.stroke();
+}
+
+function fillCircle(x, y, r, c) {
+  context.fillStyle = c;
+  context.beginPath();
+  context.arc(x, y, r, 0, Math.PI * 2, true);
+  context.closePath();
+  context.fill();
+}
+
+function strokeSquare(x, y, d, c) {
+  context.strokeStyle = c;
+  context.lineWidth = 2;
+  context.strokeRect(x, y, d, d);
+}
+
+function fillSquare(x, y, d, c) {
+  context.fillStyle = c;
+  context.fillRect(x, y, d, d);
+}
+
+// callback for shape selection
+function setShape(obj) {
+  switch (obj.selectedIndex) {
+    case 0:
+      useCircles = true;
+      break;
+    case 1:
+      useCircles = false;
+      break;
+    default:
+      useCircles = true;
+  }
+  drawGrid();
+  setState();
+}
+
+// callback for size selection
+function setSize(obj) {
+  switch (obj.selectedIndex) {
+    case 0:
+      dotSpacing = 5;
+      minDotRadius = 1;
+      break;
+    case 1:
+      dotSpacing = 10;
+      minDotRadius = 3;
+      break;
+    case 2:
+      dotSpacing = 20;
+      minDotRadius = 5;
+      break;
+    case 3:
+      dotSpacing = 40;
+      minDotRadius = 7;
+      break;
+    default:
+      dotSpacing = 10;
+      minDotRadius = 3;
+  }
+  maxDotRadius = dotSpacing - dotPadding;
+  drawGrid();
+  setState();
+}
+
+// callback for motion selection
+function setMotion(obj) {
+  if (obj.selectedIndex <= 0) {
+    speedDisabled = true;
+    setState();
+    return;
+  }
+  var i = 0;
+  for (var s in statNames) {
+    if (i == obj.selectedIndex) {
+      speedStatType = s;
+      break;
+    }
+    i++;
+  }
+  speedDisabled = false;
+  setState();
+}
+
+// callback for color selection
+function setColor(obj) {
+  var i = 0;
+  for (var s in statNames) {
+    if (i == obj.selectedIndex) {
+      colorStatType = s;
+      break;
+    }
+    i++;
+  }
+  setState();
+}
+
+// hide server info on mouseout
+function hideId(e) {
+  document.getElementById('vishoverinfo').style.visibility = 'hidden';
+}
+
+// display server info on mouseover
+function showId(e) {
+  var x;
+  var y;
+  if (e.pageX || e.pageY) {
+    x = e.pageX + main.scrollLeft;
+    y = e.pageY + main.scrollTop;
+  }
+  else {
+    // clientX and clientY unimplemented
+    return;
+  }
+  var relx = x - canvas.offsetLeft - main.offsetLeft;
+  var rely = y - canvas.offsetTop - main.offsetTop;
+  var width = Math.ceil(Math.sqrt(stats.servers.length));
+  gotDot = Math.floor(relx / (dotSpacing * 2)) + width *
+      Math.floor(rely / (dotSpacing * 2));
+  mousedDot = -1;
+  if (relx < (width * dotSpacing * 2) && gotDot >= 0 &&
+      gotDot < stats.servers.length) {
+    mousedDot = gotDot;
+    document.getElementById('vishoverinfo').style.left = relx +
+        canvas.offsetLeft;
+    document.getElementById('vishoverinfo').style.top = Math.max(0,
+        rely + canvas.offsetTop - 70);
+    document.getElementById('vishoverinfo').style.visibility = 'visible';
+  }
+  else {
+    document.getElementById('vishoverinfo').style.visibility = 'hidden';
+  }
+}
+
+function setState() {
+  var url = visurl + '?shape=' + (useCircles ? 'circles' : 'squares') +
+      '&size=' + (dotSpacing * 2) + (speedDisabled ? '' :
+      '&motion=' + speedStatType) +
+      '&color=' + colorStatType;
+  window.history.replaceState(window.history.state, 'Server Activity', url);
+
+  setOptions(useCircles ? 'circles' : 'squares', dotSpacing * 2,
+      speedDisabled ? '' : speedStatType, colorStatType);
+}
+
+// go to server page on click
+function goToServer(e) {
+  /*
+   * mousedDot shouldn't be set to an invalid dot,
+   * but stats might have changed since then
+   */
+  if (mousedDot >= 0 && mousedDot < stats.servers.length)
+    window.location = serverurl + stats.servers[mousedDot].ip;
+}
+
+/*window.onload = function() {
+  drawGrid();
+  drawDots();
+  getXML();
+}*/


Mime
View raw message