This is an automated email from the ASF dual-hosted git repository.

ocket8888 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 e12468f  TP: adds the ability to rearrange server table columns as 
well as toggle column visibility/searchability (#3760)
e12468f is described below

commit e12468f0c76e56f879459b952c89d6e39a39248b
Author: Jeremy Mitchell <[email protected]>
AuthorDate: Wed Aug 7 09:12:13 2019 -0600

    TP: adds the ability to rearrange server table columns as well as toggle 
column visibility/searchability (#3760)
    
    * adds the ability to toggle server column visibility on/off as well as 
reorder columns
    
    * adds changelog entry
    
    * docs updates
    
    * adds a UI test to hide the first column
    
    * additional server table doc updates
    
    * updates per PR review
---
 CHANGELOG.md                                       |   1 +
 .../traffic_portal/images/tp_table_server.png      | Bin 0 -> 143569 bytes
 .../admin/traffic_portal/usingtrafficportal.rst    |  57 ++++++---
 docs/source/api/servers.rst                        |   4 +-
 .../TableCacheGroupServersController.js            |  26 ++++-
 .../table.cacheGroupServers.tpl.html               | 124 ++++++++++++++------
 .../table/cdnServers/TableCDNServersController.js  |  26 ++++-
 .../table/cdnServers/table.cdnServers.tpl.html     | 124 ++++++++++++++------
 .../TableDeliveryServiceServersController.js       |  31 +++--
 .../table.deliveryServiceServers.tpl.html          | 128 +++++++++++++++------
 .../TablePhysLocationServersController.js          |  26 ++++-
 .../table.physLocationServers.tpl.html             | 124 ++++++++++++++------
 .../TableProfileServersController.js               |  26 ++++-
 .../profileServers/table.profileServers.tpl.html   | 124 ++++++++++++++------
 .../table/servers/TableServersController.js        |  67 ++++++++++-
 .../modules/table/servers/table.servers.tpl.html   | 124 ++++++++++++++------
 .../statusServers/TableStatusServersController.js  |  26 ++++-
 .../statusServers/table.statusServers.tpl.html     | 124 ++++++++++++++------
 .../typeServers/TableTypeServersController.js      |  26 ++++-
 .../table/typeServers/table.typeServers.tpl.html   | 124 ++++++++++++++------
 .../test/end_to_end/Servers/servers-spec.js        |  10 ++
 21 files changed, 1000 insertions(+), 322 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a04a43..66237ad 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -36,6 +36,7 @@ The format is based on [Keep a 
Changelog](http://keepachangelog.com/en/1.0.0/).
 - In Traffic Portal, delivery service table columns can now be rearranged and 
their visibility toggled on/off as desired by the user. Hidden table columns 
are excluded from the table search. These settings are persisted in the browser.
 - Added an API 1.4 endpoint, /api/1.4/user/login/oauth to handle SSO login 
using OAuth.
 - Added /#!/sso page to Traffic Portal to catch redirects back from OAuth 
provider and POST token into the API.
+- In Traffic Portal, server table columns can now be rearranged and their 
visibility toggled on/off as desired by the user. Hidden table columns are 
excluded from the table search. These settings are persisted in the browser.
 
 ### Changed
 - Traffic Router, added TLS certificate validation on certificates imported 
from Traffic Ops
diff --git a/docs/source/admin/traffic_portal/images/tp_table_server.png 
b/docs/source/admin/traffic_portal/images/tp_table_server.png
new file mode 100644
index 0000000..61e3a6e
Binary files /dev/null and 
b/docs/source/admin/traffic_portal/images/tp_table_server.png differ
diff --git a/docs/source/admin/traffic_portal/usingtrafficportal.rst 
b/docs/source/admin/traffic_portal/usingtrafficportal.rst
index 0199f8a..0cabd18 100644
--- a/docs/source/admin/traffic_portal/usingtrafficportal.rst
+++ b/docs/source/admin/traffic_portal/usingtrafficportal.rst
@@ -296,26 +296,55 @@ Interfaces for managing the various components of Traffic 
Control and how they i
 
 Servers
 -------
-A table of all servers (of all kinds) across all :term:`Delivery Services` and 
CDNs visible to the user. It has the following columns:
+A configurable table of all servers (of all kinds) across all :term:`Delivery 
Services` and CDNs visible to the user.
 
-:UPD:    'true' when updates to the server's configuration are pending, 
'false' otherwise
-:Host:   The hostname of the server
-:Domain: The server's domain. (The :abbr:`FQDN (Fully Qualified Domain Name)` 
of the server is given by :file:`{Host}.{Domain}`)
-:IP:     The server's IPv4 address
-:IPv6:   The server's IPv6 address
-:Status: The server's :term:`Status`
+.. figure:: ./images/tp_table_server.png
+       :align: center
+       :alt: An example table of Servers
 
-       .. seealso:: :ref:`health-proto`
+       Table of Servers
 
-:Type:         The :term:`Type` of server e.g. EDGE for an :term:`Edge-tier 
cache server`
-:Profile:      The :ref:`profile-name` of the server's :term:`Profile`
-:CDN:          The name of the CDN to which this server is assigned (if any)
-:Cache Group:  The name of the :term:`Cache Group` to which this server belongs
-:Phys Location:        The name of the :term:`Physical Location` to which this 
server belongs
-:ILO:          If not empty, this is the IPv4 address of the server's 
:abbr:`ILO (Integrated Lights-Out)` interface
+Use the `Select Columns` menu to select the server columns to view and search. 
Columns can also be rearranged using drag-and-drop. Available server columns 
include:
+
+:Cache Group:       [Visible by default] The name of the :term:`Cache Group` 
to which this server belongs
+:CDN:               [Visible by default] The name of the CDN to which the 
server belongs
+:Domain:            [Visible by default] The domain part of the server's 
:abbr:`FQDN (Fully Qualified Domain Name)`
+:Host:              [Visible by default] The (short) hostname of the server
+:HTTPS Port:        The port on which the server listens for incoming HTTPS 
connections/requests
+:ID:                An integral, unique identifier for this server
+:ILO IP Address:    [Visible by default] The IPv4 address of the server's 
:abbr:`ILO (Integrated Lights-Out)` service
 
        .. seealso:: `Hewlett Packard ILO Wikipedia Page 
<https://en.wikipedia.org/wiki/HP_Integrated_Lights-Out>`_
 
+:ILO IP Gateway:    The IPv4 gateway address of the server's :abbr:`ILO 
(Integrated Lights-Out)` service
+:ILO IP Netmask:    The IPv4 subnet mask of the server's :abbr:`ILO 
(Integrated Lights-Out)` service
+:ILO Username:      The user name for the server's :abbr:`ILO (Integrated 
Lights-Out)` service
+:Interface Name:    The name of the primary network interface used by the 
server
+:IPv6 Address:      [Visible by default] The IPv6 address and subnet mask of 
``interfaceName``
+:IPv6 Gateway:      The IPv6 address of the gateway used by ``interfaceName``
+:Last Updated:      The date and time at which this server description was 
last modified
+:Mgmt IP Address:   The IPv4 address of some network interface on the server 
used for 'management'
+:Mgmt IP Gateway:   The IPv4 address of a gateway used by some network 
interface on the server used for 'management'
+:Mgmt IP Netmask:   The IPv4 subnet mask used by some network interface on the 
server used for 'management'
+:Network Gateway:   The IPv4 address of the gateway used by ``interfaceName``
+:Network IP:        [Visible by default] The IPv4 address of ``interfaceName``
+:Network MTU:       The Maximum Transmission Unit (MTU) to configured on 
``interfaceName``
+:Network Subnet:    The IPv4 subnet mask used by ``interfaceName``
+:Offline Reason:    A user-entered reason why the server is in ADMIN_DOWN or 
OFFLINE status
+:Phys Location:     [Visible by default] The name of the physical location 
where the server resides
+:Profile:           [Visible by default] The :ref:`profile-name` of the 
:term:`Profile` used by this server
+:Rack:              A string indicating "server rack" location
+:Reval Pending:     [Visible by default] A boolean value represented as a 
clock (content invalidation/revalidation is pending) or green check mark 
(content invalidation/revalidation is not pending)
+:Router Hostname:   The human-readable name of the router responsible for 
reaching this server
+:Router Port Name:  The human-readable name of the port used by the router 
responsible for reaching this server
+:Status:            [Visible by default] The :term:`Status` of the server
+
+       .. seealso:: :ref:`health-proto`
+
+:TCP Port:          The port on which this server listens for incoming TCP 
connections
+:Type:              [Visible by default] The name of the :term:`Type` of this 
server
+:Update Pending:    [Visible by default] A boolean value represented as a 
clock (updates are pending) or green check mark (updates are not pending), 
typically to be acted upon by Traffic Ops ORT
+
 Server management includes the ability to (where applicable):
 
 - create a new server
diff --git a/docs/source/api/servers.rst b/docs/source/api/servers.rst
index cae3c90..a9765ad 100644
--- a/docs/source/api/servers.rst
+++ b/docs/source/api/servers.rst
@@ -99,7 +99,7 @@ Response Structure
 :rack:           A string indicating "server rack" location
 :routerHostName: The human-readable name of the router responsible for 
reaching this server
 :routerPortName: The human-readable name of the port used by the router 
responsible for reaching this server
-:status:         The status of the server
+:status:         The :term:`Status` of the server
 
        .. seealso:: :ref:`health-proto`
 
@@ -111,7 +111,7 @@ Response Structure
 
        .. note:: This is typically thought of as synonymous with "HTTP port", 
as the port specified by ``httpsPort`` may also be used for incoming TCP 
connections.
 
-:type:       The name of the 'type' of this server
+:type:       The name of the :term:`Type` of this server
 :typeId:     The integral, unique identifier of the 'type' of this server
 :updPending: A boolean value which, if ``true``, indicates that the server has 
updates of some kind pending, typically to be acted upon by Traffic Ops ORT
 :xmppId:     An identifier to be used in XMPP communications with the server - 
in nearly all cases this will be the same as ``hostName``
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 4e589a1..1fa6b43 100644
--- 
a/traffic_portal/app/src/common/modules/table/cacheGroupServers/TableCacheGroupServersController.js
+++ 
b/traffic_portal/app/src/common/modules/table/cacheGroupServers/TableCacheGroupServersController.js
@@ -22,6 +22,8 @@ var TableCacheGroupsServersController = function(cacheGroup, 
servers, $controlle
        // extends the TableServersController to inherit common methods
        angular.extend(this, $controller('TableServersController', { servers: 
servers, $scope: $scope }));
 
+       let cacheGroupServersTable;
+
        $scope.cacheGroup = cacheGroup;
 
        var queueCacheGroupServerUpdates = function(cacheGroup, cdnId) {
@@ -92,11 +94,29 @@ var TableCacheGroupsServersController = 
function(cacheGroup, servers, $controlle
                });
        };
 
+       $scope.toggleVisibility = function(colName) {
+               const col = cacheGroupServersTable.column(colName + ':name');
+               col.visible(!col.visible());
+               cacheGroupServersTable.rows().invalidate().draw();
+       };
+
        angular.element(document).ready(function () {
-               $('#cacheGroupServersTable').dataTable({
-                       "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, 
"All"]],
+               cacheGroupServersTable = 
$('#cacheGroupServersTable').DataTable({
+                       "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
                        "iDisplayLength": 25,
-                       "aaSorting": []
+                       "aaSorting": [],
+                       "columns": $scope.columns,
+                       "colReorder": {
+                               realtime: false
+                       },
+                       "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_cacheGroupServersTable_/')).columns;
+                               } catch (e) {
+                                       console.error("Failure to retrieve 
required column info from localStorage 
(key=DataTables_cacheGroupServersTable_/):", e);
+                               }
+                       }
                });
        });
 
diff --git 
a/traffic_portal/app/src/common/modules/table/cacheGroupServers/table.cacheGroupServers.tpl.html
 
b/traffic_portal/app/src/common/modules/table/cacheGroupServers/table.cacheGroupServers.tpl.html
index 8eb2d9c..2fc47e8 100644
--- 
a/traffic_portal/app/src/common/modules/table/cacheGroupServers/table.cacheGroupServers.tpl.html
+++ 
b/traffic_portal/app/src/common/modules/table/cacheGroupServers/table.cacheGroupServers.tpl.html
@@ -36,6 +36,19 @@ under the License.
                 </ul>
             </div>
             <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">
+                    <i class="fa fa-columns"></i>&nbsp;
+                    <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'">
+                        <div class="checkbox">
+                            <label><input type="checkbox" ng-model="c.visible" 
ng-click="toggleVisibility(c.name)"> {{::c.name}}</label>
+                        </div>
+                    </li>
+                </menu>
+            </div>
         </div>
         <div class="clearfix"></div>
     </div>
@@ -43,42 +56,85 @@ under the License.
         <br>
         <table id="cacheGroupServersTable" class="table responsive-utilities 
jambo_table">
             <thead>
-            <tr class="headings">
-                <th>UPD</th>
-                <th>Host</th>
-                <th>Domain</th>
-                <th>IP</th>
-                <th>IPv6</th>
-                <th>Status</th>
-                <th>Type</th>
-                <th>Profile</th>
-                <th>CDN</th>
-                <th>Cache Group</th>
-                <th>Phys Location</th>
-                <th>ILO</th>
-            </tr>
+                <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-order="{{::s.updPending}}" 
data-search="{{(s.updPending) ? 'UPD' : ''}}">
-                    <i title="Updates Pending" 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>
-                <td data-search="^{{::s.hostName}}$">{{::s.hostName}}</td>
-                <td data-search="^{{::s.domainName}}$">{{::s.domainName}}</td>
-                <td data-search="^{{::s.ipAddress}}$"><a 
ng-click="ssh(s.ipAddress, $event)">{{::s.ipAddress}}</a></td>
-                <td data-search="^{{::s.ip6Address}}$">{{::s.ip6Address}}</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.type}}$">{{::s.type}}</td>
-                <td data-search="^{{::s.profile}}$">{{::s.profile}}</td>
-                <td data-search="^{{::s.cdnName}}$">{{::s.cdnName}}</td>
-                <td data-search="^{{::s.cachegroup}}$">{{::s.cachegroup}}</td>
-                <td 
data-search="^{{::s.physLocation}}$">{{::s.physLocation}}</td>
-                <td data-search="^{{::s.iloIpAddress}}$"><a 
ng-click="ssh(s.iloIpAddress, $event)">{{::s.iloIpAddress}}</a></td>
-            </tr>
+                <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 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>
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 f8ba198..dada97a 100644
--- 
a/traffic_portal/app/src/common/modules/table/cdnServers/TableCDNServersController.js
+++ 
b/traffic_portal/app/src/common/modules/table/cdnServers/TableCDNServersController.js
@@ -22,13 +22,33 @@ var TableCDNServersController = function(cdn, servers, 
$controller, $scope) {
        // extends the TableServersController to inherit common methods
        angular.extend(this, $controller('TableServersController', { servers: 
servers, $scope: $scope }));
 
+       let cdnServersTable;
+
        $scope.cdn = cdn;
 
+       $scope.toggleVisibility = function(colName) {
+               const col = cdnServersTable.column(colName + ':name');
+               col.visible(!col.visible());
+               cdnServersTable.rows().invalidate().draw();
+       };
+
        angular.element(document).ready(function () {
-               $('#cdnServersTable').dataTable({
-                       "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, 
"All"]],
+               cdnServersTable = $('#cdnServersTable').DataTable({
+                       "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
                        "iDisplayLength": 25,
-                       "aaSorting": []
+                       "aaSorting": [],
+                       "columns": $scope.columns,
+                       "colReorder": {
+                               realtime: false
+                       },
+                       "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_cdnServersTable_/')).columns;
+                               } catch (e) {
+                                       console.error("Failure to retrieve 
required column info from localStorage (key=DataTables_cdnServersTable_/):", e);
+                               }
+                       }
                });
        });
 
diff --git 
a/traffic_portal/app/src/common/modules/table/cdnServers/table.cdnServers.tpl.html
 
b/traffic_portal/app/src/common/modules/table/cdnServers/table.cdnServers.tpl.html
index 3418db8..c17266e 100644
--- 
a/traffic_portal/app/src/common/modules/table/cdnServers/table.cdnServers.tpl.html
+++ 
b/traffic_portal/app/src/common/modules/table/cdnServers/table.cdnServers.tpl.html
@@ -36,6 +36,19 @@ under the License.
                 </ul>
             </div>
             <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">
+                    <i class="fa fa-columns"></i>&nbsp;
+                    <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'">
+                        <div class="checkbox">
+                            <label><input type="checkbox" ng-model="c.visible" 
ng-click="toggleVisibility(c.name)"> {{::c.name}}</label>
+                        </div>
+                    </li>
+                </menu>
+            </div>
         </div>
         <div class="clearfix"></div>
     </div>
@@ -43,42 +56,85 @@ under the License.
         <br>
         <table id="cdnServersTable" class="table responsive-utilities 
jambo_table">
             <thead>
-            <tr class="headings">
-                <th>UPD</th>
-                <th>Host</th>
-                <th>Domain</th>
-                <th>IP</th>
-                <th>IPv6</th>
-                <th>Status</th>
-                <th>Type</th>
-                <th>Profile</th>
-                <th>CDN</th>
-                <th>Cache Group</th>
-                <th>Phys Location</th>
-                <th>ILO</th>
-            </tr>
+                <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.updPending) ? 'UPD' : ''}}" 
data-order="{{::s.updPending}}">
-                    <i title="Updates Pending" 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>
-                <td data-search="^{{::s.hostName}}$">{{::s.hostName}}</td>
-                <td data-search="^{{::s.domainName}}$">{{::s.domainName}}</td>
-                <td data-search="^{{::s.ipAddress}}$"><a 
ng-click="ssh(s.ipAddress, $event)">{{::s.ipAddress}}</a></td>
-                <td data-search="^{{::s.ip6Address}}$">{{::s.ip6Address}}</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.type}}$">{{::s.type}}</td>
-                <td data-search="^{{::s.profile}}$">{{::s.profile}}</td>
-                <td data-search="^{{::s.cdnName}}$">{{::s.cdnName}}</td>
-                <td data-search="^{{::s.cachegroup}}$">{{::s.cachegroup}}</td>
-                <td 
data-search="^{{::s.physLocation}}$">{{::s.physLocation}}</td>
-                <td data-search="^{{::s.iloIpAddress}}$"><a 
ng-click="ssh(s.iloIpAddress, $event)">{{::s.iloIpAddress}}</a></td>
-            </tr>
+                <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 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>
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 7eb292f..c9b92d6 100644
--- 
a/traffic_portal/app/src/common/modules/table/deliveryServiceServers/TableDeliveryServiceServersController.js
+++ 
b/traffic_portal/app/src/common/modules/table/deliveryServiceServers/TableDeliveryServiceServersController.js
@@ -22,6 +22,8 @@ var TableDeliveryServiceServersController = 
function(deliveryService, servers, $
        // extends the TableServersController to inherit common methods
        angular.extend(this, $controller('TableServersController', { servers: 
servers, $scope: $scope }));
 
+       let dsServersTable;
+
        var removeServer = function(serverId) {
                
deliveryServiceService.deleteDeliveryServiceServer($scope.deliveryService.id, 
serverId)
                        .then(
@@ -37,7 +39,7 @@ var TableDeliveryServiceServersController = 
function(deliveryService, servers, $
        $scope.contextMenuItems.splice(2, 0,
                {
                        text: 'Unlink Server from Delivery Service',
-                       hasTopDivider: function() {
+                       hasBottomDivider: function() {
                                return true;
                        },
                        click: function ($itemScope) {
@@ -101,14 +103,29 @@ var TableDeliveryServiceServersController = 
function(deliveryService, servers, $
                });
        };
 
+       $scope.toggleVisibility = function(colName) {
+               const col = dsServersTable.column(colName + ':name');
+               col.visible(!col.visible());
+               dsServersTable.rows().invalidate().draw();
+       };
+
        angular.element(document).ready(function () {
-               $('#dsServersTable').dataTable({
-                       "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, 
"All"]],
+               dsServersTable = $('#dsServersTable').DataTable({
+                       "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
                        "iDisplayLength": 25,
-                       "columnDefs": [
-                               { 'orderable': false, 'targets': 12 }
-                       ],
-                       "aaSorting": []
+                       "aaSorting": [],
+                       "columns": $scope.columns,
+                       "colReorder": {
+                               realtime: false
+                       },
+                       "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_dsServersTable_/')).columns;
+                               } catch (e) {
+                                       console.error("Failure to retrieve 
required column info from localStorage (key=DataTables_dsServersTable_/):", e);
+                               }
+                       }
                });
        });
 
diff --git 
a/traffic_portal/app/src/common/modules/table/deliveryServiceServers/table.deliveryServiceServers.tpl.html
 
b/traffic_portal/app/src/common/modules/table/deliveryServiceServers/table.deliveryServiceServers.tpl.html
index c60a966..dcd0b19 100644
--- 
a/traffic_portal/app/src/common/modules/table/deliveryServiceServers/table.deliveryServiceServers.tpl.html
+++ 
b/traffic_portal/app/src/common/modules/table/deliveryServiceServers/table.deliveryServiceServers.tpl.html
@@ -27,6 +27,19 @@ under the License.
         <div class="pull-right">
             <button class="btn btn-primary" title="Link Servers to Delivery 
Service" ng-click="selectServers()"><i class="fa fa-link"></i></button>
             <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">
+                    <i class="fa fa-columns"></i>&nbsp;
+                    <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'">
+                        <div class="checkbox">
+                            <label><input type="checkbox" ng-model="c.visible" 
ng-click="toggleVisibility(c.name)"> {{::c.name}}</label>
+                        </div>
+                    </li>
+                </menu>
+            </div>
         </div>
         <div class="clearfix"></div>
     </div>
@@ -34,46 +47,85 @@ under the License.
         <br>
         <table id="dsServersTable" class="table responsive-utilities 
jambo_table">
             <thead>
-            <tr class="headings">
-                <th>UPD</th>
-                <th>Host</th>
-                <th>Domain</th>
-                <th>IP</th>
-                <th>IPv6</th>
-                <th>Status</th>
-                <th>Type</th>
-                <th>Profile</th>
-                <th>CDN</th>
-                <th>Cache Group</th>
-                <th>Phys Location</th>
-                <th>ILO</th>
-                <th></th>
-            </tr>
+                <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.updPending) ? 'UPD' : ''}}" 
data-order="{{::s.updPending}}">
-                    <i title="Updates Pending" 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>
-                <td data-search="^{{::s.hostName}}$">{{::s.hostName}}</td>
-                <td data-search="^{{::s.domainName}}$">{{::s.domainName}}</td>
-                <td data-search="^{{::s.ipAddress}}$"><a 
ng-click="ssh(s.ipAddress, $event)">{{::s.ipAddress}}</a></td>
-                <td data-search="^{{::s.ip6Address}}$">{{::s.ip6Address}}</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.type}}$">{{::s.type}}</td>
-                <td data-search="^{{::s.profile}}$">{{::s.profile}}</td>
-                <td data-search="^{{::s.cdnName}}$">{{::s.cdnName}}</td>
-                <td data-search="^{{::s.cachegroup}}$">{{::s.cachegroup}}</td>
-                <td 
data-search="^{{::s.physLocation}}$">{{::s.physLocation}}</td>
-                <td data-search="^{{::s.iloIpAddress}}$"><a 
ng-click="ssh(s.iloIpAddress, $event)">{{::s.iloIpAddress}}</a></td>
-                <td style="text-align: right;">
-                    <a class="link action-link" title="Unlink Server from 
Delivery Service" ng-click="confirmRemoveServer(s, $event)"><i class="fa fa-sm 
fa-chain-broken"></i></a>
-                </td>
-            </tr>
+                <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 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>
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 af2db09..8c2e55a 100644
--- 
a/traffic_portal/app/src/common/modules/table/physLocationServers/TablePhysLocationServersController.js
+++ 
b/traffic_portal/app/src/common/modules/table/physLocationServers/TablePhysLocationServersController.js
@@ -22,13 +22,33 @@ var TablePhysLocationServersController = 
function(physLocation, servers, $contro
        // extends the TableServersController to inherit common methods
        angular.extend(this, $controller('TableServersController', { servers: 
servers, $scope: $scope }));
 
+       let physLocServersTable;
+
        $scope.physLocation = physLocation;
 
+       $scope.toggleVisibility = function(colName) {
+               const col = physLocServersTable.column(colName + ':name');
+               col.visible(!col.visible());
+               physLocServersTable.rows().invalidate().draw();
+       };
+
        angular.element(document).ready(function () {
-               $('#physLocServersTable').dataTable({
-                       "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, 
"All"]],
+               physLocServersTable = $('#physLocServersTable').DataTable({
+                       "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
                        "iDisplayLength": 25,
-                       "aaSorting": []
+                       "aaSorting": [],
+                       "columns": $scope.columns,
+                       "colReorder": {
+                               realtime: false
+                       },
+                       "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_physLocServersTable_/')).columns;
+                               } catch (e) {
+                                       console.error("Failure to retrieve 
required column info from localStorage 
(key=DataTables_physLocServersTable_/):", e);
+                               }
+                       }
                });
        });
 
diff --git 
a/traffic_portal/app/src/common/modules/table/physLocationServers/table.physLocationServers.tpl.html
 
b/traffic_portal/app/src/common/modules/table/physLocationServers/table.physLocationServers.tpl.html
index 45858ee..08c3f5a 100644
--- 
a/traffic_portal/app/src/common/modules/table/physLocationServers/table.physLocationServers.tpl.html
+++ 
b/traffic_portal/app/src/common/modules/table/physLocationServers/table.physLocationServers.tpl.html
@@ -26,6 +26,19 @@ under the License.
         </ol>
         <div class="pull-right">
             <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">
+                    <i class="fa fa-columns"></i>&nbsp;
+                    <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'">
+                        <div class="checkbox">
+                            <label><input type="checkbox" ng-model="c.visible" 
ng-click="toggleVisibility(c.name)"> {{::c.name}}</label>
+                        </div>
+                    </li>
+                </menu>
+            </div>
         </div>
         <div class="clearfix"></div>
     </div>
@@ -33,42 +46,85 @@ under the License.
         <br>
         <table id="physLocServersTable" class="table responsive-utilities 
jambo_table">
             <thead>
-            <tr class="headings">
-                <th>UPD</th>
-                <th>Host</th>
-                <th>Domain</th>
-                <th>IP</th>
-                <th>IPv6</th>
-                <th>Status</th>
-                <th>Type</th>
-                <th>Profile</th>
-                <th>CDN</th>
-                <th>Cache Group</th>
-                <th>Phys Location</th>
-                <th>ILO</th>
-            </tr>
+                <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.updPending) ? 'UPD' : ''}}" 
data-order="{{::s.updPending}}">
-                    <i title="Updates Pending" 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>
-                <td data-search="^{{::s.hostName}}$">{{::s.hostName}}</td>
-                <td data-search="^{{::s.domainName}}$">{{::s.domainName}}</td>
-                <td data-search="^{{::s.ipAddress}}$"><a 
ng-click="ssh(s.ipAddress, $event)">{{::s.ipAddress}}</a></td>
-                <td data-search="^{{::s.ip6Address}}$">{{::s.ip6Address}}</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.type}}$">{{::s.type}}</td>
-                <td data-search="^{{::s.profile}}$">{{::s.profile}}</td>
-                <td data-search="^{{::s.cdnName}}$">{{::s.cdnName}}</td>
-                <td data-search="^{{::s.cachegroup}}$">{{::s.cachegroup}}</td>
-                <td 
data-search="^{{::s.physLocation}}$">{{::s.physLocation}}</td>
-                <td data-search="^{{::s.iloIpAddress}}$"><a 
ng-click="ssh(s.iloIpAddress, $event)">{{::s.iloIpAddress}}</a></td>
-            </tr>
+                <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 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>
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 4d66d75..12a6003 100644
--- 
a/traffic_portal/app/src/common/modules/table/profileServers/TableProfileServersController.js
+++ 
b/traffic_portal/app/src/common/modules/table/profileServers/TableProfileServersController.js
@@ -22,13 +22,33 @@ var TableProfileServersController = function(profile, 
servers, $controller, $sco
        // extends the TableServersController to inherit common methods
        angular.extend(this, $controller('TableServersController', { servers: 
servers, $scope: $scope }));
 
+       let profileServersTable;
+
        $scope.profile = profile;
 
+       $scope.toggleVisibility = function(colName) {
+               const col = profileServersTable.column(colName + ':name');
+               col.visible(!col.visible());
+               profileServersTable.rows().invalidate().draw();
+       };
+
        angular.element(document).ready(function () {
-               $('#profileServersTable').dataTable({
-                       "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, 
"All"]],
+               profileServersTable = $('#profileServersTable').DataTable({
+                       "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
                        "iDisplayLength": 25,
-                       "aaSorting": []
+                       "aaSorting": [],
+                       "columns": $scope.columns,
+                       "colReorder": {
+                               realtime: false
+                       },
+                       "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_profileServersTable_/')).columns;
+                               } catch (e) {
+                                       console.error("Failure to retrieve 
required column info from localStorage 
(key=DataTables_profileServersTable_/):", e);
+                               }
+                       }
                });
        });
 
diff --git 
a/traffic_portal/app/src/common/modules/table/profileServers/table.profileServers.tpl.html
 
b/traffic_portal/app/src/common/modules/table/profileServers/table.profileServers.tpl.html
index 8e5616d..a5783b7 100644
--- 
a/traffic_portal/app/src/common/modules/table/profileServers/table.profileServers.tpl.html
+++ 
b/traffic_portal/app/src/common/modules/table/profileServers/table.profileServers.tpl.html
@@ -26,6 +26,19 @@ under the License.
         </ol>
         <div class="pull-right">
             <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">
+                    <i class="fa fa-columns"></i>&nbsp;
+                    <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'">
+                        <div class="checkbox">
+                            <label><input type="checkbox" ng-model="c.visible" 
ng-click="toggleVisibility(c.name)"> {{::c.name}}</label>
+                        </div>
+                    </li>
+                </menu>
+            </div>
         </div>
         <div class="clearfix"></div>
     </div>
@@ -33,42 +46,85 @@ under the License.
         <br>
         <table id="profileServersTable" class="table responsive-utilities 
jambo_table">
             <thead>
-            <tr class="headings">
-                <th>UPD</th>
-                <th>Host</th>
-                <th>Domain</th>
-                <th>IP</th>
-                <th>IPv6</th>
-                <th>Status</th>
-                <th>Type</th>
-                <th>Profile</th>
-                <th>CDN</th>
-                <th>Cache Group</th>
-                <th>Phys Location</th>
-                <th>ILO</th>
-            </tr>
+                <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.updPending) ? 'UPD' : ''}}" 
data-order="{{::s.updPending}}">
-                    <i title="Updates Pending" 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>
-                <td data-search="^{{::s.hostName}}$">{{::s.hostName}}</td>
-                <td data-search="^{{::s.domainName}}$">{{::s.domainName}}</td>
-                <td data-search="^{{::s.ipAddress}}$"><a 
ng-click="ssh(s.ipAddress, $event)">{{::s.ipAddress}}</a></td>
-                <td data-search="^{{::s.ip6Address}}$">{{::s.ip6Address}}</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.type}}$">{{::s.type}}</td>
-                <td data-search="^{{::s.profile}}$">{{::s.profile}}</td>
-                <td data-search="^{{::s.cdnName}}$">{{::s.cdnName}}</td>
-                <td data-search="^{{::s.cachegroup}}$">{{::s.cachegroup}}</td>
-                <td 
data-search="^{{::s.physLocation}}$">{{::s.physLocation}}</td>
-                <td data-search="^{{::s.iloIpAddress}}$"><a 
ng-click="ssh(s.iloIpAddress, $event)">{{::s.iloIpAddress}}</a></td>
-            </tr>
+                <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 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>
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 f869bf6..bd784d3 100644
--- 
a/traffic_portal/app/src/common/modules/table/servers/TableServersController.js
+++ 
b/traffic_portal/app/src/common/modules/table/servers/TableServersController.js
@@ -17,7 +17,9 @@
  * under the License.
  */
 
-var TableServersController = function(servers, $scope, $state, $uibModal, 
$window, locationUtils, serverUtils, cdnService, serverService, statusService, 
propertiesModel, messageModel) {
+var TableServersController = function(servers, $scope, $state, $uibModal, 
$window, dateUtils, locationUtils, serverUtils, cdnService, serverService, 
statusService, propertiesModel, messageModel) {
+
+    let serversTable;
 
     var getStatuses = function() {
         statusService.getStatuses()
@@ -128,6 +130,41 @@ var TableServersController = function(servers, $scope, 
$state, $uibModal, $windo
 
     $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',
@@ -320,12 +357,20 @@ var TableServersController = function(servers, $scope, 
$state, $uibModal, $windo
         $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 () {
@@ -334,14 +379,26 @@ var TableServersController = function(servers, $scope, 
$state, $uibModal, $windo
     init();
 
     angular.element(document).ready(function () {
-        $('#serversTable').dataTable({
-            "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
+        serversTable = $('#serversTable').DataTable({
+            "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
             "iDisplayLength": 25,
-            "aaSorting": []
+            "aaSorting": [],
+            "columns": $scope.columns,
+            "colReorder": {
+                realtime: false
+            },
+            "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);
+                }
+            }
         });
     });
 
 };
 
-TableServersController.$inject = ['servers', '$scope', '$state', '$uibModal', 
'$window', 'locationUtils', 'serverUtils', 'cdnService', 'serverService', 
'statusService', 'propertiesModel', 'messageModel'];
+TableServersController.$inject = ['servers', '$scope', '$state', '$uibModal', 
'$window', 'dateUtils', 'locationUtils', 'serverUtils', 'cdnService', 
'serverService', 'statusService', 'propertiesModel', 'messageModel'];
 module.exports = TableServersController;
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 e1d468a..9c3dce4 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
@@ -25,6 +25,19 @@ under the License.
         <div class="pull-right">
             <button class="btn btn-primary" name="createServersButton" 
title="Create Server" ng-click="createServer()"><i class="fa 
fa-plus"></i></button>
             <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">
+                    <i class="fa fa-columns"></i>&nbsp;
+                    <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'">
+                        <div class="checkbox">
+                            <label><input type="checkbox" ng-model="c.visible" 
ng-click="toggleVisibility(c.name)"> {{::c.name}}</label>
+                        </div>
+                    </li>
+                </menu>
+            </div>
             <div class="btn-group" role="group" uib-dropdown 
is-open="more.isopen">
                 <button type="button" class="btn btn-default dropdown-toggle" 
uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
                     More&nbsp;
@@ -42,42 +55,85 @@ under the License.
         <br>
         <table id="serversTable" class="table responsive-utilities 
jambo_table">
             <thead>
-            <tr class="headings">
-                <th>UPD</th>
-                <th>Host</th>
-                <th>Domain</th>
-                <th>IP</th>
-                <th>IPv6</th>
-                <th>Status</th>
-                <th>Type</th>
-                <th>Profile</th>
-                <th>CDN</th>
-                <th>Cache Group</th>
-                <th>Phys Location</th>
-                <th>ILO</th>
-            </tr>
+                <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.updPending) ? 'UPD' : ''}}" 
data-order="{{::s.updPending}}">
-                    <i title="Updates Pending" 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>
-                <td name="hostName" 
data-search="^{{::s.hostName}}$">{{::s.hostName}}</td>
-                <td data-search="^{{::s.domainName}}$">{{::s.domainName}}</td>
-                <td data-search="^{{::s.ipAddress}}$"><a 
ng-click="ssh(s.ipAddress, $event)">{{::s.ipAddress}}</a></td>
-                <td data-search="^{{::s.ip6Address}}$">{{::s.ip6Address}}</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.type}}$">{{::s.type}}</td>
-                <td data-search="^{{::s.profile}}$">{{::s.profile}}</td>
-                <td data-search="^{{::s.cdnName}}$">{{::s.cdnName}}</td>
-                <td data-search="^{{::s.cachegroup}}$">{{::s.cachegroup}}</td>
-                <td 
data-search="^{{::s.physLocation}}$">{{::s.physLocation}}</td>
-                <td data-search="^{{::s.iloIpAddress}}$"><a 
ng-click="ssh(s.iloIpAddress, $event)">{{::s.iloIpAddress}}</a></td>
-            </tr>
+                <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>
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 dbb8b70..7d60308 100644
--- 
a/traffic_portal/app/src/common/modules/table/statusServers/TableStatusServersController.js
+++ 
b/traffic_portal/app/src/common/modules/table/statusServers/TableStatusServersController.js
@@ -22,13 +22,33 @@ var TableStatusServersController = function(status, 
servers, $controller, $scope
        // extends the TableServersController to inherit common methods
        angular.extend(this, $controller('TableServersController', { servers: 
servers, $scope: $scope }));
 
+       let statusServersTable;
+
        $scope.status = status;
 
+       $scope.toggleVisibility = function(colName) {
+               const col = statusServersTable.column(colName + ':name');
+               col.visible(!col.visible());
+               statusServersTable.rows().invalidate().draw();
+       };
+
        angular.element(document).ready(function () {
-               $('#statusServersTable').dataTable({
-                       "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, 
"All"]],
+               statusServersTable = $('#statusServersTable').DataTable({
+                       "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
                        "iDisplayLength": 25,
-                       "aaSorting": []
+                       "aaSorting": [],
+                       "columns": $scope.columns,
+                       "colReorder": {
+                               realtime: false
+                       },
+                       "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_statusServersTable_/')).columns;
+                               } catch (e) {
+                                       console.error("Failure to retrieve 
required column info from localStorage (key=DataTables_statusServersTable_/):", 
e);
+                               }
+                       }
                });
        });
 
diff --git 
a/traffic_portal/app/src/common/modules/table/statusServers/table.statusServers.tpl.html
 
b/traffic_portal/app/src/common/modules/table/statusServers/table.statusServers.tpl.html
index 0e7ef2f..5ddb8a0 100644
--- 
a/traffic_portal/app/src/common/modules/table/statusServers/table.statusServers.tpl.html
+++ 
b/traffic_portal/app/src/common/modules/table/statusServers/table.statusServers.tpl.html
@@ -26,6 +26,19 @@ under the License.
         </ol>
         <div class="pull-right">
             <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">
+                    <i class="fa fa-columns"></i>&nbsp;
+                    <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'">
+                        <div class="checkbox">
+                            <label><input type="checkbox" ng-model="c.visible" 
ng-click="toggleVisibility(c.name)"> {{::c.name}}</label>
+                        </div>
+                    </li>
+                </menu>
+            </div>
         </div>
         <div class="clearfix"></div>
     </div>
@@ -33,42 +46,85 @@ under the License.
         <br>
         <table id="statusServersTable" class="table responsive-utilities 
jambo_table">
             <thead>
-            <tr class="headings">
-                <th>UPD</th>
-                <th>Host</th>
-                <th>Domain</th>
-                <th>IP</th>
-                <th>IPv6</th>
-                <th>Status</th>
-                <th>Type</th>
-                <th>Profile</th>
-                <th>CDN</th>
-                <th>Cache Group</th>
-                <th>Phys Location</th>
-                <th>ILO</th>
-            </tr>
+                <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.updPending) ? 'UPD' : ''}}" 
data-order="{{::s.updPending}}">
-                    <i title="Updates Pending" 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>
-                <td data-search="^{{::s.hostName}}$">{{::s.hostName}}</td>
-                <td data-search="^{{::s.domainName}}$">{{::s.domainName}}</td>
-                <td data-search="^{{::s.ipAddress}}$"><a 
ng-click="ssh(s.ipAddress, $event)">{{::s.ipAddress}}</a></td>
-                <td data-search="^{{::s.ip6Address}}$">{{::s.ip6Address}}</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.type}}$">{{::s.type}}</td>
-                <td data-search="^{{::s.profile}}$">{{::s.profile}}</td>
-                <td data-search="^{{::s.cdnName}}$">{{::s.cdnName}}</td>
-                <td data-search="^{{::s.cachegroup}}$">{{::s.cachegroup}}</td>
-                <td 
data-search="^{{::s.physLocation}}$">{{::s.physLocation}}</td>
-                <td data-search="^{{::s.iloIpAddress}}$"><a 
ng-click="ssh(s.iloIpAddress, $event)">{{::s.iloIpAddress}}</a></td>
-            </tr>
+                <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 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>
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 45d5b8d..5e415fb 100644
--- 
a/traffic_portal/app/src/common/modules/table/typeServers/TableTypeServersController.js
+++ 
b/traffic_portal/app/src/common/modules/table/typeServers/TableTypeServersController.js
@@ -22,13 +22,33 @@ var TableTypeServersController = function(type, servers, 
$controller, $scope) {
        // extends the TableServersController to inherit common methods
        angular.extend(this, $controller('TableServersController', { servers: 
servers, $scope: $scope }));
 
+       let typeServersTable;
+
        $scope.type = type;
 
+       $scope.toggleVisibility = function(colName) {
+               const col = typeServersTable.column(colName + ':name');
+               col.visible(!col.visible());
+               typeServersTable.rows().invalidate().draw();
+       };
+
        angular.element(document).ready(function () {
-               $('#typeServersTable').dataTable({
-                       "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, 
"All"]],
+               typeServersTable = $('#typeServersTable').DataTable({
+                       "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
                        "iDisplayLength": 25,
-                       "aaSorting": []
+                       "aaSorting": [],
+                       "columns": $scope.columns,
+                       "colReorder": {
+                               realtime: false
+                       },
+                       "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_typeServersTable_/')).columns;
+                               } catch (e) {
+                                       console.error("Failure to retrieve 
required column info from localStorage (key=DataTables_typeServersTable_/):", 
e);
+                               }
+                       }
                });
        });
 
diff --git 
a/traffic_portal/app/src/common/modules/table/typeServers/table.typeServers.tpl.html
 
b/traffic_portal/app/src/common/modules/table/typeServers/table.typeServers.tpl.html
index baf5bb1..eb7b7fc 100644
--- 
a/traffic_portal/app/src/common/modules/table/typeServers/table.typeServers.tpl.html
+++ 
b/traffic_portal/app/src/common/modules/table/typeServers/table.typeServers.tpl.html
@@ -26,6 +26,19 @@ under the License.
         </ol>
         <div class="pull-right">
             <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">
+                    <i class="fa fa-columns"></i>&nbsp;
+                    <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'">
+                        <div class="checkbox">
+                            <label><input type="checkbox" ng-model="c.visible" 
ng-click="toggleVisibility(c.name)"> {{::c.name}}</label>
+                        </div>
+                    </li>
+                </menu>
+            </div>
         </div>
         <div class="clearfix"></div>
     </div>
@@ -33,42 +46,85 @@ under the License.
         <br>
         <table id="typeServersTable" class="table responsive-utilities 
jambo_table">
             <thead>
-            <tr class="headings">
-                <th>UPD</th>
-                <th>Host</th>
-                <th>Domain</th>
-                <th>IP</th>
-                <th>IPv6</th>
-                <th>Status</th>
-                <th>Type</th>
-                <th>Profile</th>
-                <th>CDN</th>
-                <th>Cache Group</th>
-                <th>Phys Location</th>
-                <th>ILO</th>
-            </tr>
+                <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.updPending) ? 'UPD' : ''}}" 
data-order="{{::s.updPending}}">
-                    <i title="Updates Pending" 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>
-                <td data-search="^{{::s.hostName}}$">{{::s.hostName}}</td>
-                <td data-search="^{{::s.domainName}}$">{{::s.domainName}}</td>
-                <td data-search="^{{::s.ipAddress}}$"><a 
ng-click="ssh(s.ipAddress, $event)">{{::s.ipAddress}}</a></td>
-                <td data-search="^{{::s.ip6Address}}$">{{::s.ip6Address}}</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.type}}$">{{::s.type}}</td>
-                <td data-search="^{{::s.profile}}$">{{::s.profile}}</td>
-                <td data-search="^{{::s.cdnName}}$">{{::s.cdnName}}</td>
-                <td data-search="^{{::s.cachegroup}}$">{{::s.cachegroup}}</td>
-                <td 
data-search="^{{::s.physLocation}}$">{{::s.physLocation}}</td>
-                <td data-search="^{{::s.iloIpAddress}}$"><a 
ng-click="ssh(s.iloIpAddress, $event)">{{::s.iloIpAddress}}</a></td>
-            </tr>
+                <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 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>
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 20d80fc..6daa2f2 100644
--- a/traffic_portal/test/end_to_end/Servers/servers-spec.js
+++ b/traffic_portal/test/end_to_end/Servers/servers-spec.js
@@ -69,6 +69,16 @@ describe('Traffic Portal Servers Test Suite', function() {
                
expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/servers");
        });
 
+       it('should toggle the visibility of the first table column ', 
function() {
+               browser.driver.findElement(by.id('toggleColumns')).click();
+               let first = element.all(by.css('input[type=checkbox]')).first();
+               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);
+       });
+
        it('should verify the new Server and then update Server', function() {
                console.log('Verifying new server added and updating ' + 
mockVals.hostName);
                browser.sleep(1000);

Reply via email to