summaryrefslogtreecommitdiffstats
path: root/oom-app-overlay/src/main/webapp/app/oom/consul
diff options
context:
space:
mode:
Diffstat (limited to 'oom-app-overlay/src/main/webapp/app/oom/consul')
-rw-r--r--oom-app-overlay/src/main/webapp/app/oom/consul/datacenter-health-service.js51
-rw-r--r--oom-app-overlay/src/main/webapp/app/oom/consul/datacenter-table-controller.js103
-rw-r--r--oom-app-overlay/src/main/webapp/app/oom/consul/datacenter_table.html71
-rw-r--r--oom-app-overlay/src/main/webapp/app/oom/consul/node-health-service.js78
-rw-r--r--oom-app-overlay/src/main/webapp/app/oom/consul/node-services-controller.js77
-rw-r--r--oom-app-overlay/src/main/webapp/app/oom/consul/node-table-controller.js118
-rw-r--r--oom-app-overlay/src/main/webapp/app/oom/consul/node_popups.html67
-rw-r--r--oom-app-overlay/src/main/webapp/app/oom/consul/node_table.html78
-rw-r--r--oom-app-overlay/src/main/webapp/app/oom/consul/service-controllers.js366
-rw-r--r--oom-app-overlay/src/main/webapp/app/oom/consul/service-health-service.js145
-rw-r--r--oom-app-overlay/src/main/webapp/app/oom/consul/service_health_table.html93
-rw-r--r--oom-app-overlay/src/main/webapp/app/oom/consul/service_popups.html207
12 files changed, 1454 insertions, 0 deletions
diff --git a/oom-app-overlay/src/main/webapp/app/oom/consul/datacenter-health-service.js b/oom-app-overlay/src/main/webapp/app/oom/consul/datacenter-health-service.js
new file mode 100644
index 0000000..66f934e
--- /dev/null
+++ b/oom-app-overlay/src/main/webapp/app/oom/consul/datacenter-health-service.js
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.factory('DatacenterHealthService', function ($http, $q, $log) {
+ return {
+ /**
+ * Gets one page of objects.
+ * @param {Number} pageNum - page number; e.g., 1
+ * @param {Number} viewPerPage - number of items per page; e.g., 25
+ * @return {JSON} Response object from remote side
+ */
+ getDatacentersHealth: function(pageNum,viewPerPage) {
+ // cache control for IE
+ var cc = "&cc=" + new Date().getTime().toString();
+ return $http({
+ method: 'GET',
+ url: 'healthServices/datacenters?pageNum=' + pageNum + '&viewPerPage=' + viewPerPage + cc,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('DatacentersService.getDatacentersHealth: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('DatacenterService.getDatacentersHealth failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ };
+});
diff --git a/oom-app-overlay/src/main/webapp/app/oom/consul/datacenter-table-controller.js b/oom-app-overlay/src/main/webapp/app/oom/consul/datacenter-table-controller.js
new file mode 100644
index 0000000..f1c8820
--- /dev/null
+++ b/oom-app-overlay/src/main/webapp/app/oom/consul/datacenter-table-controller.js
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.controller('datacenterTableController', function($scope, $log, $modal, DatacenterHealthService) {
+
+ 'use strict';
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ // models for controls on screen
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.currentPageNum = 1;
+ $scope.ecdapp.totalPages = 1;
+ $scope.ecdapp.viewPerPage = 100;
+ $scope.ecdapp.viewPerPageOptions = [ {
+ index : 0,
+ value : 50
+ }, {
+ index : 1,
+ value : 100
+ }, {
+ index : 2,
+ value : 500
+ }, {
+ index : 3,
+ value : 1000
+ }, {
+ index : 4,
+ value : 2500
+ } ];
+ // other
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.isDataLoading = true;
+ $scope.ecdapp.isRequestFailed = false;
+
+ /**
+ * Answers an array of the specified size - makes Angular iteration easy.
+ */
+ $scope.ecdapp.buildArraySizeN = function(num) {
+ // $log.debug("buildArraySizeN: invoked with " + num);
+ return new Array(num);
+ }
+
+ /**
+ * Loads the table. Interprets the remote controller's response and copies
+ * to scope variables. The response is either list to be assigned to
+ * tableData, or an error to be shown.
+ */
+ $scope.ecdapp.loadTable = function() {
+ $scope.ecdapp.isDataLoading = true;
+ DatacenterHealthService.getDatacentersHealth(
+ $scope.ecdapp.currentPageNum, $scope.ecdapp.viewPerPage).then(
+ function(jsonObj) {
+ if (jsonObj.error) {
+ $log.error("datacentersController.loadTable failed: "
+ + jsonObj.error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = jsonObj.error;
+ $scope.ecdapp.tableData = [];
+ } else {
+ // $log.debug("datacentersController.loadTable
+ // succeeded, size " + jsonObj.data.length);
+ $scope.ecdapp.isRequestFailed = false;
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.totalPages = jsonObj.totalPages;
+ $scope.ecdapp.tableData = jsonObj.items;
+ }
+ $scope.ecdapp.isDataLoading = false;
+ },
+ function(error) {
+ $log.error("datacentersController.loadTable failed: "
+ + error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = error;
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.isDataLoading = false;
+ });
+ };
+
+ // Populate the table on load. Note that the b2b selector code
+ // sets the page-number value, and the change event calls load table.
+ // Do not call this here to avoid double load:
+ // $scope.ecdapp.loadTable();
+
+});
diff --git a/oom-app-overlay/src/main/webapp/app/oom/consul/datacenter_table.html b/oom-app-overlay/src/main/webapp/app/oom/consul/datacenter_table.html
new file mode 100644
index 0000000..73a1b82
--- /dev/null
+++ b/oom-app-overlay/src/main/webapp/app/oom/consul/datacenter_table.html
@@ -0,0 +1,71 @@
+<div id="page-content">
+
+ <h1 class="heading-page" id="consul_datacenters">Monitored Datacenters</h1>
+
+ <!-- show progress indicator -->
+ <div ng-show="ecdapp.isDataLoading">
+ <div class="span" style="margin-bottom:20px;">
+ <i class="icon-primary-spinner small" role="img" aria-label="Please wait while the content loads"></i>
+ Please wait while the content loads.
+ </div>
+ </div>
+
+ <div ng-hide="ecdapp.isDataLoading">
+
+ <div id="button-search-row">
+ <div style="float:right;">
+ <div class="form-field form-field__small">
+ <input
+ type="text"
+ placeholder="Search Datacenters"
+ ng-model="ecdapp.searchString"/>
+ </div>
+ </div>
+ </div>
+
+ <div ng-show="ecdapp.isRequestFailed">
+ <span class="ecd-error-message">{{ecdapp.errMsg}}</span>
+ </div>
+
+ <div ng-hide="ecdapp.isRequestFailed">
+
+ <div
+ b2b-table
+ id="consul-datacenters-table"
+ class="b2b-table-div"
+ table-data="ecdapp.tableData"
+ search-string="ecdapp.searchString"
+ current-page="ecdapp.currentPageIgnored"
+ next-sort="ecdapp.nextSortIgnored">
+
+ <table>
+
+ <thead b2b-table-row type="header">
+ <tr id="th-header-row">
+ <th b2b-table-header key="name">Name</th>
+ </tr>
+ </thead>
+
+ <tbody b2b-table-row type="body" row-repeat="rowData in ecdapp.tableData">
+ <tr id="tr-rowData">
+ <td b2b-table-body
+ ng-bind="rowData.name"/>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <div b2b-pagination="" total-pages="ecdapp.totalPages"
+ current-page="ecdapp.currentPageNum"
+ click-handler="pageChangeHandler" role="navigation"></div>
+
+ </div>
+ <!-- failed -->
+
+ <div style="height: 10px;">
+ <!-- space between page number and black footer -->
+ </div>
+
+ </div><!-- loading -->
+
+</div><!-- page content -->
diff --git a/oom-app-overlay/src/main/webapp/app/oom/consul/node-health-service.js b/oom-app-overlay/src/main/webapp/app/oom/consul/node-health-service.js
new file mode 100644
index 0000000..3f3c8f6
--- /dev/null
+++ b/oom-app-overlay/src/main/webapp/app/oom/consul/node-health-service.js
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.factory('NodeHealthService', function ($http, $q, $log) {
+ return {
+ /**
+ * Gets one page of objects.
+ * @param {Number} pageNum - page number; e.g., 1
+ * @param {Number} viewPerPage - number of items per page; e.g., 25
+ * @return {JSON} Response object from remote side
+ */
+ getNodesHealth: function(pageNum,viewPerPage) {
+ // cache control for IE
+ let cc = "&cc=" + new Date().getTime().toString();
+ let url = 'healthservices/nodes?pageNum=' + pageNum + '&viewPerPage=' + viewPerPage + cc;
+ return $http({
+ method: 'GET',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('nodeHealthService.getNodesHealth: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('nodeHealthService.getNodesHealth failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ /**
+ * Gets all services on the specified node.
+ * @param {nodeName} node name (not the UUID)
+ * @return {JSON} Response object from remote side
+ */
+ getNodeServicesHealth: function(nodeName) {
+ // cache control for IE
+ let cc = "?cc=" + new Date().getTime().toString();
+ let url = 'healthservices/nodes/' + nodeName + cc;
+ return $http({
+ method: 'GET',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('serviceHealthService.getNodeServicesHealth: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('serviceHealthService.getNodeServicesHealth failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ };
+});
diff --git a/oom-app-overlay/src/main/webapp/app/oom/consul/node-services-controller.js b/oom-app-overlay/src/main/webapp/app/oom/consul/node-services-controller.js
new file mode 100644
index 0000000..b82ba40
--- /dev/null
+++ b/oom-app-overlay/src/main/webapp/app/oom/consul/node-services-controller.js
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.controller('nodeServicesCtrl', function($scope, $log, message, NodeHealthService) {
+
+ 'use strict';
+
+ // Controls logging in this controller
+ var debug = false;
+
+ if (debug)
+ $log.debug('nodeServicesCtrl: message is ' + JSON.stringify(message));
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ $scope.ecdapp.label = 'Services on Node ' + message.node;
+
+ /**
+ * Loads the table of services for the specified node.
+ */
+ $scope.ecdapp.loadTable = function(nodeName) {
+ $scope.ecdapp.isDataLoading = true;
+ if (debug)
+ $log.debug('nodeServicesCtrl: loading data for ' + nodeName);
+ NodeHealthService.getNodeServicesHealth(nodeName).then(
+ function(jsonObj) {
+ if (debug)
+ $log.debug('nodeServicesCtrl: response is ' + JSON.stringify(jsonObj));
+ if (jsonObj.error) {
+ $log.error("nodeServicesCtrl.loadTable failed: "
+ + jsonObj.error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = jsonObj.error;
+ $scope.ecdapp.tableData = [];
+ } else {
+ // $log.debug("serviceHealthController.loadTable
+ // succeeded, size " + jsonObj.data.length);
+ $scope.ecdapp.isRequestFailed = false;
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.tableData = jsonObj;
+ }
+ $scope.ecdapp.isDataLoading = false;
+ },
+ function(error) {
+ $log.error("nodeServicesCtrl.loadTable failed: "
+ + error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = error;
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.isDataLoading = false;
+ });
+ };
+
+ // Show services for the requested node
+ if (debug)
+ $log.debug('nodeServicesCtrl: requesting services for node ' + message.node);
+ $scope.ecdapp.loadTable(message.node);
+
+});
diff --git a/oom-app-overlay/src/main/webapp/app/oom/consul/node-table-controller.js b/oom-app-overlay/src/main/webapp/app/oom/consul/node-table-controller.js
new file mode 100644
index 0000000..61ececb
--- /dev/null
+++ b/oom-app-overlay/src/main/webapp/app/oom/consul/node-table-controller.js
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.controller('nodeTableController', function($scope, $log, $modal, NodeHealthService) {
+
+ 'use strict';
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ // models for controls on screen
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.currentPageNum = 1;
+ $scope.ecdapp.viewPerPage = 10;
+ // other
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.isDataLoading = true;
+ $scope.ecdapp.isRequestFailed = false;
+
+ /**
+ * Answers an array of the specified size - makes Angular iteration easy.
+ */
+ $scope.ecdapp.buildArraySizeN = function(num) {
+ // $log.debug("buildArraySizeN: invoked with " + num);
+ return new Array(num);
+ }
+
+ /**
+ * Loads the table. Interprets the remote controller's response and copies
+ * to scope variables. The response is either list to be assigned to
+ * tableData, or an error to be shown.
+ */
+ $scope.ecdapp.loadTable = function() {
+ $scope.ecdapp.isDataLoading = true;
+ NodeHealthService.getNodesHealth($scope.ecdapp.currentPageNum,
+ $scope.ecdapp.viewPerPage).then(
+ function(jsonObj) {
+ if (jsonObj.error) {
+ $log.error("nodeHealthController.loadTable failed: "
+ + jsonObj.error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = jsonObj.error;
+ $scope.ecdapp.tableData = [];
+ } else {
+ // $log.debug("nodeHealthController.loadTable succeeded,
+ // size " + jsonObj.data.length);
+ $scope.ecdapp.isRequestFailed = false;
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.totalPages = jsonObj.totalPages;
+ $scope.ecdapp.tableData = jsonObj.items;
+ }
+ $scope.ecdapp.isDataLoading = false;
+ },
+ function(error) {
+ $log.error("nodeHealthController.loadTable failed: "
+ + error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = error;
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.isDataLoading = false;
+ });
+ };
+
+ /**
+ * Invoked at first page load AND when user clicks on the B2B pagination
+ * control.
+ */
+ $scope.pageChangeHandler = function(page) {
+ // console.log('pageChangeHandler: current is ' +
+ // $scope.ecdapp.currentPageNum + ' new is ' + page);
+ $scope.ecdapp.currentPageNum = page;
+ $scope.ecdapp.loadTable();
+ }
+
+
+ /**
+ * Shows a modal pop-up with services on this node.
+ */
+ $scope.ecdapp.viewServicesModalPopup = function(nodeInfo) {
+ var modalInstance = $modal.open({
+ templateUrl : 'node_services_popup.html',
+ controller : 'nodeServicesCtrl',
+ windowClass: 'modal-docked',
+ sizeClass: 'modal-large',
+ resolve : {
+ message : function() {
+ return nodeInfo ;
+ }
+ }
+ });
+ modalInstance.result.then(function(response) {
+ // No response expected.
+ });
+ };
+
+ // Populate the table on load. Note that the b2b selector code
+ // sets the page-number value, and the change event calls load table.
+ // Do not call this here to avoid double load:
+ // $scope.ecdapp.loadTable();
+
+});
diff --git a/oom-app-overlay/src/main/webapp/app/oom/consul/node_popups.html b/oom-app-overlay/src/main/webapp/app/oom/consul/node_popups.html
new file mode 100644
index 0000000..63b5e5f
--- /dev/null
+++ b/oom-app-overlay/src/main/webapp/app/oom/consul/node_popups.html
@@ -0,0 +1,67 @@
+<script type="text/ng-template" id="node_services_popup.html">
+
+ <div class="b2b-modal-header ng-scope">
+ <h2 id="myModalLabel" modal-title="">{{ecdapp.label}}</h2>
+ <div class="corner-button in">
+ <button type="button" class="close" aria-label="Close"
+ ng-click="$dismiss('cancel')"></button>
+ </div>
+ </div>
+
+ <!-- show progress indicator -->
+ <div ng-show="ecdapp.isDataLoading">
+ <div class="span" style="margin-bottom: 20px;">
+ <i class="icon-primary-spinner small" role="img"
+ aria-label="Please wait while the content loads"></i> Please wait
+ while the content loads.
+ </div>
+ </div>
+
+ <div ng-hide="ecdapp.isDataLoading">
+
+ <div ng-show="ecdapp.isRequestFailed">
+ <span class="ecd-error-message">{{ecdapp.errMsg}}</span>
+ </div>
+
+ <div ng-hide="ecdapp.isRequestFailed">
+
+ <div b2b-table id="consul-node-services-table" class="b2b-table-div"
+ table-data="ecdapp.tableData" search-string="ecdapp.searchStringIgnored"
+ current-page="ecdapp.currentPageIgnored" next-sort="ecdapp.nextSortIgnored">
+
+ <table>
+ <thead b2b-table-row type="header">
+ <tr id="th-header-row">
+ <th b2b-table-header key="serviceName">Service Name</th>
+ <th b2b-table-header key="serviceID">Service ID</th>
+ <th b2b-table-header key="status">Status</th>
+ <th b2b-table-header key="notes">Notes</th>
+ <th b2b-table-header key="output">Output</th>
+ </tr>
+ </thead>
+ <tbody b2b-table-row type="body"
+ row-repeat="rowData in ecdapp.tableData">
+ <tr id="tr-rowData">
+ <td b2b-table-body ng-bind="rowData.serviceName" />
+ <td b2b-table-body ng-bind="rowData.serviceID" />
+ <td b2b-table-body ng-bind="rowData.status" />
+ <td b2b-table-body ng-bind="rowData.notes" />
+ <td b2b-table-body ng-bind="rowData.output" />
+ </tr>
+ </tbody>
+ </table>
+
+ </div> <!--table-->
+ </div> <!--failed-->
+ </div> <!--hide-->
+
+ <div class="b2b-modal-footer ng-scope ng-isolate-scope">
+ <div class="cta-button-group in">
+ <button class="btn btn-alt btn-small" type="button"
+ ng-click="$dismiss('cancel')">
+ Close
+ </button>
+ </div>
+ </div>
+
+</script>
diff --git a/oom-app-overlay/src/main/webapp/app/oom/consul/node_table.html b/oom-app-overlay/src/main/webapp/app/oom/consul/node_table.html
new file mode 100644
index 0000000..231d331
--- /dev/null
+++ b/oom-app-overlay/src/main/webapp/app/oom/consul/node_table.html
@@ -0,0 +1,78 @@
+<div id="page-content">
+
+ <h1 class="heading-page" id="consul_nodes">Monitored Nodes</h1>
+
+ <!-- show progress indicator -->
+ <div ng-show="ecdapp.isDataLoading">
+ <div class="span" style="margin-bottom: 20px;">
+ <i class="icon-primary-spinner small" role="img"
+ aria-label="Please wait while the content loads"></i> Please wait
+ while the content loads.
+ </div>
+ </div>
+
+ <div ng-hide="ecdapp.isDataLoading">
+
+ <div id="button-search-row">
+ <div style="float: right;">
+ <div class="form-field form-field__small">
+ <input type="text" placeholder="Search Nodes"
+ ng-model="ecdapp.searchString" />
+ </div>
+ </div>
+ </div>
+
+ <div ng-show="ecdapp.isRequestFailed">
+ <span class="ecd-error-message">{{ecdapp.errMsg}}</span>
+ </div>
+
+ <div ng-hide="ecdapp.isRequestFailed">
+
+ <div b2b-table id="consul-nodes-table" class="b2b-table-div"
+ table-data="ecdapp.tableData" search-string="ecdapp.searchString"
+ current-page="ecdapp.currentPageIgnored"
+ next-sort="ecdapp.nextSortIgnored">
+
+ <table>
+
+ <thead b2b-table-row type="header">
+ <tr id="th-header-row">
+ <th b2b-table-header key="node">Node Name</th>
+ <th b2b-table-header key="id">Node ID</th>
+ <th b2b-table-header key="address">Address</th>
+ <th b2b-table-header sortable="false"><i class="icon-controls-gear ecd-icon-display"></i></th>
+ </tr>
+ </thead>
+
+ <tbody b2b-table-row type="body"
+ row-repeat="rowData in ecdapp.tableData">
+ <tr id="tr-rowData">
+ <td b2b-table-body ng-bind="rowData.node" />
+ <td b2b-table-body ng-bind="rowData.id" />
+ <td b2b-table-body ng-bind="rowData.address" />
+ <td b2b-table-body>
+ <div ng-click="ecdapp.viewServicesModalPopup(rowData);">
+ <a href="" title="View node services" class="icon-people-preview ecd-icon-action"></a>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <div b2b-pagination="" total-pages="ecdapp.totalPages"
+ current-page="ecdapp.currentPageNum"
+ click-handler="pageChangeHandler" role="navigation"></div>
+
+ </div>
+ <!-- failed -->
+
+ <div style="height: 10px;">
+ <!-- space between page number and black footer -->
+ </div>
+
+ </div>
+ <!-- loading -->
+
+</div>
+<!-- page content -->
diff --git a/oom-app-overlay/src/main/webapp/app/oom/consul/service-controllers.js b/oom-app-overlay/src/main/webapp/app/oom/consul/service-controllers.js
new file mode 100644
index 0000000..339c436
--- /dev/null
+++ b/oom-app-overlay/src/main/webapp/app/oom/consul/service-controllers.js
@@ -0,0 +1,366 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.controller('serviceHealthTableController', function($scope, $log, $modal, modalService, ServiceHealthService) {
+
+ 'use strict';
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ // models for controls on screen
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.currentPageNum = 1;
+ $scope.ecdapp.viewPerPage = 100;
+ // other
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.isDataLoading = true;
+ $scope.ecdapp.isRequestFailed = false;
+
+ /**
+ * Loads the table. Interprets the remote controller's response and copies
+ * to scope variables. The response is either list to be assigned to
+ * tableData, or an error to be shown.
+ */
+ $scope.ecdapp.loadTable = function() {
+ $scope.ecdapp.isDataLoading = true;
+ ServiceHealthService.getServicesHealth($scope.ecdapp.currentPageNum,
+ $scope.ecdapp.viewPerPage).then(
+ function(jsonObj) {
+ if (jsonObj.error) {
+ $log.error("serviceHealthTableController.loadTable failed: "
+ + jsonObj.error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = jsonObj.error;
+ $scope.ecdapp.tableData = [];
+ } else {
+ // $log.debug("serviceHealthController.loadTable
+ // succeeded, size " + jsonObj.data.length);
+ $scope.ecdapp.isRequestFailed = false;
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.totalPages = jsonObj.totalPages;
+ $scope.ecdapp.tableData = jsonObj.items;
+ }
+ $scope.ecdapp.isDataLoading = false;
+ },
+ function(error) {
+ $log.error("serviceHealthTableController.loadTable failed: "
+ + error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = error;
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.isDataLoading = false;
+ });
+ };
+
+ /**
+ * Invoked at first page load AND when user clicks on the B2B pagination
+ * control.
+ */
+ $scope.pageChangeHandler = function(page) {
+ // console.log('pageChangeHandler: current is ' +
+ // $scope.ecdapp.currentPageNum + ' new is ' + page);
+ $scope.ecdapp.currentPageNum = page;
+ $scope.ecdapp.loadTable();
+ }
+
+ /**
+ * Shows a modal pop-up to register a service.
+ */
+ $scope.ecdapp.registerServiceModalPopup = function() {
+ var modalInstance = $modal.open({
+ templateUrl : 'service_register_popup.html',
+ controller : 'serviceRegisterCtrl',
+ windowClass: 'modal-docked',
+ sizeClass: 'modal-medium',
+ resolve : {
+ message : function() {
+ return { /* no data */ } ;
+ }
+ }
+ });
+ modalInstance.result.then(function(response) {
+ // $log.debug('addFeedModalPopup: response: ' + JSON.stringify(response));
+ if (response == null) {
+ // $log.debug('user closed dialog');
+ }
+ else {
+ if (response.error != null) {
+ $log.error('uploadBlueprintModalPopup failed: ' + response.error);
+ alert('Failed to upload blueprint:\n' + response.error);
+ }
+ else {
+ // success, get the updated list.
+ $scope.ecdapp.loadTable()
+ }
+ }
+ });
+ };
+
+ /**
+ * Shows a modal pop-up with service health history.
+ */
+ $scope.ecdapp.viewHealthHistoryModalPopup = function(service) {
+ var modalInstance = $modal.open({
+ templateUrl : 'service_history_popup.html',
+ controller : 'serviceHistoryCtlr',
+ windowClass: 'modal-docked',
+ sizeClass: 'modal-large',
+ resolve : {
+ message : function() {
+ return service;
+ }
+ }
+ });
+ modalInstance.result.then(function(response) {
+ // $log.debug('addFeedModalPopup: response: ' + JSON.stringify(response));
+ if (response == null) {
+ // $log.debug('user closed dialog');
+ }
+ else {
+ if (response.error != null) {
+ $log.error('uploadBlueprintModalPopup failed: ' + response.error);
+ alert('Failed to upload blueprint:\n' + response.error);
+ }
+ else {
+ // success, get the updated list.
+ $scope.ecdapp.loadTable()
+ }
+ }
+ });
+ };
+
+ /**
+ * Shows a modal pop-up to confirm deregistration.
+ * On successful completion, updates the table.
+ */
+ $scope.ecdapp.deregisterServiceModalPopup = function(service) {
+ modalService.popupConfirmWin("Confirm", "Deregister service '"
+ + service.serviceName + "'?", function() {
+ ServiceHealthService.deregisterService(service.serviceName).then(
+ function(response) {
+ if (response && response.error) {
+ // $log.error('deleteBlueprint failed: ' + response.error);
+ alert('Failed to deregister service:\n' + response.error);
+ }
+ else {
+ // No response body on success.
+ $scope.ecdapp.loadTable();
+ }
+ },
+ function(error) {
+ $log.error('ServiceHealthService.deregisterService failed: ' + error);
+ alert('Failed to deregister service:\n' + error);
+ });
+ })
+ };
+
+ // Populate the table on load. Note that the b2b selector code
+ // sets the page-number value, and the change event calls load table.
+ // Do not call this here to avoid double load:
+ // $scope.ecdapp.loadTable();
+
+});
+
+
+appDS2.controller('serviceRegisterCtrl', function($scope, $log, message, ServiceHealthService) {
+
+ 'use strict';
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+
+ $scope.ecdapp.label = 'Register Service';
+ // Model the data simply here.
+ // Build the complex request later.
+ $scope.ecdapp.registerRequest =
+ {
+ service_id : '',
+ service_name : '',
+ service_address : '',
+ service_port : '',
+ check_endpoint: '',
+ check_interval: '',
+ check_description: '',
+ check_name: ''
+ };
+
+ /**
+ * Validates content of user-editable fields.
+ * Uses the list in message.feedList
+ * Returns null if all is well,
+ * a descriptive error message otherwise.
+ */
+ $scope.ecdapp.validateRequest = function(request) {
+ if (request == null)
+ return "No data found.\nPlease enter some values.";
+ if (request.service_id == null || request.service_id.trim() == '')
+ return "Service ID is required.\nPlease enter a value.";
+ if (request.service_name == null || request.service_name.trim() == '')
+ return "Service name is required.\nPlease enter a value.";
+ if (request.service_address == null || request.service_address.trim() == '')
+ return "Service address is required.\nPlease enter a value.";
+ if (request.service_port == null || request.service_port.trim() == '')
+ return "Service port is required.\nPlease enter a value.";
+ if (request.check_endpoint == null || request.check_endpoint.trim() == '')
+ return "Check endpoint URL is required.\nPlease enter a value.";
+ if (request.check_interval == null || request.check_interval.trim() == '')
+ return "Check interval is required.\nPlease enter a value.";
+ // description and name are optional (I think)
+ return null;
+ }
+
+ $scope.ecdapp.registerService = function(edit_req) {
+ var validateMsg = $scope.ecdapp.validateRequest(edit_req);
+ if (validateMsg != null) {
+ alert('Invalid registration request:\n' + validateMsg);
+ return;
+ }
+ // Build the complex request
+ let request = {
+ services : [
+ {
+ id : edit_req.service_id,
+ name : edit_req.service_name,
+ address : edit_req.service_address,
+ port : edit_req.service_port,
+ tags: [ ],
+ checks : [
+ {
+ endpoint : edit_req.check_endoint,
+ interval : edit_req.check_interval,
+ description : edit_req.description,
+ name : edit_req.check_name
+ }
+ ]
+ }
+ ]
+ };
+
+ ServiceHealthService.registerService(request)
+ .then(function(response) {
+ if (response.error)
+ alert('Failed to register service:\n' + response.error);
+ },
+ function (error) {
+ $log.error('serviceRegisterCtrl: error while registering: ' + error);
+ alert('Server rejected registration request:\n' + error);
+ }
+ );
+
+ };
+
+});
+
+
+appDS2.controller('serviceHistoryCtlr', function($scope, $log, $modal, message, ServiceHealthService) {
+
+ 'use strict';
+
+ // Controls logging in this controller
+ var debug = false;
+ if (debug)
+ $log.debug('serviceHistoryCtlr: message: ' + JSON.stringify(message));
+
+ // this object holds all app data and functions
+ $scope.ecdapp = {};
+ // For convenience
+ $scope.ecdapp.serviceName = message.serviceName;
+ $scope.ecdapp.label = 'History for Service ' + $scope.ecdapp.serviceName;
+
+ // models for controls on screen
+ $scope.ecdapp.startDateTime = '';
+ $scope.ecdapp.endDateTime = '';
+ // data fetched from backend
+ $scope.ecdapp.tableData = [];
+ // progress and error handling
+ $scope.ecdapp.isDataLoading = false;
+ $scope.ecdapp.isRequestFailed = false;
+ $scope.ecdapp.errMsg = null;
+
+ /**
+ * Loads the table. Interprets the remote controller's response and copies
+ * to scope variables. The response is either list to be assigned to
+ * tableData, or an error to be shown.
+ */
+ $scope.ecdapp.showHistory = function() {
+ // Validate the entries in the date fields.
+ // If user types, it's a STRING (not a Date).
+ if ($scope.ecdapp.startDateTime == null) {
+ alert("Please enter a start date.");
+ return;
+ }
+ let startDT = Date.parse($scope.ecdapp.startDateTime);
+ if (isNaN(startDT)) {
+ alert("Failed to parse start date.");
+ return;
+ }
+ else {
+ // Use the parsed version.
+ $scope.ecdapp.startDateTime = new Date(startDT);
+ }
+ if ($scope.ecdapp.endDateTime == null) {
+ alert("Please enter an end date.");
+ return;
+ }
+ let endDT = Date.parse($scope.ecdapp.endDateTime);
+ if (isNaN(endDT)) {
+ alert("Failed to parse end date.");
+ return;
+ }
+ else {
+ $scope.ecdapp.endDateTime = new Date(endDT);
+ }
+ if ($scope.ecdapp.startDateTime.getTime() >= $scope.ecdapp.endDateTime.getTime()) {
+ alert("The start date must be before the end date, please correct.");
+ return;
+ }
+ $scope.ecdapp.isDataLoading = true;
+ ServiceHealthService.getServiceHealthHistory(
+ $scope.ecdapp.serviceName,
+ $scope.ecdapp.startDateTime.toISOString(),
+ $scope.ecdapp.endDateTime.toISOString() ).then(
+ function(jsonObj) {
+ if (jsonObj.error) {
+ $log.error("serviceHistoryCtlr.getServiceHealthHistory reported error: "
+ + jsonObj.error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = jsonObj.error;
+ $scope.ecdapp.tableData = [];
+ } else {
+ if (debug)
+ $log.debug("serviceHistoryCtlr.getServiceHealthHistory succeeded, size " + jsonObj.length);
+ $scope.ecdapp.isRequestFailed = false;
+ $scope.ecdapp.errMsg = null;
+ $scope.ecdapp.tableData = jsonObj;
+ }
+ $scope.ecdapp.isDataLoading = false;
+ },
+ function(error) {
+ $log.error("serviceHistoryCtlr.getServiceHealthHistory failed: "
+ + error);
+ $scope.ecdapp.isRequestFailed = true;
+ $scope.ecdapp.errMsg = error;
+ $scope.ecdapp.tableData = [];
+ $scope.ecdapp.isDataLoading = false;
+ });
+ };
+
+});
diff --git a/oom-app-overlay/src/main/webapp/app/oom/consul/service-health-service.js b/oom-app-overlay/src/main/webapp/app/oom/consul/service-health-service.js
new file mode 100644
index 0000000..010cc11
--- /dev/null
+++ b/oom-app-overlay/src/main/webapp/app/oom/consul/service-health-service.js
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * =============LICENSE_START=========================================================
+ *
+ * =================================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *******************************************************************************/
+appDS2.factory('ServiceHealthService', function ($http, $q, $log) {
+ return {
+
+ /**
+ * Gets information on all services.
+ */
+ getServices: function() {
+ let cc = "?cc=" + new Date().getTime().toString();
+ let url = 'healthservices/services' + cc;
+ return $http({
+ method: 'GET',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('serviceHealthService.getServices: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('serviceHealthService.getServices failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ /**
+ * Gets one page of objects.
+ * @param {Number} pageNum - page number; e.g., 1
+ * @param {Number} viewPerPage - number of items per page; e.g., 25
+ * @return {JSON} Response object from remote side
+ */
+ getServicesHealth: function(pageNum, viewPerPage) {
+ // cache control for IE
+ let cc = "&cc=" + new Date().getTime().toString();
+ let url = 'healthservices/serviceshealth?pageNum=' + pageNum + '&viewPerPage=' + viewPerPage + cc;
+ return $http({
+ method: 'GET',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('serviceHealthService.getServicesHealth: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('serviceHealthService.getServicesHealth failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ /**
+ * Gets history of the specified service between the specified date-times.
+ */
+ getServiceHealthHistory: function(serviceName, startDateTime, endDateTime) {
+ // encode everything
+ let enService = encodeURIComponent(serviceName);
+ let enStart = encodeURIComponent(startDateTime);
+ let enEnd = encodeURIComponent(endDateTime);
+ let url = 'healthservices/svchist/' + enService + '?start=' + enStart + '&end=' + enEnd;
+ return $http({
+ method: 'GET',
+ url: url,
+ cache: false,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('serviceHealthService.getServiceHealthHistory: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('serviceHealthService.getServiceHealthHistory failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ /**
+ * Registers a service with Consul for health monitoring.
+ */
+ registerService: function(request) {
+ let url = 'healthservices/register';
+ return $http({
+ method: 'POST',
+ url: url,
+ data: request,
+ responseType: 'json'
+ }).then(function(response) {
+ if (response.data == null || typeof response.data != 'object')
+ return $q.reject('ServiceHealthService.registerService: response.data null or not object');
+ else
+ return response.data;
+ },
+ function(error) {
+ $log.error('ServiceHealthService.registerService failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ /**
+ * Deregisters a service from Consul.
+ */
+ deregisterService: function(serviceName) {
+ let url = 'healthservices/deregister/' + serviceName;
+ return $http({
+ method: 'POST',
+ url: url,
+ responseType: 'json'
+ }).then(function(response) {
+ // This is called on response code 200..299.
+ // On success, response.data is null.
+ // On failure, response.data has an error message.
+ return response.data;
+ },
+ function(error) {
+ $log.error('ServiceHealthService.deregisterService failed: ' + JSON.stringify(error));
+ return $q.reject(error.statusText);
+ });
+ },
+
+ };
+});
diff --git a/oom-app-overlay/src/main/webapp/app/oom/consul/service_health_table.html b/oom-app-overlay/src/main/webapp/app/oom/consul/service_health_table.html
new file mode 100644
index 0000000..b6a4557
--- /dev/null
+++ b/oom-app-overlay/src/main/webapp/app/oom/consul/service_health_table.html
@@ -0,0 +1,93 @@
+<div id="page-content">
+
+ <h1 class="heading-page" id="consul_services">Monitored Services</h1>
+
+ <!-- show progress indicator -->
+ <div ng-show="ecdapp.isDataLoading">
+ <div class="span" style="margin-bottom: 20px;">
+ <i class="icon-primary-spinner small" role="img"
+ aria-label="Please wait while the content loads"></i> Please wait
+ while the content loads.
+ </div>
+ </div>
+
+ <div ng-hide="ecdapp.isDataLoading">
+
+ <div id="button-search-row">
+ <button class="btn btn-alt btn-small"
+ type="submit"
+ ng-click="ecdapp.registerServiceModalPopup();">
+ Register Service...
+ </button>
+ <div style="float: right;">
+ <div class="form-field form-field__small">
+ <input type="text" placeholder="Search Services"
+ ng-model="ecdapp.searchString" />
+ </div>
+ </div>
+ </div>
+
+ <div ng-show="ecdapp.isRequestFailed">
+ <span class="ecd-error-message">{{ecdapp.errMsg}}</span>
+ </div>
+
+ <div ng-hide="ecdapp.isRequestFailed">
+
+ <div b2b-table id="consul-services-table" class="b2b-table-div"
+ table-data="ecdapp.tableData" search-string="ecdapp.searchString"
+ current-page="ecdapp.currentPageIgnored"
+ next-sort="ecdapp.nextSortIgnored">
+
+ <table>
+
+ <thead b2b-table-row type="header">
+ <tr id="th-header-row">
+ <th b2b-table-header key="serviceName">Service Name</th>
+ <th b2b-table-header key="serviceID">Service ID</th>
+ <th b2b-table-header key="node">Node Name</th>
+ <th b2b-table-header key="status">Status</th>
+ <th b2b-table-header key="notes">Notes</th>
+ <th b2b-table-header key="output">Output</th>
+ <th b2b-table-header sortable="false"><i class="icon-controls-gear ecd-icon-display"></i></th>
+ </tr>
+ </thead>
+
+ <tbody b2b-table-row type="body"
+ row-repeat="rowData in ecdapp.tableData">
+ <tr id="tr-rowData">
+ <td b2b-table-body ng-bind="rowData.serviceName" />
+ <td b2b-table-body ng-bind="rowData.serviceID" />
+ <td b2b-table-body ng-bind="rowData.node" />
+ <td b2b-table-body ng-bind="rowData.status" />
+ <td b2b-table-body ng-bind="rowData.notes" />
+ <td b2b-table-body ng-bind="rowData.output" />
+ <td b2b-table-body>
+ <div ng-click="ecdapp.viewHealthHistoryModalPopup(rowData);">
+ <a href="" title="View history" class="icon-datanetwork-history ecd-icon-action"></a>
+ </div>
+ <div ng-click="ecdapp.deregisterServiceModalPopup(rowData);">
+ <a href="" title="Deregister service" class="icon-misc-trash ecd-icon-action"></a>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <div b2b-pagination="" total-pages="ecdapp.totalPages"
+ current-page="ecdapp.currentPageNum"
+ click-handler="pageChangeHandler" role="navigation"></div>
+
+
+ </div>
+ <!-- error -->
+
+ <div style="height: 10px;">
+ <!-- space between page number and black footer -->
+ </div>
+
+ </div>
+ <!-- loading -->
+
+</div>
+<!-- page content -->
diff --git a/oom-app-overlay/src/main/webapp/app/oom/consul/service_popups.html b/oom-app-overlay/src/main/webapp/app/oom/consul/service_popups.html
new file mode 100644
index 0000000..8fd92b3
--- /dev/null
+++ b/oom-app-overlay/src/main/webapp/app/oom/consul/service_popups.html
@@ -0,0 +1,207 @@
+<script type="text/ng-template" id="service_register_popup.html">
+
+ <div class="b2b-modal-header ng-scope">
+ <h2 id="myModalLabel" modal-title="">{{ecdapp.label}}</h2>
+ <div class="corner-button in">
+ <button type="button" class="close" aria-label="Close"
+ ng-click="$dismiss('cancel')"></button>
+ </div>
+ </div>
+
+ <div class="b2b-modal-body ng-scope ng-isolate-scope" tabindex="0"
+ role="region" aria-label="Modal body content">
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <div class="form-row">
+ <label for="serviceName">*Service Name</label>
+ <div class="field-group">
+ <input id="serviceName" class="span12" type="text" data-ng-model="ecdapp.editRequest.service_name" autofocus />
+ </div>
+ </div>
+ </div>
+ <div class="span12">
+ <div class="form-row">
+ <label for="checkEndpoint">*Endpoint URL</label>
+ <div class="field-group">
+ <input id="checkEndpoint" class="span12" type="text" data-ng-model="ecdapp.editRequest.check_endpoint"/>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <div class="form-row">
+ <label for="serviceId">*Service ID</label>
+ <div class="field-group">
+ <input id="serviceId" class="span12" type="text" data-ng-model="ecdapp.editRequest.service_id"/>
+ </div>
+ </div>
+ </div>
+ <div class="span12">
+ <div class="form-row">
+ <label for="checkInterval">*Interval</label>
+ <div class="field-group">
+ <input id="checkInterval" class="span12" type="text" data-ng-model="ecdapp.editRequest.check_interval"/>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <div class="form-row">
+ <label for="serviceAddress">*Address</label>
+ <div class="field-group">
+ <input id="serviceAddress" class="span12" type="text" data-ng-model="ecdapp.editRequest.service_address"/>
+ </div>
+ </div>
+ </div>
+ <div class="span12">
+ <div class="form-row">
+ <label for="checkDescription">Description</label>
+ <div class="field-group">
+ <input id="checkDescription" class="span12" type="text" data-ng-model="ecdapp.editRequest.check_description"/>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <div class="form-row">
+ <label for="servicePort">*Port</label>
+ <div class="field-group">
+ <input id="servicePort" class="span12" type="text" data-ng-model="ecdapp.editRequest.service_port"/>
+ </div>
+ </div>
+ </div>
+ <div class="span12">
+ <div class="form-row">
+ <label for="checkName">Name</label>
+ <div class="field-group">
+ <input id="checkName" class="span12" type="text" data-ng-model="ecdapp.editRequest.check_name"/>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="b2b-modal-footer ng-scope ng-isolate-scope">
+ <div class="cta-button-group in">
+ <button class="btn btn-alt btn-small" type="button"
+ ng-click="ecdapp.registerService(ecdapp.editRequest);">
+ Save
+ </button>
+ <button class="btn btn-small" type="button"
+ ng-click="$dismiss('cancel')">
+ Cancel
+ </button>
+ </div>
+ </div>
+
+</script>
+
+<script type="text/ng-template" id="service_history_popup.html">
+
+ <div class="b2b-modal-header ng-scope">
+ <h2 id="myModalLabel" modal-title="">{{ecdapp.label}}</h2>
+ <div class="corner-button in">
+ <button type="button" class="close" aria-label="Close"
+ ng-click="$dismiss('cancel')"></button>
+ </div>
+ </div>
+
+ <div class="b2b-modal-body ng-scope ng-isolate-scope" tabindex="0"
+ role="region" aria-label="Modal body content">
+
+ <div class="row-nowrap">
+ <div class="span12">
+ <div class="form-row">
+ <label for="startDateTime">*Start Date</label>
+ <div class="field-group">
+ <div class="datepicker-container" >
+ <input id="startDateTime" name="startDateTime" class="span12" type="text" ng-model="ecdapp.startDateTime" b2b-datepicker>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="span12">
+ <div class="form-row">
+ <label for="endDateTime">*End Date</label>
+ <div class="field-group">
+ <div class="datepicker-container" >
+ <input id="endDateTime" name="endDateTime" class="span12" type="text" ng-model="ecdapp.endDateTime" b2b-datepicker>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="span12">
+ <div class="form-row">
+ <label for="submit">&nbsp;</label>
+ <div class="field-group">
+ <button id="submit"
+ class="btn btn-alt btn-small"
+ type="submit"
+ ng-disabled="ecdapp.startDateTime === '' || ecdapp.endDateTime === '' "
+ ng-click="ecdapp.showHistory();">
+ Search
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <!-- show progress indicator -->
+ <div ng-show="ecdapp.isDataLoading">
+ <div class="span" style="margin-bottom: 20px;">
+ <i class="icon-primary-spinner small" role="img"
+ aria-label="Please wait while the content loads"></i> Please wait
+ while the content loads.
+ </div>
+ </div>
+
+ <div ng-show="ecdapp.isRequestFailed">
+ <span class="ecd-error-message">{{ecdapp.errMsg}}</span>
+ </div>
+
+ <div ng-hide="ecdapp.isRequestFailed">
+ <div b2b-table id="consul-services-history-table" class="b2b-table-div"
+ table-data="ecdapp.tableData" search-string="ecdapp.searchString"
+ current-page="ecdapp.currentPageIgnored"
+ next-sort="ecdapp.nextSortIgnored">
+ <table>
+ <thead b2b-table-row type="header">
+ <tr id="th-header-row">
+ <th b2b-table-header key="status">Status</th>
+ <th b2b-table-header key="output">Output</th>
+ <th b2b-table-header key="notes">Date</th>
+ </tr>
+ </thead>
+
+ <tbody b2b-table-row type="body"
+ row-repeat="rowData in ecdapp.tableData">
+ <tr id="tr-rowData">
+ <td b2b-table-body ng-bind="rowData.status" />
+ <td b2b-table-body ng-bind="rowData.output" />
+ <td b2b-table-body ng-bind="rowData.date" />
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div> <!--hide-->
+
+ </div>
+
+ <div class="b2b-modal-footer ng-scope ng-isolate-scope">
+ <div class="cta-button-group in">
+ <button class="btn btn-alt btn-small" type="button"
+ ng-click="$dismiss();">
+ Close
+ </button>
+ </div>
+ </div>
+
+</script>