This is an automated email from the ASF dual-hosted git repository.
mitchell852 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
The following commit(s) were added to refs/heads/master by this push:
new e5d7dc8 Servers table switch to ag-grid (#4769)
e5d7dc8 is described below
commit e5d7dc8a0a63e7fd9917e2fd958dd8c9e7975306
Author: ocket8888 <[email protected]>
AuthorDate: Tue Jun 16 19:41:40 2020 -0600
Servers table switch to ag-grid (#4769)
* Added ag-grid tables to TP
* Fixed build issues
* Replaced servers table with agGrid
* Switch to tabs
* Started setting up context menu support
* Added some context menu functionality, fixed some styling
* Put styling in the stylesheet; added server delete to context menu
* Moved menu outside of panel
* Added server status update to context menu
* Added queue updates to context menu
* Added clear updates to context menu; added disabled menuitem styling
* Fixed a type error, finished context menu
* Removed unused things, general clean-up and re-organization
* added CSV export
* Rolled back changes to source of AngularJS
* Fixed menuitem button styling
* table now saves sort, filter, and column state
* table now saves column sizes
* Rolled back inneffectual browserify changes
* fixes server TP tests to work with ag-grid
* fixes broken TP ds test
* adds a new super controller for the *servers tables
* Fixed blank CDNs column
* Fixed incorrect update pending label icon
* Removed unused coldef properties, removed unused gridOptions property
* Fixed broken 'show charts' button in servers table context menu
* Fixed context menu not closing when certain actions were selected
Co-authored-by: Jeremy Mitchell <[email protected]>
---
traffic_portal/app/src/app.js | 6 +-
.../app/src/common/modules/table/_table.scss | 71 ++
.../TableCacheGroupServersController.js | 4 +-
.../table/cdnServers/TableCDNServersController.js | 4 +-
.../TableDeliveryServiceServersController.js | 4 +-
.../TablePhysLocationServersController.js | 4 +-
.../TableProfileServersController.js | 4 +-
.../TableServerCapabilityServersController.js | 4 +-
.../table/servers/TableParentServersController.js | 421 +++++++++
.../table/servers/TableServersController.js | 991 ++++++++++++---------
.../app/src/common/modules/table/servers/index.js | 3 +-
.../modules/table/servers/table.servers.tpl.html | 134 +--
.../statusServers/TableStatusServersController.js | 4 +-
.../typeServers/TableTypeServersController.js | 4 +-
traffic_portal/app/src/index.html | 1 +
traffic_portal/grunt/copy.js | 18 +-
traffic_portal/grunt/globalConfig.js | 5 +-
traffic_portal/package-lock.json | 5 +
traffic_portal/package.json | 3 +
.../deliveryServices/delivery-services-spec.js | 2 +-
.../test/end_to_end/servers/servers-spec.js | 17 +-
21 files changed, 1183 insertions(+), 526 deletions(-)
diff --git a/traffic_portal/app/src/app.js b/traffic_portal/app/src/app.js
index ddf01c5..7575d3c 100644
--- a/traffic_portal/app/src/app.js
+++ b/traffic_portal/app/src/app.js
@@ -24,8 +24,11 @@ var App = function($urlRouterProvider) {
$urlRouterProvider.otherwise('/');
};
+
App.$inject = ['$urlRouterProvider'];
+agGrid.initialiseAgGridWithAngular1(angular);
+
var trafficPortal = angular.module('trafficPortal', [
'config',
'ngAnimate',
@@ -42,6 +45,7 @@ var trafficPortal = angular.module('trafficPortal', [
'angular-loading-bar',
'moment-picker',
'jsonFormatter',
+ 'agGrid',
// public modules
require('./modules/public').name,
@@ -509,5 +513,3 @@ trafficPortal.factory('authInterceptor', function
($rootScope, $q, $window, $loc
trafficPortal.config(function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
});
-
-
diff --git a/traffic_portal/app/src/common/modules/table/_table.scss
b/traffic_portal/app/src/common/modules/table/_table.scss
index 1c39b48..e6a2868 100644
--- a/traffic_portal/app/src/common/modules/table/_table.scss
+++ b/traffic_portal/app/src/common/modules/table/_table.scss
@@ -107,3 +107,74 @@ th.center, td.center {
.dt-button.btn-link {
text-decoration: underline;
}
+
+/* Table context menus */
+menu[type="contextmenu"] {
+ display: block;
+ position: fixed;
+ background-color: white;
+ padding: 0;
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+ border-radius: 3px;
+
+ ul {
+ display: block;
+ clear: both;
+ font-weight: normal;
+ line-height: 1.428571429;
+ white-space: nowrap;
+ padding: 0;
+ margin: 0;
+
+ li {
+ display: block;
+ clear: both;
+
+ &:hover {
+ color: #262626;
+ background-color: #f5f5f5;
+ }
+
+ a, button {
+ color: #333333;
+ text-decoration: none;
+ padding: 7px 20px;
+ display: block;
+ clear: both;
+ }
+
+ button {
+ background: transparent;
+ border: none;
+ width: 100%;
+ text-align: left;
+
+ &[disabled] {
+ color: gray;
+ background-color: #f5f5f5;
+ }
+ }
+ }
+
+ hr.divider {
+ margin: 0;
+ }
+ }
+}
+
+div.dropdown button.menu-item-button {
+ color: #333333;
+ width: 100%;
+ background: transparent;
+ border: none;
+ text-align: inherit;
+ display: block;
+ clear: both;
+ padding: 3px 20px;
+ margin: 0;
+
+ &:hover {
+ color: #262626;
+ background-color: #f5f5f5;
+ }
+}
diff --git
a/traffic_portal/app/src/common/modules/table/cacheGroupServers/TableCacheGroupServersController.js
b/traffic_portal/app/src/common/modules/table/cacheGroupServers/TableCacheGroupServersController.js
index 7ce6742..8ea50a2 100644
---
a/traffic_portal/app/src/common/modules/table/cacheGroupServers/TableCacheGroupServersController.js
+++
b/traffic_portal/app/src/common/modules/table/cacheGroupServers/TableCacheGroupServersController.js
@@ -19,8 +19,8 @@
var TableCacheGroupsServersController = function(cacheGroup, servers,
$controller, $scope, $state, $uibModal, cacheGroupService) {
- // extends the TableServersController to inherit common methods
- angular.extend(this, $controller('TableServersController', { servers:
servers, $scope: $scope }));
+ // extends the TableParentServersController to inherit common methods
+ angular.extend(this, $controller('TableParentServersController', {
servers: servers, $scope: $scope }));
let cacheGroupServersTable;
diff --git
a/traffic_portal/app/src/common/modules/table/cdnServers/TableCDNServersController.js
b/traffic_portal/app/src/common/modules/table/cdnServers/TableCDNServersController.js
index f0b8df7..b6a4dca 100644
---
a/traffic_portal/app/src/common/modules/table/cdnServers/TableCDNServersController.js
+++
b/traffic_portal/app/src/common/modules/table/cdnServers/TableCDNServersController.js
@@ -19,8 +19,8 @@
var TableCDNServersController = function(cdn, servers, $controller, $scope) {
- // extends the TableServersController to inherit common methods
- angular.extend(this, $controller('TableServersController', { servers:
servers, $scope: $scope }));
+ // extends the TableParentServersController to inherit common methods
+ angular.extend(this, $controller('TableParentServersController', {
servers: servers, $scope: $scope }));
let cdnServersTable;
diff --git
a/traffic_portal/app/src/common/modules/table/deliveryServiceServers/TableDeliveryServiceServersController.js
b/traffic_portal/app/src/common/modules/table/deliveryServiceServers/TableDeliveryServiceServersController.js
index b343657..5d0c094 100644
---
a/traffic_portal/app/src/common/modules/table/deliveryServiceServers/TableDeliveryServiceServersController.js
+++
b/traffic_portal/app/src/common/modules/table/deliveryServiceServers/TableDeliveryServiceServersController.js
@@ -19,8 +19,8 @@
var TableDeliveryServiceServersController = function(deliveryService, servers,
$controller, $scope, $uibModal, deliveryServiceService, serverUtils) {
- // extends the TableServersController to inherit common methods
- angular.extend(this, $controller('TableServersController', { servers:
servers, $scope: $scope }));
+ // extends the TableParentServersController to inherit common methods
+ angular.extend(this, $controller('TableParentServersController', {
servers: servers, $scope: $scope }));
let dsServersTable;
diff --git
a/traffic_portal/app/src/common/modules/table/physLocationServers/TablePhysLocationServersController.js
b/traffic_portal/app/src/common/modules/table/physLocationServers/TablePhysLocationServersController.js
index 497eb6c..f329796 100644
---
a/traffic_portal/app/src/common/modules/table/physLocationServers/TablePhysLocationServersController.js
+++
b/traffic_portal/app/src/common/modules/table/physLocationServers/TablePhysLocationServersController.js
@@ -19,8 +19,8 @@
var TablePhysLocationServersController = function(physLocation, servers,
$controller, $scope) {
- // extends the TableServersController to inherit common methods
- angular.extend(this, $controller('TableServersController', { servers:
servers, $scope: $scope }));
+ // extends the TableParentServersController to inherit common methods
+ angular.extend(this, $controller('TableParentServersController', {
servers: servers, $scope: $scope }));
let physLocServersTable;
diff --git
a/traffic_portal/app/src/common/modules/table/profileServers/TableProfileServersController.js
b/traffic_portal/app/src/common/modules/table/profileServers/TableProfileServersController.js
index dbc2cf7..eff77f2 100644
---
a/traffic_portal/app/src/common/modules/table/profileServers/TableProfileServersController.js
+++
b/traffic_portal/app/src/common/modules/table/profileServers/TableProfileServersController.js
@@ -19,8 +19,8 @@
var TableProfileServersController = function(profile, servers, $controller,
$scope) {
- // extends the TableServersController to inherit common methods
- angular.extend(this, $controller('TableServersController', { servers:
servers, $scope: $scope }));
+ // extends the TableParentServersController to inherit common methods
+ angular.extend(this, $controller('TableParentServersController', {
servers: servers, $scope: $scope }));
let profileServersTable;
diff --git
a/traffic_portal/app/src/common/modules/table/serverCapabilityServers/TableServerCapabilityServersController.js
b/traffic_portal/app/src/common/modules/table/serverCapabilityServers/TableServerCapabilityServersController.js
index a6dad82..1afca89 100644
---
a/traffic_portal/app/src/common/modules/table/serverCapabilityServers/TableServerCapabilityServersController.js
+++
b/traffic_portal/app/src/common/modules/table/serverCapabilityServers/TableServerCapabilityServersController.js
@@ -19,8 +19,8 @@
var TableServerCapabilityServersController = function(serverCapability,
servers, $scope, $state, $controller, $uibModal, $window, locationUtils,
serverService, messageModel) {
- // extends the TableServersController to inherit common methods
- angular.extend(this, $controller('TableServersController', { servers:
servers, $scope: $scope }));
+ // extends the TableParentServersController to inherit common methods
+ angular.extend(this, $controller('TableParentServersController', {
servers: servers, $scope: $scope }));
var removeCapability = function(serverId) {
serverService.removeServerCapability(serverId,
serverCapability.name)
diff --git
a/traffic_portal/app/src/common/modules/table/servers/TableParentServersController.js
b/traffic_portal/app/src/common/modules/table/servers/TableParentServersController.js
new file mode 100644
index 0000000..5fb0adc
--- /dev/null
+++
b/traffic_portal/app/src/common/modules/table/servers/TableParentServersController.js
@@ -0,0 +1,421 @@
+/*
+ * 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 TableParentServersController = function(servers, $scope, $state,
$uibModal, $window, dateUtils, locationUtils, serverUtils, cdnService,
serverService, statusService, propertiesModel, messageModel) {
+
+ let serversTable;
+
+ var getStatuses = function() {
+ statusService.getStatuses()
+ .then(function(result) {
+ $scope.statuses = result;
+ });
+ };
+
+ var queueServerUpdates = function(server) {
+ serverService.queueServerUpdates(server.id)
+ .then(
+ function() {
+ $scope.refresh();
+ }
+ );
+ };
+
+ var clearServerUpdates = function(server) {
+ serverService.clearServerUpdates(server.id)
+ .then(
+ function() {
+ $scope.refresh();
+ }
+ );
+ };
+
+ var queueCDNServerUpdates = function(cdnId) {
+ cdnService.queueServerUpdates(cdnId)
+ .then(
+ function() {
+ $scope.refresh();
+ }
+ );
+ };
+
+ var clearCDNServerUpdates = function(cdnId) {
+ cdnService.clearServerUpdates(cdnId)
+ .then(
+ function() {
+ $scope.refresh();
+ }
+ );
+ };
+
+ var confirmDelete = function(server) {
+ var params = {
+ title: 'Delete Server: ' + server.hostName,
+ key: server.hostName
+ };
+ var modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/delete/dialog.delete.tpl.html',
+ controller: 'DialogDeleteController',
+ size: 'md',
+ resolve: {
+ params: function () {
+ return params;
+ }
+ }
+ });
+ modalInstance.result.then(function() {
+ deleteServer(server);
+ }, function () {
+ // do nothing
+ });
+ };
+
+ var deleteServer = function(server) {
+ serverService.deleteServer(server.id)
+ .then(function(result) {
+ messageModel.setMessages(result.alerts, false);
+ $scope.refresh();
+ });
+ };
+
+ var confirmStatusUpdate = function(server) {
+ var modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/select/status/dialog.select.status.tpl.html',
+ controller: 'DialogSelectStatusController',
+ size: 'md',
+ resolve: {
+ server: function() {
+ return server;
+ },
+ statuses: function() {
+ return $scope.statuses;
+ }
+ }
+ });
+ modalInstance.result.then(function(status) {
+ updateStatus(status, server);
+ }, function () {
+ // do nothing
+ });
+ };
+
+ var updateStatus = function(status, server) {
+ serverService.updateStatus(server.id, { status: status.id,
offlineReason: status.offlineReason })
+ .then(
+ function(result) {
+
messageModel.setMessages(result.data.alerts, false);
+ $scope.refresh();
+ },
+ function(fault) {
+
messageModel.setMessages(fault.data.alerts, false);
+ }
+ );
+ };
+
+ $scope.servers = servers;
+
+ $scope.columns = [
+ { "name": "Cache Group", "visible": true, "searchable": true },
+ { "name": "CDN", "visible": true, "searchable": true },
+ { "name": "Domain", "visible": true, "searchable": true },
+ { "name": "Host", "visible": true, "searchable": true },
+ { "name": "HTTPS Port", "visible": false, "searchable": false },
+ { "name": "ID", "visible": false, "searchable": false },
+ { "name": "ILO IP Address", "visible": true, "searchable": true
},
+ { "name": "ILO IP Gateway", "visible": false, "searchable":
false },
+ { "name": "ILO IP Netmask", "visible": false, "searchable":
false },
+ { "name": "ILO Username", "visible": false, "searchable": false
},
+ { "name": "Interface Name", "visible": false, "searchable":
false },
+ { "name": "IPv6 Address", "visible": true, "searchable": true },
+ { "name": "IPv6 Gateway", "visible": false, "searchable": false
},
+ { "name": "Last Updated", "visible": false, "searchable": false
},
+ { "name": "Mgmt IP Address", "visible": false, "searchable":
false },
+ { "name": "Mgmt IP Gateway", "visible": false, "searchable":
false },
+ { "name": "Mgmt IP Netmask", "visible": false, "searchable":
false },
+ { "name": "Network Gateway", "visible": false, "searchable":
false },
+ { "name": "Network IP", "visible": true, "searchable": true },
+ { "name": "Network MTU", "visible": false, "searchable": false
},
+ { "name": "Network Subnet", "visible": false, "searchable":
false },
+ { "name": "Offline Reason", "visible": false, "searchable":
false },
+ { "name": "Phys Location", "visible": true, "searchable": true
},
+ { "name": "Profile", "visible": true, "searchable": true },
+ { "name": "Rack", "visible": false, "searchable": false },
+ { "name": "Reval Pending", "visible": false, "searchable":
false },
+ { "name": "Router Hostname", "visible": false, "searchable":
false },
+ { "name": "Router Port Name", "visible": false, "searchable":
false },
+ { "name": "Status", "visible": true, "searchable": true },
+ { "name": "TCP Port", "visible": false, "searchable": false },
+ { "name": "Type", "visible": true, "searchable": true },
+ { "name": "Update Pending", "visible": true, "searchable": true
}
+ ];
+
+ $scope.contextMenuItems = [
+ {
+ text: 'Open in New Tab',
+ click: function ($itemScope) {
+ $window.open('/#!/servers/' + $itemScope.s.id,
'_blank');
+ }
+ },
+ null, // Divider
+ {
+ text: 'Navigate to Server FQDN',
+ click: function ($itemScope) {
+ $window.open('http://' + $itemScope.s.hostName
+ '.' + $itemScope.s.domainName, '_blank');
+ }
+ },
+ null, // Divider
+ {
+ text: 'Edit',
+ click: function ($itemScope) {
+ $scope.editServer($itemScope.s.id);
+ }
+ },
+ {
+ text: 'Delete',
+ click: function ($itemScope) {
+ confirmDelete($itemScope.s);
+ }
+ },
+ null, // Divider
+ {
+ text: 'Update Status',
+ click: function ($itemScope) {
+ confirmStatusUpdate($itemScope.s);
+ }
+ },
+ {
+ text: 'Queue Server Updates',
+ displayed: function ($itemScope) {
+ return serverUtils.isCache($itemScope.s) &&
!$itemScope.s.updPending;
+ },
+ click: function ($itemScope) {
+ queueServerUpdates($itemScope.s);
+ }
+ },
+ {
+ text: 'Clear Server Updates',
+ displayed: function ($itemScope) {
+ return serverUtils.isCache($itemScope.s) &&
$itemScope.s.updPending;
+ },
+ click: function ($itemScope) {
+ clearServerUpdates($itemScope.s);
+ }
+ },
+ {
+ text: 'Show Charts',
+ displayed: function () {
+ return
propertiesModel.properties.servers.charts.show;
+ },
+ hasBottomDivider: function () {
+ return true;
+ },
+ hasTopDivider: function () {
+ return true;
+ },
+ click: function ($itemScope) {
+
$window.open(propertiesModel.properties.servers.charts.baseUrl +
$itemScope.s.hostName, '_blank');
+ }
+ },
+ {
+ text: 'Manage Capabilities',
+ displayed: function ($itemScope) {
+ return serverUtils.isCache($itemScope.s);
+ },
+ hasTopDivider: function () {
+ return true;
+ },
+ click: function ($itemScope) {
+ locationUtils.navigateToPath('/servers/' +
$itemScope.s.id + '/capabilities');
+ }
+ },
+ {
+ text: 'Manage Delivery Services',
+ displayed: function ($itemScope) {
+ return serverUtils.isEdge($itemScope.s) ||
serverUtils.isOrigin($itemScope.s);
+ },
+ hasTopDivider: function ($itemScope) {
+ return !serverUtils.isCache($itemScope.s);
+ },
+ click: function ($itemScope) {
+ locationUtils.navigateToPath('/servers/' +
$itemScope.s.id + '/delivery-services');
+ }
+ },
+ {
+ text: 'View Config Files',
+ displayed: function ($itemScope) {
+ return serverUtils.isCache($itemScope.s);
+ },
+ click: function ($itemScope) {
+ locationUtils.navigateToPath('/servers/' +
$itemScope.s.id + '/config-files');
+ }
+ }
+ ];
+
+ $scope.editServer = function(id) {
+ locationUtils.navigateToPath('/servers/' + id);
+ };
+
+ $scope.createServer = function() {
+ locationUtils.navigateToPath('/servers/new');
+ };
+
+ $scope.confirmCDNQueueServerUpdates = function(cdn) {
+ var params;
+ if (cdn) {
+ params = {
+ title: 'Queue Server Updates: ' + cdn.name,
+ message: 'Are you sure you want to queue server
updates for all ' + cdn.name + ' servers?'
+ };
+ var modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/confirm/dialog.confirm.tpl.html',
+ controller: 'DialogConfirmController',
+ size: 'md',
+ resolve: {
+ params: function () {
+ return params;
+ }
+ }
+ });
+ modalInstance.result.then(function() {
+ queueCDNServerUpdates(cdn.id);
+ }, function () {
+ // do nothing
+ });
+ } else {
+ params = {
+ title: 'Queue Server Updates',
+ message: "Please select a CDN"
+ };
+ var modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/select/dialog.select.tpl.html',
+ controller: 'DialogSelectController',
+ size: 'md',
+ resolve: {
+ params: function () {
+ return params;
+ },
+ collection: function(cdnService) {
+ return cdnService.getCDNs();
+ }
+ }
+ });
+ modalInstance.result.then(function(cdn) {
+ queueCDNServerUpdates(cdn.id);
+ }, function () {
+ // do nothing
+ });
+ }
+ };
+
+ $scope.confirmCDNClearServerUpdates = function(cdn) {
+ var params;
+ if (cdn) {
+ params = {
+ title: 'Clear Server Updates: ' + cdn.name,
+ message: 'Are you sure you want to clear server
updates for all ' + cdn.name + ' servers?'
+ };
+ var modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/confirm/dialog.confirm.tpl.html',
+ controller: 'DialogConfirmController',
+ size: 'md',
+ resolve: {
+ params: function () {
+ return params;
+ }
+ }
+ });
+ modalInstance.result.then(function() {
+ clearCDNServerUpdates(cdn.id);
+ }, function () {
+ // do nothing
+ });
+
+
+ } else {
+ params = {
+ title: 'Clear Server Updates',
+ message: "Please select a CDN"
+ };
+ var modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/select/dialog.select.tpl.html',
+ controller: 'DialogSelectController',
+ size: 'md',
+ resolve: {
+ params: function () {
+ return params;
+ },
+ collection: function(cdnService) {
+ return cdnService.getCDNs();
+ }
+ }
+ });
+ modalInstance.result.then(function(cdn) {
+ clearCDNServerUpdates(cdn.id);
+ }, function () {
+ // do nothing
+ });
+ }
+ };
+
+ $scope.refresh = function() {
+ $state.reload(); // reloads all the resolves for the view
+ };
+
+ $scope.toggleVisibility = function(colName) {
+ const col = serversTable.column(colName + ':name');
+ col.visible(!col.visible());
+ serversTable.rows().invalidate().draw();
+ };
+
+ $scope.ssh = serverUtils.ssh;
+
+ $scope.isOffline = serverUtils.isOffline;
+
+ $scope.offlineReason = serverUtils.offlineReason;
+
+ $scope.getRelativeTime = dateUtils.getRelativeTime;
+
+ $scope.navigateToPath = locationUtils.navigateToPath;
+
+ var init = function () {
+ getStatuses();
+ };
+ init();
+
+ angular.element(document).ready(function () {
+ serversTable = $('#serversTable').DataTable({
+ "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
+ "iDisplayLength": 25,
+ "aaSorting": [],
+ "columns": $scope.columns,
+ "initComplete": function(settings, json) {
+ try {
+ // need to create the show/hide column
checkboxes and bind to the current visibility
+ $scope.columns =
JSON.parse(localStorage.getItem('DataTables_serversTable_/')).columns;
+ } catch (e) {
+ console.error("Failure to retrieve
required column info from localStorage (key=DataTables_serversTable_/):", e);
+ }
+ }
+ });
+ });
+
+};
+
+TableParentServersController.$inject = ['servers', '$scope', '$state',
'$uibModal', '$window', 'dateUtils', 'locationUtils', 'serverUtils',
'cdnService', 'serverService', 'statusService', 'propertiesModel',
'messageModel'];
+module.exports = TableParentServersController;
diff --git
a/traffic_portal/app/src/common/modules/table/servers/TableServersController.js
b/traffic_portal/app/src/common/modules/table/servers/TableServersController.js
index 4073abe..10ad816 100644
---
a/traffic_portal/app/src/common/modules/table/servers/TableServersController.js
+++
b/traffic_portal/app/src/common/modules/table/servers/TableServersController.js
@@ -17,405 +17,600 @@
* under the License.
*/
-var TableServersController = function(servers, $scope, $state, $uibModal,
$window, dateUtils, locationUtils, serverUtils, cdnService, serverService,
statusService, propertiesModel, messageModel) {
-
- let serversTable;
-
- var getStatuses = function() {
- statusService.getStatuses()
- .then(function(result) {
- $scope.statuses = result;
- });
- };
-
- var queueServerUpdates = function(server) {
- serverService.queueServerUpdates(server.id)
- .then(
- function() {
- $scope.refresh();
- }
- );
- };
-
- var clearServerUpdates = function(server) {
- serverService.clearServerUpdates(server.id)
- .then(
- function() {
- $scope.refresh();
- }
- );
- };
-
- var queueCDNServerUpdates = function(cdnId) {
- cdnService.queueServerUpdates(cdnId)
- .then(
- function() {
- $scope.refresh();
- }
- );
- };
-
- var clearCDNServerUpdates = function(cdnId) {
- cdnService.clearServerUpdates(cdnId)
- .then(
- function() {
- $scope.refresh();
- }
- );
- };
-
- var confirmDelete = function(server) {
- var params = {
- title: 'Delete Server: ' + server.hostName,
- key: server.hostName
- };
- var modalInstance = $uibModal.open({
- templateUrl: 'common/modules/dialog/delete/dialog.delete.tpl.html',
- controller: 'DialogDeleteController',
- size: 'md',
- resolve: {
- params: function () {
- return params;
- }
- }
- });
- modalInstance.result.then(function() {
- deleteServer(server);
- }, function () {
- // do nothing
- });
- };
-
- var deleteServer = function(server) {
- serverService.deleteServer(server.id)
- .then(function(result) {
- messageModel.setMessages(result.alerts, false);
- $scope.refresh();
- });
- };
-
- var confirmStatusUpdate = function(server) {
- var modalInstance = $uibModal.open({
- templateUrl:
'common/modules/dialog/select/status/dialog.select.status.tpl.html',
- controller: 'DialogSelectStatusController',
- size: 'md',
- resolve: {
- server: function() {
- return server;
- },
- statuses: function() {
- return $scope.statuses;
- }
- }
- });
- modalInstance.result.then(function(status) {
- updateStatus(status, server);
- }, function () {
- // do nothing
- });
- };
-
- var updateStatus = function(status, server) {
- serverService.updateStatus(server.id, { status: status.id,
offlineReason: status.offlineReason })
- .then(
- function(result) {
- messageModel.setMessages(result.data.alerts, false);
- $scope.refresh();
- },
- function(fault) {
- messageModel.setMessages(fault.data.alerts, false);
- }
- );
- };
-
- $scope.servers = servers;
-
- $scope.columns = [
- { "name": "Cache Group", "visible": true, "searchable": true },
- { "name": "CDN", "visible": true, "searchable": true },
- { "name": "Domain", "visible": true, "searchable": true },
- { "name": "Host", "visible": true, "searchable": true },
- { "name": "HTTPS Port", "visible": false, "searchable": false },
- { "name": "ID", "visible": false, "searchable": false },
- { "name": "ILO IP Address", "visible": true, "searchable": true },
- { "name": "ILO IP Gateway", "visible": false, "searchable": false },
- { "name": "ILO IP Netmask", "visible": false, "searchable": false },
- { "name": "ILO Username", "visible": false, "searchable": false },
- { "name": "Interface Name", "visible": false, "searchable": false },
- { "name": "IPv6 Address", "visible": true, "searchable": true },
- { "name": "IPv6 Gateway", "visible": false, "searchable": false },
- { "name": "Last Updated", "visible": false, "searchable": false },
- { "name": "Mgmt IP Address", "visible": false, "searchable": false },
- { "name": "Mgmt IP Gateway", "visible": false, "searchable": false },
- { "name": "Mgmt IP Netmask", "visible": false, "searchable": false },
- { "name": "Network Gateway", "visible": false, "searchable": false },
- { "name": "Network IP", "visible": true, "searchable": true },
- { "name": "Network MTU", "visible": false, "searchable": false },
- { "name": "Network Subnet", "visible": false, "searchable": false },
- { "name": "Offline Reason", "visible": false, "searchable": false },
- { "name": "Phys Location", "visible": true, "searchable": true },
- { "name": "Profile", "visible": true, "searchable": true },
- { "name": "Rack", "visible": false, "searchable": false },
- { "name": "Reval Pending", "visible": false, "searchable": false },
- { "name": "Router Hostname", "visible": false, "searchable": false },
- { "name": "Router Port Name", "visible": false, "searchable": false },
- { "name": "Status", "visible": true, "searchable": true },
- { "name": "TCP Port", "visible": false, "searchable": false },
- { "name": "Type", "visible": true, "searchable": true },
- { "name": "Update Pending", "visible": true, "searchable": true }
- ];
-
- $scope.contextMenuItems = [
- {
- text: 'Open in New Tab',
- click: function ($itemScope) {
- $window.open('/#!/servers/' + $itemScope.s.id, '_blank');
- }
- },
- null, // Divider
- {
- text: 'Navigate to Server FQDN',
- click: function ($itemScope) {
- $window.open('http://' + $itemScope.s.hostName + '.' +
$itemScope.s.domainName, '_blank');
- }
- },
- null, // Divider
- {
- text: 'Edit',
- click: function ($itemScope) {
- $scope.editServer($itemScope.s.id);
- }
- },
- {
- text: 'Delete',
- click: function ($itemScope) {
- confirmDelete($itemScope.s);
- }
- },
- null, // Divider
- {
- text: 'Update Status',
- click: function ($itemScope) {
- confirmStatusUpdate($itemScope.s);
- }
- },
- {
- text: 'Queue Server Updates',
- displayed: function ($itemScope) {
- return serverUtils.isCache($itemScope.s) &&
!$itemScope.s.updPending;
- },
- click: function ($itemScope) {
- queueServerUpdates($itemScope.s);
- }
- },
- {
- text: 'Clear Server Updates',
- displayed: function ($itemScope) {
- return serverUtils.isCache($itemScope.s) &&
$itemScope.s.updPending;
- },
- click: function ($itemScope) {
- clearServerUpdates($itemScope.s);
- }
- },
- {
- text: 'Show Charts',
- displayed: function () {
- return propertiesModel.properties.servers.charts.show;
- },
- hasBottomDivider: function () {
- return true;
- },
- hasTopDivider: function () {
- return true;
- },
- click: function ($itemScope) {
- $window.open(propertiesModel.properties.servers.charts.baseUrl
+ $itemScope.s.hostName, '_blank');
- }
- },
- {
- text: 'Manage Capabilities',
- displayed: function ($itemScope) {
- return serverUtils.isCache($itemScope.s);
- },
- hasTopDivider: function () {
- return true;
- },
- click: function ($itemScope) {
- locationUtils.navigateToPath('/servers/' + $itemScope.s.id +
'/capabilities');
- }
- },
- {
- text: 'Manage Delivery Services',
- displayed: function ($itemScope) {
- return serverUtils.isEdge($itemScope.s) ||
serverUtils.isOrigin($itemScope.s);
- },
- hasTopDivider: function ($itemScope) {
- return !serverUtils.isCache($itemScope.s);
- },
- click: function ($itemScope) {
- locationUtils.navigateToPath('/servers/' + $itemScope.s.id +
'/delivery-services');
- }
- },
- {
- text: 'View Config Files',
- displayed: function ($itemScope) {
- return serverUtils.isCache($itemScope.s);
- },
- click: function ($itemScope) {
- locationUtils.navigateToPath('/servers/' + $itemScope.s.id +
'/config-files');
- }
- }
- ];
-
- $scope.editServer = function(id) {
- locationUtils.navigateToPath('/servers/' + id);
- };
-
- $scope.createServer = function() {
- locationUtils.navigateToPath('/servers/new');
- };
-
- $scope.confirmCDNQueueServerUpdates = function(cdn) {
- var params;
- if (cdn) {
- params = {
- title: 'Queue Server Updates: ' + cdn.name,
- message: 'Are you sure you want to queue server updates for
all ' + cdn.name + ' servers?'
- };
- var modalInstance = $uibModal.open({
- templateUrl:
'common/modules/dialog/confirm/dialog.confirm.tpl.html',
- controller: 'DialogConfirmController',
- size: 'md',
- resolve: {
- params: function () {
- return params;
- }
- }
- });
- modalInstance.result.then(function() {
- queueCDNServerUpdates(cdn.id);
- }, function () {
- // do nothing
- });
- } else {
- params = {
- title: 'Queue Server Updates',
- message: "Please select a CDN"
- };
- var modalInstance = $uibModal.open({
- templateUrl:
'common/modules/dialog/select/dialog.select.tpl.html',
- controller: 'DialogSelectController',
- size: 'md',
- resolve: {
- params: function () {
- return params;
- },
- collection: function(cdnService) {
- return cdnService.getCDNs();
- }
- }
- });
- modalInstance.result.then(function(cdn) {
- queueCDNServerUpdates(cdn.id);
- }, function () {
- // do nothing
- });
- }
- };
-
- $scope.confirmCDNClearServerUpdates = function(cdn) {
- var params;
- if (cdn) {
- params = {
- title: 'Clear Server Updates: ' + cdn.name,
- message: 'Are you sure you want to clear server updates for
all ' + cdn.name + ' servers?'
- };
- var modalInstance = $uibModal.open({
- templateUrl:
'common/modules/dialog/confirm/dialog.confirm.tpl.html',
- controller: 'DialogConfirmController',
- size: 'md',
- resolve: {
- params: function () {
- return params;
- }
- }
- });
- modalInstance.result.then(function() {
- clearCDNServerUpdates(cdn.id);
- }, function () {
- // do nothing
- });
-
-
- } else {
- params = {
- title: 'Clear Server Updates',
- message: "Please select a CDN"
- };
- var modalInstance = $uibModal.open({
- templateUrl:
'common/modules/dialog/select/dialog.select.tpl.html',
- controller: 'DialogSelectController',
- size: 'md',
- resolve: {
- params: function () {
- return params;
- },
- collection: function(cdnService) {
- return cdnService.getCDNs();
- }
- }
- });
- modalInstance.result.then(function(cdn) {
- clearCDNServerUpdates(cdn.id);
- }, function () {
- // do nothing
- });
- }
- };
-
- $scope.refresh = function() {
- $state.reload(); // reloads all the resolves for the view
- };
-
- $scope.toggleVisibility = function(colName) {
- const col = serversTable.column(colName + ':name');
- col.visible(!col.visible());
- serversTable.rows().invalidate().draw();
- };
-
- $scope.ssh = serverUtils.ssh;
-
- $scope.isOffline = serverUtils.isOffline;
-
- $scope.offlineReason = serverUtils.offlineReason;
-
- $scope.getRelativeTime = dateUtils.getRelativeTime;
-
- $scope.navigateToPath = locationUtils.navigateToPath;
-
- var init = function () {
- getStatuses();
- };
- init();
-
- angular.element(document).ready(function () {
- serversTable = $('#serversTable').DataTable({
- "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
- "iDisplayLength": 25,
- "aaSorting": [],
- "columns": $scope.columns,
- "initComplete": function(settings, json) {
- try {
- // need to create the show/hide column checkboxes and bind
to the current visibility
- $scope.columns =
JSON.parse(localStorage.getItem('DataTables_serversTable_/')).columns;
- } catch (e) {
- console.error("Failure to retrieve required column info
from localStorage (key=DataTables_serversTable_/):", e);
- }
- }
- });
- });
+var TableServersController = function(servers, $scope, $state, $uibModal,
$window, dateUtils, locationUtils, serverUtils, cdnService, serverService,
statusService, propertiesModel, messageModel, userModel, $document) {
+ /**** Table cell formatters/renderers ****/
+ // browserify can't handle classes...
+ function SSHCellRenderer() {}
+ SSHCellRenderer.prototype.init = function(params) {
+ this.eGui = document.createElement("A");
+ this.eGui.href = "ssh://" + userModel.user.username + "@" +
params.value;
+ this.eGui.setAttribute("target", "_blank");
+ this.eGui.textContent = params.value;
+ };
+ SSHCellRenderer.prototype.getGui = function() {return this.eGui;};
+
+ function UpdateCellRenderer() {}
+ UpdateCellRenderer.prototype.init = function(params) {
+ this.eGui = document.createElement("I");
+ this.eGui.setAttribute("aria-hidden", "true");
+ this.eGui.setAttribute("title", String(params.value));
+ this.eGui.classList.add("fa", "fa-lg");
+ if (params.value) {
+ this.eGui.classList.add("fa-clock-o");
+ } else {
+ this.eGui.classList.add("fa-check");
+ }
+ }
+ UpdateCellRenderer.prototype.getGui = function() {return this.eGui;};
+
+ /**
+ * Gets text with which to file a status tooltip.
+ * @returns {string | undefined} The offline reason if the server is
offline, otherwise nothing.
+ */
+ function offlineReasonTooltip(params) {
+ if (!params.value || !serverUtils.isOffline(params.value)) {
+ return;
+ }
+ return params.data.offlineReason;
+ }
+
+ /**
+ * Formats the contents of a 'lastUpdated' column cell as "relative to
now".
+ */
+ function dateCellFormatter(params) {
+ return dateUtils.getRelativeTime(params.value);
+ }
+
+
+ /**** Constants, scope data, etc. ****/
+
+ /** The columns of the ag-grid table */
+ const columns = [
+ {
+ headerName: "Cache Group",
+ field: "cachegroup",
+ hide: false,
+ },
+ {
+ headerName: "CDN",
+ field: "cdnName",
+ hide: false,
+ },
+ {
+ headerName: "Domain",
+ field: "domainName",
+ hide: false,
+ },
+ {
+ headerName: "Host",
+ field: "hostName",
+ hide: false,
+ },
+ {
+ headerName: "HTTPS Port",
+ field: "httpsPort",
+ hide: true,
+ filter: "agNumberColumnFilter"
+ },
+ {
+ headerName: "ID",
+ field: "id",
+ hide: true,
+ filter: "agNumberColumnFilter"
+ },
+ {
+ headerName: "ILO IP Address",
+ field: "iloIpAddress",
+ hide: true,
+ cellRenderer: "sshCellRenderer",
+ onCellClicked: null
+ },
+ {
+ headerName: "ILO IP Gateway",
+ field: "iloIpGateway",
+ hide: true,
+ cellRenderer: "sshCellRenderer",
+ onCellClicked: null
+ },
+ {
+ headerName: "ILO IP Netmask",
+ field: "iloIpNetmask",
+ hide: true,
+ },
+ {
+ headerName: "ILO Username",
+ field: "iloUsername",
+ hide: true,
+ },
+ {
+ headerName: "Interface Name",
+ field: "interfaceName",
+ hide: true,
+ },
+ {
+ headerName: "IPv6 Address",
+ field: "ipv6Address",
+ hide: false,
+ },
+ {
+ headerName: "IPv6 Gateway",
+ field: "ipv6Gateway",
+ hide: true,
+ },
+ {
+ headerName: "Last Updated",
+ field: "lastUpdated",
+ hide: true,
+ filter: "agDateColumnFilter",
+ valueFormatter: dateCellFormatter
+ },
+ {
+ headerName: "Mgmt IP Address",
+ field: "mgmtIpAddress",
+ hide: true,
+ },
+ {
+ headerName: "Mgmt IP Gateway",
+ field: "mgmtIpGateway",
+ hide: true,
+ filter: true,
+ cellRenderer: "sshCellRenderer",
+ onCellClicked: null
+ },
+ {
+ headerName: "Mgmt IP Netmask",
+ field: "mgmtIpNetmask",
+ hide: true,
+ filter: true,
+ cellRenderer: "sshCellRenderer",
+ onCellClicked: null
+ },
+ {
+ headerName: "Network Gateway",
+ field: "ipGateway",
+ hide: true,
+ filter: true,
+ cellRenderer: "sshCellRenderer",
+ onCellClicked: null
+ },
+ {
+ headerName: "Network IP",
+ field: "ipAddress",
+ hide: false,
+ filter: true,
+ cellRenderer: "sshCellRenderer",
+ onCellClicked: null
+ },
+ {
+ headerName: "Network MTU",
+ field: "interfaceMtu",
+ hide: true,
+ filter: "agNumberColumnFilter"
+ },
+ {
+ headerName: "Network Subnet",
+ field: "ipNetmask",
+ hide: true,
+ },
+ {
+ headerName: "Offline Reason",
+ field: "offlineReason",
+ hide: true,
+ },
+ {
+ headerName: "Phys Location",
+ field: "physLocation",
+ hide: true,
+ },
+ {
+ headerName: "Profile",
+ field: "profile",
+ hide: false,
+ },
+ {
+ headerName: "Rack",
+ field: "rack",
+ hide: true,
+ },
+ {
+ headerName: "Reval Pending",
+ field: "revalPending",
+ hide: true,
+ filter: true,
+ cellRenderer: "updateCellRenderer"
+ },
+ {
+ headerName: "Router Hostname",
+ field: "routerHostName",
+ hide: true,
+ },
+ {
+ headerName: "Router Port Name",
+ field: "routerPortName",
+ hide: true,
+ },
+ {
+ headerName: "Status",
+ field: "status",
+ hide: false,
+ tooltip: offlineReasonTooltip
+ },
+ {
+ headerName: "TCP Port",
+ field: "tcpPort",
+ hide: true,
+ },
+ {
+ headerName: "Type",
+ field: "type",
+ hide: false,
+ },
+ {
+ headerName: "Update Pending",
+ field: "updPending",
+ hide: false,
+ filter: true,
+ cellRenderer: "updateCellRenderer"
+ }
+ ];
+
+ /** All of the statuses (populated on init). */
+ let statuses = [];
+
+ /** All of the servers - lastUpdated fields converted to actual Dates.
*/
+ $scope.servers = servers.map(function(x){x.lastUpdated = x.lastUpdated
? new Date(x.lastUpdated.replace("+00", "Z")) : x.lastUpdated;});
+
+ /** The base URL to use for constructing links to server charts. */
+ $scope.chartsBase = propertiesModel.properties.servers.charts.baseUrl;
+
+ /** The currently selected server - at the moment only used by the
context menu */
+ $scope.server = {
+ hostName: "",
+ domainName: "",
+ id: -1
+ };
+
+ /** Options, configuration, data and callbacks for the ag-grid table. */
+ $scope.gridOptions = {
+ components: {
+ sshCellRenderer: SSHCellRenderer,
+ updateCellRenderer: UpdateCellRenderer
+ },
+ columnDefs: columns,
+ defaultColDef: {
+ filter: true,
+ onCellClicked: function(params) {
+
locationUtils.navigateToPath('/servers/' + params.data.id);
+ // Event is outside the digest cycle,
so we need to trigger one.
+ $scope.$apply();
+ },
+ sortable: true,
+ resizable: true
+ },
+ rowData: servers,
+ pagination: true,
+ rowBuffer: 0,
+ onColumnResized: function(params) {
+ localStorage.setItem("servers_table_columns",
JSON.stringify($scope.gridOptions.columnApi.getColumnState()));
+ },
+ tooltipShowDelay: 500,
+ allowContextMenuWithControlKey: true,
+ preventDefaultOnContextMenu: true,
+ onCellContextMenu: function(params) {
+ $scope.showMenu = true;
+ $scope.menuStyle.left = String(params.event.pageX) +
"px";
+ $scope.menuStyle.top = String(params.event.pageY) +
"px";
+ $scope.server = params.data;
+ $scope.$apply();
+ },
+ colResizeDefault: "shift"
+ };
+
+ /** These three functions are used by the context menu to determine
what functionality to provide for a server. */
+ $scope.isCache = serverUtils.isCache;
+ $scope.isEdge = serverUtils.isEdge;
+ $scope.isOrigin = serverUtils.isOrigin;
+
+ /** Used by the context menu to determine whether or not to include
links to server charts. */
+ $scope.showCharts = propertiesModel.properties.servers.charts.show;
+
+ /** This is used to position the context menu under the cursor. */
+ $scope.menuStyle = {
+ left: 0,
+ top: 0,
+ };
+
+ /** Controls whether or not the context menu is visible. */
+ $scope.showMenu = false;
+
+
+ /**** Miscellaneous scope functions ****/
+
+ /** Reloads all 'resolve'd data for the view. */
+ $scope.refresh = function() {
+ $state.reload();
+ };
+
+ /** Toggles the visibility of a column that has the ID provided as
'col'. */
+ $scope.toggleVisibility = function(col) {
+ const visible =
$scope.gridOptions.columnApi.getColumn(col).isVisible();
+ $scope.gridOptions.columnApi.setColumnVisible(col, !visible);
+ };
+
+ /** Downloads the table as a CSV */
+ $scope.exportCSV = function() {
+ // TODO: figure out how to reconcile clicking on a server
taking you to it
+ // with row selection exports.
+ const params = {
+ allColumns: true,
+ fileName: "servers.csv",
+ };
+ $scope.gridOptions.api.exportDataAsCsv(params);
+ }
+
+ /**** Context menu functions ****/
+
+ $scope.queueServerUpdates = function(server, event) {
+ event.stopPropagation();
+
serverService.queueServerUpdates(server.id).then($scope.refresh);
+ };
+
+ $scope.clearServerUpdates = function(server, event) {
+ event.stopPropagation();
+
serverService.clearServerUpdates(server.id).then($scope.refresh);
+ };
+
+ $scope.confirmDelete = function(server, event) {
+ event.stopPropagation();
+
+ const params = {
+ title: 'Delete Server: ' + server.hostName,
+ key: server.hostName
+ };
+ const modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/delete/dialog.delete.tpl.html',
+ controller: 'DialogDeleteController',
+ size: 'md',
+ resolve: {
+ params: function () {
+ return params;
+ }
+ }
+ });
+ modalInstance.result.then(
+ function() {
+ serverService.deleteServer(server.id).then(
+ function(result) {
+
messageModel.setMessages(result.alerts, false);
+ $scope.refresh();
+ },
+ function(err) {
+ // TODO: use template strings
once the build can handle them.
+ console.error("Error deleting
server", server.hostName + "." + server.domainName, "(#" + String(server.id) +
"):", err);
+ }
+ );
+ },
+ function() {
+ // This is just a cancel event from closing the
dialog, do nothing.
+ }
+ );
+ };
+
+ /**
+ * updateStatus sets the status of the given server to the given status
value.
+ *
+ * @param {{id: number, offlineReason?: string}} status The numeric ID
of the status to set along with a reason why it was set offline, if applicable.
+ * @param {{id: number}} server The server (or at least its numeric ID)
which will have its status set.
+ */
+ function updateStatus(status, server) {
+ const params = {
+ status: status.id,
+ offlineReason: status.offlineReason
+ };
+
+ serverService.updateStatus(server.id, params).then(
+ function(result) {
+ messageModel.setMessages(result.data.alerts,
false);
+ $scope.refresh();
+ },
+ function(fault) {
+ messageModel.setMessages(fault.data.alerts,
false);
+ }
+ );
+ };
+
+ $scope.confirmStatusUpdate = function(server, event) {
+ event.stopPropagation();
+
+ const modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/select/status/dialog.select.status.tpl.html',
+ controller: 'DialogSelectStatusController',
+ size: 'md',
+ resolve: {
+ server: function() {
+ return server;
+ },
+ statuses: function() {
+ return statuses;
+ }
+ }
+ });
+ modalInstance.result.then(
+ function(status) {
+ updateStatus(status, server);
+ },
+ function () {
+ // this is just a cancel event from closing the
dialog, do nothing
+ }
+ );
+ };
+
+ $scope.confirmCDNQueueServerUpdates = function(cdn) {
+ let params;
+ if (cdn) {
+ params = {
+ title: 'Queue Server Updates: ' + cdn.name,
+ message: 'Are you sure you want to queue server
updates for all ' + cdn.name + ' servers?'
+ };
+ const modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/confirm/dialog.confirm.tpl.html',
+ controller: 'DialogConfirmController',
+ size: 'md',
+ resolve: {
+ params: function () {
+ return params;
+ }
+ }
+ });
+ modalInstance.result.then(function() {
+
cdnService.queueServerUpdates(cdn.id).then($scope.refresh);
+ }, function () {
+ // this is just a cancel event from closing the
dialog, do nothing
+ });
+ } else {
+ params = {
+ title: 'Queue Server Updates',
+ message: "Please select a CDN"
+ };
+ const modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/select/dialog.select.tpl.html',
+ controller: 'DialogSelectController',
+ size: 'md',
+ resolve: {
+ params: function () {
+ return params;
+ },
+ collection: function(cdnService) {
+ return cdnService.getCDNs();
+ }
+ }
+ });
+ modalInstance.result.then(function(cdn) {
+
cdnService.queueServerUpdates(cdn.id).then($scope.refresh);
+ }, function () {
+ // do nothing
+ });
+ }
+ };
+
+ $scope.confirmCDNClearServerUpdates = function(cdn) {
+ let params;
+ if (cdn) {
+ params = {
+ title: 'Clear Server Updates: ' + cdn.name,
+ message: 'Are you sure you want to clear server
updates for all ' + cdn.name + ' servers?'
+ };
+ const modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/confirm/dialog.confirm.tpl.html',
+ controller: 'DialogConfirmController',
+ size: 'md',
+ resolve: {
+ params: function () {
+ return params;
+ }
+ }
+ });
+ modalInstance.result.then(function() {
+
cdnService.clearServerUpdates(cdn.id).then($scope.refresh);
+ }, function () {
+ // do nothing
+ });
+
+
+ } else {
+ params = {
+ title: 'Clear Server Updates',
+ message: "Please select a CDN"
+ };
+ const modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/select/dialog.select.tpl.html',
+ controller: 'DialogSelectController',
+ size: 'md',
+ resolve: {
+ params: function () {
+ return params;
+ },
+ collection: function(cdnService) {
+ return cdnService.getCDNs();
+ }
+ }
+ });
+ modalInstance.result.then(function(cdn) {
+
cdnService.clearServerUpdates(cdn.id).then($scope.refresh);
+ }, function () {
+ // do nothing
+ });
+ }
+ };
+
+
+ /**** Initialization code, including loading user columns from
localstorage ****/
+ angular.element(document).ready(function () {
+ try {
+ // need to create the show/hide column checkboxes and
bind to the current visibility
+ const colstates =
JSON.parse(localStorage.getItem("servers_table_columns"));
+ if (colstates) {
+ if
(!$scope.gridOptions.columnApi.setColumnState(colstates)) {
+ console.error("Failed to load stored
column state: one or more columns not found");
+ }
+ } else {
+ $scope.gridOptions.api.sizeColumnsToFit();
+ }
+ } catch (e) {
+ console.error("Failure to retrieve required column info
from localStorage (key=servers_table_columns):", e);
+ }
+
+ try {
+ const filterState =
JSON.parse(localStorage.getItem("servers_table_filters"));
+ $scope.gridOptions.api.setFilterModel(filterState);
+ } catch (e) {
+ console.error("Failure to load stored filter state:",
e);
+ }
+
+ $scope.gridOptions.api.addEventListener("filterChanged",
function() {
+ localStorage.setItem("servers_table_filters",
JSON.stringify($scope.gridOptions.api.getFilterModel()));
+ });
+
+ try {
+ const sortState =
JSON.parse(localStorage.getItem("servers_table_sort"));
+ $scope.gridOptions.api.setSortModel(sortState);
+ } catch (e) {
+ console.error("Failure to load stored sort state:", e);
+ }
+
+ $scope.gridOptions.api.addEventListener("sortChanged",
function() {
+ localStorage.setItem("servers_table_sort",
JSON.stringify($scope.gridOptions.api.getSortModel()));
+ });
+
+ $scope.gridOptions.api.addEventListener("columnMoved",
function() {
+ localStorage.setItem("servers_table_columns",
JSON.stringify($scope.gridOptions.columnApi.getColumnState()));
+ });
+
+ $scope.gridOptions.api.addEventListener("columnVisible",
function() {
+ $scope.gridOptions.api.sizeColumnsToFit();
+ try {
+ colStates =
$scope.gridOptions.columnApi.getColumnState();
+ localStorage.setItem("servers_table_columns",
JSON.stringify(colStates));
+ } catch (e) {
+ console.error("Failed to store column defs to
local storage:", e);
+ }
+ });
+
+ // clicks outside the context menu will hide it
+ $document.bind("click", function(e) {
+ $scope.showMenu = false;
+ e.stopPropagation();
+ $scope.$apply();
+ });
+
+ statusService.getStatuses().then(
+ function(result) {
+ statuses = result;
+ }
+ );
+ });
};
-TableServersController.$inject = ['servers', '$scope', '$state', '$uibModal',
'$window', 'dateUtils', 'locationUtils', 'serverUtils', 'cdnService',
'serverService', 'statusService', 'propertiesModel', 'messageModel'];
+TableServersController.$inject = ['servers', '$scope', '$state', '$uibModal',
'$window', 'dateUtils', 'locationUtils', 'serverUtils', 'cdnService',
'serverService', 'statusService', 'propertiesModel', 'messageModel',
"userModel", "$document"];
module.exports = TableServersController;
diff --git a/traffic_portal/app/src/common/modules/table/servers/index.js
b/traffic_portal/app/src/common/modules/table/servers/index.js
index e955714..2b5d9b5 100644
--- a/traffic_portal/app/src/common/modules/table/servers/index.js
+++ b/traffic_portal/app/src/common/modules/table/servers/index.js
@@ -18,4 +18,5 @@
*/
module.exports = angular.module('trafficPortal.table.servers', [])
- .controller('TableServersController', require('./TableServersController'));
+ .controller('TableServersController', require('./TableServersController'))
+ .controller('TableParentServersController',
require('./TableParentServersController'));
diff --git
a/traffic_portal/app/src/common/modules/table/servers/table.servers.tpl.html
b/traffic_portal/app/src/common/modules/table/servers/table.servers.tpl.html
index 9c3dce4..4d36373 100644
--- a/traffic_portal/app/src/common/modules/table/servers/table.servers.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/servers/table.servers.tpl.html
@@ -23,7 +23,7 @@ under the License.
<li class="active">Servers</li>
</ol>
<div class="pull-right">
- <button class="btn btn-primary" name="createServersButton"
title="Create Server" ng-click="createServer()"><i class="fa
fa-plus"></i></button>
+ <a class="btn btn-primary" name="createServersButton"
title="Create Server" href="#!/servers/new"><i class="fa fa-plus"></i></a>
<button class="btn btn-default" title="Refresh"
ng-click="refresh()"><i class="fa fa-refresh"></i></button>
<div id="toggleColumns" class="btn-group" role="group"
title="Select Table Columns" uib-dropdown is-open="columnSettings.isopen">
<button type="button" class="btn btn-default dropdown-toggle"
uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
@@ -31,9 +31,9 @@ under the License.
<span class="caret"></span>
</button>
<menu ng-click="$event.stopPropagation()"
class="column-settings dropdown-menu-right dropdown-menu" uib-dropdown-menu>
- <li role="menuitem" ng-repeat="c in columns |
orderBy:'name'">
+ <li role="menuitem" ng-repeat="c in
gridOptions.columnApi.getAllColumns() | orderBy:'colDef.headerName'">
<div class="checkbox">
- <label><input type="checkbox" ng-model="c.visible"
ng-click="toggleVisibility(c.name)"> {{::c.name}}</label>
+ <label><input type="checkbox"
ng-checked="c.isVisible()"
ng-click="toggleVisibility(c.colId)">{{::c.colDef.headerName}}</label>
</div>
</li>
</menu>
@@ -46,99 +46,53 @@ under the License.
<ul class="dropdown-menu-right dropdown-menu"
uib-dropdown-menu>
<li role="menuitem"><a
ng-click="confirmCDNQueueServerUpdates(null)">Queue CDN Server Updates</a></li>
<li role="menuitem"><a
ng-click="confirmCDNClearServerUpdates(null)">Clear CDN Server Updates</a></li>
+ <li role="menuitem"><button class="menu-item-button"
type="button" ng-click="exportCSV()">Export CSV</button></li>
</ul>
</div>
</div>
<div class="clearfix"></div>
</div>
<div class="x_content">
- <br>
- <table id="serversTable" class="table responsive-utilities
jambo_table">
- <thead>
- <tr class="headings">
- <th>Cache Group</th>
- <th>CDN</th>
- <th>Domain</th>
- <th>Host</th>
- <th>HTTPS Port</th>
- <th>ID</th>
- <th>ILO IP Address</th>
- <th>ILO IP Gateway</th>
- <th>ILO IP Netmask</th>
- <th>ILO Username</th>
- <th>Interface Name</th>
- <th>IPv6 Address</th>
- <th>IPv6 Gateway</th>
- <th>Last Updated</th>
- <th>Mgmt IP Address</th>
- <th>Mgmt IP Gateway</th>
- <th>Mgmt IP Netmask</th>
- <th>Network Gateway</th>
- <th>Network IP</th>
- <th>Network MTU</th>
- <th>Network Subnet</th>
- <th>Offline Reason</th>
- <th>Phys Location</th>
- <th>Profile</th>
- <th>Rack</th>
- <th>Reval Pending</th>
- <th>Router Hostname</th>
- <th>Router Port Name</th>
- <th>Status</th>
- <th>TCP Port</th>
- <th>Type</th>
- <th>Update Pending</th>
- </tr>
- </thead>
- <tbody>
- <tr ng-click="editServer(s.id)" ng-repeat="s in ::servers"
ng-class="::{'active': s.updPending}" context-menu="contextMenuItems">
- <td
data-search="^{{::s.cachegroup}}$">{{::s.cachegroup}}</td>
- <td data-search="^{{::s.cdnName}}$">{{::s.cdnName}}</td>
- <td
data-search="^{{::s.domainName}}$">{{::s.domainName}}</td>
- <td name="hostName"
data-search="^{{::s.hostName}}$">{{::s.hostName}}</td>
- <td
data-search="^{{::s.httpsPort}}$">{{::s.httpsPort}}</td>
- <td data-search="^{{::s.id}}$">{{::s.id}}</td>
- <td data-search="^{{::s.iloIpAddress}}$"><a
ng-click="ssh(s.iloIpAddress, $event)">{{::s.iloIpAddress}}</a></td>
- <td data-search="^{{::s.iloIpGateway}}$"><a
ng-click="ssh(s.iloIpGateway, $event)">{{::s.iloIpGateway}}</a></td>
- <td
data-search="^{{::s.iloIpNetmask}}$">{{::s.iloIpNetmask}}</td>
- <td
data-search="^{{::s.iloUsername}}$">{{::s.iloUsername}}</td>
- <td
data-search="^{{::s.interfaceName}}$">{{::s.interfaceName}}</td>
- <td
data-search="^{{::s.ip6Address}}$">{{::s.ip6Address}}</td>
- <td
data-search="^{{::s.ip6Gateway}}$">{{::s.ip6Gateway}}</td>
- <td data-search="^{{::getRelativeTime(s.lastUpdated)}}$"
data-order="{{::s.lastUpdated}}">{{::getRelativeTime(s.lastUpdated)}}</td>
- <td data-search="^{{::s.mgmtIpAddress}}$"><a
ng-click="ssh(s.mgmtIpAddress, $event)">{{::s.mgmtIpAddress}}</a></td>
- <td data-search="^{{::s.mgmtIpGateway}}$"><a
ng-click="ssh(s.mgmtIpGateway, $event)">{{::s.mgmtIpGateway}}</a></td>
- <td
data-search="^{{::s.mgmtIpNetmask}}$">{{::s.mgmtIpNetmask}}</td>
- <td data-search="^{{::s.ipGateway}}$"><a
ng-click="ssh(s.ipGateway, $event)">{{::s.ipGateway}}</a></td>
- <td data-search="^{{::s.ipAddress}}$"><a
ng-click="ssh(s.ipAddress, $event)">{{::s.ipAddress}}</a></td>
- <td
data-search="^{{::s.interfaceMtu}}$">{{::s.interfaceMtu}}</td>
- <td
data-search="^{{::s.ipNetmask}}$">{{::s.ipNetmask}}</td>
- <td
data-search="^{{::s.offlineReason}}$">{{::s.offlineReason}}</td>
- <td
data-search="^{{::s.physLocation}}$">{{::s.physLocation}}</td>
- <td data-search="^{{::s.profile}}$">{{::s.profile}}</td>
- <td data-search="^{{::s.rack}}$">{{::s.rack}}</td>
- <td data-search="{{(s.revalPending) ? 'RVL' : ''}}"
data-order="{{::s.revalPending}}">
- <i title="Reval Pending (RVL)"
ng-show="s.revalPending" class="fa fa-clock-o fa-lg" aria-hidden="true"></i>
- <i title="Reval Applied" ng-show="!s.revalPending"
class="fa fa-check fa-lg" aria-hidden="true"></i>
- </td>
- <td
data-search="^{{::s.routerHostName}}$">{{::s.routerHostName}}</td>
- <td
data-search="^{{::s.routerPortName}}$">{{::s.routerPortName}}</td>
- <td data-search="^{{::s.status}}$">
- <span
ng-if="!isOffline(s.status)">{{::s.status}}</span>
- <span ng-if="isOffline(s.status)"
uib-popover="{{::offlineReason(s)}}" popover-title="Offline Reason"
popover-trigger="mouseenter" popover-placement="bottom"
popover-append-to-body="true">{{::s.status}}</span>
- </td>
- <td data-search="^{{::s.tcpPort}}$">{{::s.tcpPort}}</td>
- <td data-search="^{{::s.type}}$">{{::s.type}}</td>
- <td data-search="{{(s.updPending) ? 'UPD' : ''}}"
data-order="{{::s.updPending}}">
- <i title="Updates Pending (UPD)"
ng-show="s.updPending" class="fa fa-clock-o fa-lg" aria-hidden="true"></i>
- <i title="Updates Applied" ng-show="!s.updPending"
class="fa fa-check fa-lg" aria-hidden="true"></i>
- </td>
- </tr>
- </tbody>
- </table>
+ <div style="height: 740px;" ag-grid="gridOptions"
class="ag-theme-alpine"></div>
</div>
</div>
-
-
-
+<menu class="dropdown-menu" ng-style="menuStyle" type="contextmenu"
ng-show="showMenu">
+ <ul>
+ <li role="menuitem">
+ <a ng-href="#!/servers/{{server.id}}" target="_blank">Open in New
Tab</a>
+ </li>
+ <hr class="divider"/>
+ <li role="menuitem">
+ <a ng-href="http://{{server.hostName}}.{{server.domainName}}"
target="_blank">Navigate To Server FQDN</a>
+ </li>
+ <hr class="divider"/>
+ <li role="menuitem">
+ <a ng-href="#!/servers/{{server.id}}">Edit</a>
+ </li>
+ <li role="menuitem">
+ <button type="button" ng-click="confirmDelete(server,
$event)">Delete</button>
+ </li>
+ <hr class="divider"/>
+ <li role="menuitem">
+ <button type="button" ng-click="confirmStatusUpdate(server,
$event)">Update Status</button>
+ </li>
+ <li role="menuitem">
+ <button type="button" ng-click="queueServerUpdates(server,
$event)" ng-disabled="!isCache(server) || server.updPending">Queue Server
Updates</button>
+ </li>
+ <li role="menuitem">
+ <button type="button" ng-click="clearServerUpdates(server,
$event)" ng-disabled="!isCache(server) || !server.updPending">Clear Server
Updates</button>
+ </li>
+ <hr class="divider"/>
+ <li role="menuitem" ng-if="showCharts">
+ <a ng-href="{{chartsBase}}{{server.hostName}}"
target="_blank">Show Charts</a>
+ </li>
+ <hr class="divider"/>
+ <li role="menuitem" ng-show="isCache(server)">
+ <a ng-href="#!/servers/{{server.id}}/capabilities">Manage
Capabilities</a>
+ </li>
+ <li role="menuitem" ng-show="isEdge(server) || isOrigin(server)">
+ <a ng-href="#!/servers/{{server.id}}/delivery-services">Manage
Delivery Services</a>
+ </li>
+ </ul>
+</menu>
diff --git
a/traffic_portal/app/src/common/modules/table/statusServers/TableStatusServersController.js
b/traffic_portal/app/src/common/modules/table/statusServers/TableStatusServersController.js
index b35e637..b069705 100644
---
a/traffic_portal/app/src/common/modules/table/statusServers/TableStatusServersController.js
+++
b/traffic_portal/app/src/common/modules/table/statusServers/TableStatusServersController.js
@@ -19,8 +19,8 @@
var TableStatusServersController = function(status, servers, $controller,
$scope) {
- // extends the TableServersController to inherit common methods
- angular.extend(this, $controller('TableServersController', { servers:
servers, $scope: $scope }));
+ // extends the TableParentServersController to inherit common methods
+ angular.extend(this, $controller('TableParentServersController', {
servers: servers, $scope: $scope }));
let statusServersTable;
diff --git
a/traffic_portal/app/src/common/modules/table/typeServers/TableTypeServersController.js
b/traffic_portal/app/src/common/modules/table/typeServers/TableTypeServersController.js
index 3b03e50..2930c9d 100644
---
a/traffic_portal/app/src/common/modules/table/typeServers/TableTypeServersController.js
+++
b/traffic_portal/app/src/common/modules/table/typeServers/TableTypeServersController.js
@@ -19,8 +19,8 @@
var TableTypeServersController = function(type, servers, $controller, $scope) {
- // extends the TableServersController to inherit common methods
- angular.extend(this, $controller('TableServersController', { servers:
servers, $scope: $scope }));
+ // extends the TableParentServersController to inherit common methods
+ angular.extend(this, $controller('TableParentServersController', {
servers: servers, $scope: $scope }));
let typeServersTable;
diff --git a/traffic_portal/app/src/index.html
b/traffic_portal/app/src/index.html
index 0593391..cba678e 100644
--- a/traffic_portal/app/src/index.html
+++ b/traffic_portal/app/src/index.html
@@ -49,6 +49,7 @@ under the License.
<div class="app container body" ui-view></div>
<script src="resources/assets/js/shared-libs.js"></script>
+ <script
src="resources/assets/js/ag-grid-community/dist/ag-grid-community.min.js"></script>
<script src="resources/assets/js/app.js"></script>
<script src="resources/assets/js/config.js"></script>
diff --git a/traffic_portal/grunt/copy.js b/traffic_portal/grunt/copy.js
index f774d39..785062e 100644
--- a/traffic_portal/grunt/copy.js
+++ b/traffic_portal/grunt/copy.js
@@ -6,9 +6,9 @@
* 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
@@ -42,6 +42,13 @@ module.exports = {
'traffic_portal_release.json',
'traffic_portal_properties.json'
]
+ },
+ {
+ expand: true,
+ dot: true,
+ cwd: "<%= globalConfig.importdir %>",
+ dest: "<%= globalConfig.resourcesdir %>/assets/js/",
+ src: ["ag-grid-community/dist/ag-grid-community.min.js"]
}
]
},
@@ -78,6 +85,13 @@ module.exports = {
'traffic_portal_release.json',
'traffic_portal_properties.json'
]
+ },
+ {
+ expand: true,
+ dot: true,
+ cwd: "<%= globalConfig.importdir %>",
+ dest: "<%= globalConfig.resourcesdir %>/assets/js/",
+ src: ["ag-grid-community/dist/ag-grid-community.min.js"]
}
]
}
diff --git a/traffic_portal/grunt/globalConfig.js
b/traffic_portal/grunt/globalConfig.js
index 71ab1b4..95b34f2 100644
--- a/traffic_portal/grunt/globalConfig.js
+++ b/traffic_portal/grunt/globalConfig.js
@@ -6,9 +6,9 @@
* 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
@@ -21,6 +21,7 @@ module.exports = function() {
var globalConfig = {
app: 'app',
resourcesdir: 'app/dist/public/resources',
+ importdir: "node_modules",
distdir: 'app/dist',
srcserverdir: './server',
srcdir: 'app/src',
diff --git a/traffic_portal/package-lock.json b/traffic_portal/package-lock.json
index 2ad7393..982bfbe 100644
--- a/traffic_portal/package-lock.json
+++ b/traffic_portal/package-lock.json
@@ -83,6 +83,11 @@
}
}
},
+ "ag-grid-community": {
+ "version": "23.2.0",
+ "resolved":
"https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-23.2.0.tgz",
+ "integrity":
"sha512-aG7Ghfu79HeqOCd50GhFSeZUX1Tw9BVUX1VKMuglkAcwYPTQjuYvYT7QVQB5FGzfFjcVq4a1QFfcgdoAcZYJIA=="
+ },
"align-text": {
"version": "0.1.4",
"resolved":
"https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
diff --git a/traffic_portal/package.json b/traffic_portal/package.json
index 4462040..30d6876 100644
--- a/traffic_portal/package.json
+++ b/traffic_portal/package.json
@@ -30,5 +30,8 @@
"requirejs": "2.3.6",
"ssl-root-cas": "1.3.1",
"time-grunt": "1.3.0"
+ },
+ "dependencies": {
+ "ag-grid-community": "^23.2.0"
}
}
diff --git
a/traffic_portal/test/end_to_end/deliveryServices/delivery-services-spec.js
b/traffic_portal/test/end_to_end/deliveryServices/delivery-services-spec.js
index c6b99c3..94a7021 100644
--- a/traffic_portal/test/end_to_end/deliveryServices/delivery-services-spec.js
+++ b/traffic_portal/test/end_to_end/deliveryServices/delivery-services-spec.js
@@ -114,7 +114,7 @@ describe('Traffic Portal Delivery Services Suite',
function() {
first.click();
expect(first.isSelected()).toBe(false);
let tableColumns = element.all(by.css('#deliveryServicesTable
tr:first-child td'));
- expect(tableColumns.count()).toBe(10);
+ expect(tableColumns.count()).toBe(11);
});
it('should update the ANY_MAP delivery service', function() {
diff --git a/traffic_portal/test/end_to_end/servers/servers-spec.js
b/traffic_portal/test/end_to_end/servers/servers-spec.js
index fb3220b..1f5d240 100644
--- a/traffic_portal/test/end_to_end/servers/servers-spec.js
+++ b/traffic_portal/test/end_to_end/servers/servers-spec.js
@@ -41,11 +41,6 @@ describe('Traffic Portal Servers Test Suite', function() {
expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/servers");
});
- it('should verify CSV link exists ', function() {
- console.log("Verify CSV button exists");
-
expect(element(by.css('.dt-button.buttons-csv')).isPresent()).toBe(true);
- });
-
it('should open new Servers form page', function() {
console.log('Clicking on Create new server ' +
mockVals.hostName);
browser.driver.findElement(by.name('createServersButton')).click();
@@ -81,20 +76,14 @@ describe('Traffic Portal Servers Test Suite', function() {
expect(first.isSelected()).toBe(true);
first.click();
expect(first.isSelected()).toBe(false);
- let tableColumns = element.all(by.css('#serversTable
tr:first-child td'));
- expect(tableColumns.count()).toBe(11);
+ let tableColumns = element.all(by.css('.ag-header-cell'));
+ expect(tableColumns.count()).toBe(9);
});
it('should verify the new Server and then update Server', function() {
console.log('Verifying new server added and updating ' +
mockVals.hostName);
browser.sleep(1000);
- pageData.searchFilter.sendKeys(mockVals.hostName);
- browser.sleep(250);
- element.all(by.repeater('s in ::servers')).filter(function(row){
- return
row.element(by.name('hostName')).getText().then(function(val){
- return val === mockVals.hostName;
- });
- }).get(0).click();
+ element(by.cssContainingText('.ag-cell',
mockVals.hostName)).click()
browser.sleep(1000);
pageData.domainName.clear();
pageData.domainName.sendKeys('testupdated.com');