diff --git a/traffic_portal/app/src/app.js b/traffic_portal/app/src/app.js index ddf01c5093..7575d3c2cf 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 1c39b488a3..e6a28683e8 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 7ce6742fde..8ea50a2f08 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 f0b8df7cc3..b6a4dca883 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 b343657792..5d0c0944fb 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 497eb6c7b3..f329796c57 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 dbc2cf72e7..eff77f2189 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 a6dad82617..1afca893e7 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 0000000000..5fb0adc192 --- /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 4073abeaf8..10ad816f42 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 e955714d6e..2b5d9b5900 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 9c3dce476f..4d36373aa8 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 @@
  • Servers
  • - +
    -
  • +
  • - +
  • @@ -46,99 +46,53 @@
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Cache GroupCDNDomainHostHTTPS PortIDILO IP AddressILO IP GatewayILO IP NetmaskILO UsernameInterface NameIPv6 AddressIPv6 GatewayLast UpdatedMgmt IP AddressMgmt IP GatewayMgmt IP NetmaskNetwork GatewayNetwork IPNetwork MTUNetwork SubnetOffline ReasonPhys LocationProfileRackReval PendingRouter HostnameRouter Port NameStatusTCP PortTypeUpdate Pending
    {{::s.cachegroup}}{{::s.cdnName}}{{::s.domainName}}{{::s.hostName}}{{::s.httpsPort}}{{::s.id}}{{::s.iloIpAddress}}{{::s.iloIpGateway}}{{::s.iloIpNetmask}}{{::s.iloUsername}}{{::s.interfaceName}}{{::s.ip6Address}}{{::s.ip6Gateway}}{{::getRelativeTime(s.lastUpdated)}}{{::s.mgmtIpAddress}}{{::s.mgmtIpGateway}}{{::s.mgmtIpNetmask}}{{::s.ipGateway}}{{::s.ipAddress}}{{::s.interfaceMtu}}{{::s.ipNetmask}}{{::s.offlineReason}}{{::s.physLocation}}{{::s.profile}}{{::s.rack}} - - - {{::s.routerHostName}}{{::s.routerPortName}} - {{::s.status}} - {{::s.status}} - {{::s.tcpPort}}{{::s.type}} - - -
    +
    - - - + + + 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 b35e637772..b0697059c1 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 3b03e50089..2930c9d014 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 0593391095..cba678e581 100644 --- a/traffic_portal/app/src/index.html +++ b/traffic_portal/app/src/index.html @@ -49,6 +49,7 @@
    + diff --git a/traffic_portal/grunt/copy.js b/traffic_portal/grunt/copy.js index f774d3995f..785062e5dc 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 71ab1b4605..95b34f281f 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 2ad7393b3a..982bfbe466 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 4462040527..30d68768ca 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 c6b99c3f5a..94a7021aa9 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 fb3220b78f..1f5d240783 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');