You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by oc...@apache.org on 2021/01/20 18:27:39 UTC

[trafficcontrol] branch master updated: TP: converts DS tables to more performant and powerful ag-grid (#5408)

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 313ecfb  TP: converts DS tables to more performant and powerful ag-grid (#5408)
313ecfb is described below

commit 313ecfb0b907bcbfe185a8144a3a6f4fc8912ee8
Author: Jeremy Mitchell <mi...@users.noreply.github.com>
AuthorDate: Wed Jan 20 11:27:24 2021 -0700

    TP: converts DS tables to more performant and powerful ag-grid (#5408)
    
    * fixes invalid syntax
    
    * converts ds table to ag-grid
    
    * fixes broken context menu item
    
    * adds ag-grid to cdn ds table
    
    * adds ag-grid to profile ds table
    
    * adds More menu to cdn and profile ds table
    
    * adds ag-grid to service category ds table
    
    * add ag-grid to tenant ds table
    
    * adds ag-grid to topology ds table
    
    * adds ag-grid to type ds table
    
    * fixes navigation path
    
    * adds ag-grid to server ds table
    
    * cosmetic changes
    
    * adds changelog.md entry
    
    * updates documentation
    
    * refactors ds tests for new ag-grid
    
    * adds missing name attributes needed for tests
    
    * fixes ds ui tests
    
    * adds sleep
    
    * fixes ui test
    
    * adds min=1 to pagesize for all ag-grid tables
    
    * adds agNumberColumnFilter to number columns
    
    * updates menuitem to not be anchor and use button instead
    
    * fixes broken ui tests
---
 CHANGELOG.md                                       |   1 +
 .../traffic_portal/images/tp_menu_services.png     | Bin 61219 -> 10790 bytes
 .../admin/traffic_portal/images/tp_table_ds.png    | Bin 32698 -> 40552 bytes
 .../traffic_portal/images/tp_table_ds_requests.png | Bin 120150 -> 46902 bytes
 .../admin/traffic_portal/usingtrafficportal.rst    |   2 +-
 .../form.deliveryService.DNS.tpl.html              |   2 +-
 .../form.deliveryService.HTTP.tpl.html             |   2 +-
 .../form.deliveryService.anyMap.tpl.html           |   2 +-
 .../modules/form/tenant/form.tenant.tpl.html       |   4 +-
 .../table.cacheGroupServers.tpl.html               |   2 +-
 .../TableCDNDeliveryServicesController.js          |  32 +-
 .../table.cdnDeliveryServices.tpl.html             | 240 +++---
 .../table/cdnServers/table.cdnServers.tpl.html     |   2 +-
 .../table/changeLogs/TableChangeLogsController.js  |   4 +-
 .../table/changeLogs/table.changeLogs.tpl.html     |   2 +-
 .../table.deliveryServiceJobs.tpl.html             |   2 +-
 .../TableDeliveryServiceRequestsController.js      |   6 +-
 .../table.deliveryServiceRequests.tpl.html         |   2 +-
 .../table.deliveryServiceServers.tpl.html          |   2 +-
 .../TableDeliveryServicesController.js             | 829 +++++++++++++++------
 .../table.deliveryServices.tpl.html                | 248 +++---
 .../modules/table/jobs/TableJobsController.js      |   6 +-
 .../common/modules/table/jobs/table.jobs.tpl.html  |   2 +-
 .../table.physLocationServers.tpl.html             |   2 +-
 .../TableProfileDeliveryServicesController.js      |  32 +-
 .../table.profileDeliveryServices.tpl.html         | 237 +++---
 .../profileServers/table.profileServers.tpl.html   |   2 +-
 .../TableServerDeliveryServicesController.js       |  61 +-
 .../table.serverDeliveryServices.tpl.html          | 260 +++----
 .../modules/table/servers/table.servers.tpl.html   |   2 +-
 ...bleServiceCategoryDeliveryServicesController.js |  32 +-
 .../table.serviceCategoryDeliveryServices.tpl.html | 239 +++---
 .../statusServers/table.statusServers.tpl.html     |   2 +-
 .../TableTenantDeliveryServicesController.js       |  32 +-
 .../table.tenantDeliveryServices.tpl.html          | 237 +++---
 .../table.topologyCacheGroups.tpl.html             |   4 +-
 .../TableTopologyDeliveryServicesController.js     |  32 +-
 .../table.topologyDeliveryServices.tpl.html        | 239 +++---
 .../topologyServers/table.topologyServers.tpl.html |   2 +-
 .../TableTypeDeliveryServicesController.js         |  32 +-
 .../table.typeDeliveryServices.tpl.html            | 237 +++---
 .../table/typeServers/table.typeServers.tpl.html   |   2 +-
 .../modules/private/cdns/deliveryServices/index.js |   9 +
 .../modules/private/deliveryServices/list/index.js |   6 +
 .../private/profiles/deliveryServices/index.js     |   9 +
 .../private/servers/deliveryServices/index.js      |   3 +
 .../serviceCategories/deliveryServices/index.js    |   9 +
 .../private/tenants/deliveryServices/index.js      |  12 +
 .../private/topologies/deliveryServices/index.js   |   9 +
 .../private/types/deliveryServices/index.js        |   9 +
 .../deliveryServices/delivery-services-spec.js     | 123 ++-
 .../test/end_to_end/deliveryServices/pageData.js   |   3 +-
 52 files changed, 1467 insertions(+), 1803 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 782343c..4fcbb71 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 ### Added
 - Traffic Portal: [#5394](https://github.com/apache/trafficcontrol/issues/5394) - Converts the tenant table to a tenant tree for usability
 - Traffic Portal: [#5360](https://github.com/apache/trafficcontrol/issues/5360) - Adds the ability to clone a topology
+- Traffic Portal: upgraded delivery service UI tables to use more powerful/performant ag-grid component
 - Traffic Ops: added a feature so that the user can specify `maxRequestHeaderBytes` on a per delivery service basis
 - Traffic Router: log warnings when requests to Traffic Monitor return a 503 status code
 - [#5344](https://github.com/apache/trafficcontrol/issues/5344) - Add a page that addresses migrating from Traffic Ops API v1 for each endpoint
diff --git a/docs/source/admin/traffic_portal/images/tp_menu_services.png b/docs/source/admin/traffic_portal/images/tp_menu_services.png
index d887b16..eb55d1f 100644
Binary files a/docs/source/admin/traffic_portal/images/tp_menu_services.png and b/docs/source/admin/traffic_portal/images/tp_menu_services.png differ
diff --git a/docs/source/admin/traffic_portal/images/tp_table_ds.png b/docs/source/admin/traffic_portal/images/tp_table_ds.png
index 0db24bb..71dff11 100644
Binary files a/docs/source/admin/traffic_portal/images/tp_table_ds.png and b/docs/source/admin/traffic_portal/images/tp_table_ds.png differ
diff --git a/docs/source/admin/traffic_portal/images/tp_table_ds_requests.png b/docs/source/admin/traffic_portal/images/tp_table_ds_requests.png
index ae4ed39..28e91d4 100644
Binary files a/docs/source/admin/traffic_portal/images/tp_table_ds_requests.png and b/docs/source/admin/traffic_portal/images/tp_table_ds_requests.png differ
diff --git a/docs/source/admin/traffic_portal/usingtrafficportal.rst b/docs/source/admin/traffic_portal/usingtrafficportal.rst
index e3d67b2..4e45bf1 100644
--- a/docs/source/admin/traffic_portal/usingtrafficportal.rst
+++ b/docs/source/admin/traffic_portal/usingtrafficportal.rst
@@ -191,7 +191,7 @@ A table showing the results of the periodic :ref:`to-check-ext` that are run. Th
 
 Services
 ========
-:guilabel:`Services` groups the functionality to modify :term:`Delivery Services` - for those users with the necessary permissions - or make Delivery Service Requests for such changes - for users without necessary permissions.
+:guilabel:`Services` groups the functionality to modify :term:`Delivery Services` - for those users with the necessary permissions - or make Delivery Service Requests for such changes - for users without necessary permissions. Delivery Services can also be grouped by :term:`Service Category`.
 
 
 .. figure:: ./images/tp_menu_services.png
diff --git a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html
index 11ed857..17b3729 100644
--- a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html
+++ b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html
@@ -59,7 +59,7 @@ under the License.
                     <li role="menuitem"><a ng-click="viewOrigins()">Manage Origins</a></li>
                     <li role="menuitem"><a ng-click="viewRegexes()">Manage Regexes</a></li>
                     <li role="menuitem"><a ng-click="viewCapabilities()">Manage Required Server Capabilities</a></li>
-                    <li role="menuitem"><a ng-click="viewServers()">Manage Servers</a></li>
+                    <li name="manageServersMenuItem" role="menuitem"><button class="menu-item-button" type="button" ng-click="viewServers()">Manage Servers</button></li>
                     <li role="menuitem"><a ng-click="viewStaticDnsEntries()">Manage Static DNS Entries</a></li>
                 </ul>
             </div>
diff --git a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.HTTP.tpl.html b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.HTTP.tpl.html
index 6866cf7..a5034f2 100644
--- a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.HTTP.tpl.html
+++ b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.HTTP.tpl.html
@@ -59,7 +59,7 @@ under the License.
                     <li role="menuitem"><a ng-click="viewOrigins()">Manage Origins</a></li>
                     <li role="menuitem"><a ng-click="viewRegexes()">Manage Regexes</a></li>
                     <li role="menuitem"><a ng-click="viewCapabilities()">Manage Required Server Capabilities</a></li>
-                    <li role="menuitem"><a ng-click="viewServers()">Manage Servers</a></li>
+                    <li name="manageServersMenuItem" role="menuitem"><button class="menu-item-button" type="button" ng-click="viewServers()">Manage Servers</button></li>
                     <li role="menuitem"><a ng-click="viewStaticDnsEntries()">Manage Static DNS Entries</a></li>
                 </ul>
             </div>
diff --git a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.anyMap.tpl.html b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.anyMap.tpl.html
index 7def518..288433d 100644
--- a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.anyMap.tpl.html
+++ b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.anyMap.tpl.html
@@ -51,7 +51,7 @@ under the License.
                     <hr class="divider"/>
                     <li role="menuitem"><a ng-click="viewCharts()">View Charts</a></li>
                     <hr class="divider"/>
-                    <li role="menuitem"><a ng-click="viewServers()">Manage Servers</a></li>
+                    <li name="manageServersMenuItem" role="menuitem"><button class="menu-item-button" type="button" ng-click="viewServers()">Manage Servers</button></li>
                 </ul>
             </div>
         </div>
diff --git a/traffic_portal/app/src/common/modules/form/tenant/form.tenant.tpl.html b/traffic_portal/app/src/common/modules/form/tenant/form.tenant.tpl.html
index 92770a0..af44208 100644
--- a/traffic_portal/app/src/common/modules/form/tenant/form.tenant.tpl.html
+++ b/traffic_portal/app/src/common/modules/form/tenant/form.tenant.tpl.html
@@ -24,9 +24,9 @@ under the License.
             <li class="active">{{tenantName}}</li>
         </ol>
         <div class="pull-right" role="group" ng-show="!settings.isNew">
-            <button class="btn btn-default" title="View Users" ng-click="viewUsers()">View Users</button>
+            <button class="btn btn-primary" title="View Users" ng-click="viewUsers()">View Users</button>
             <div class="btn-group" role="group" uib-dropdown is-open="more.isopen">
-                <button name="moreBtn" type="button" class="btn btn-default dropdown-toggle" uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
+                <button name="moreBtn" type="button" class="btn btn-primary dropdown-toggle" uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
                     View Delivery Services&nbsp;
                     <span class="caret"></span>
                 </button>
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 db53bbd..2ab2b63 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
@@ -31,7 +31,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
                 </div>
                 <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">
diff --git a/traffic_portal/app/src/common/modules/table/cdnDeliveryServices/TableCDNDeliveryServicesController.js b/traffic_portal/app/src/common/modules/table/cdnDeliveryServices/TableCDNDeliveryServicesController.js
index b0324fc..23a22e0 100644
--- a/traffic_portal/app/src/common/modules/table/cdnDeliveryServices/TableCDNDeliveryServicesController.js
+++ b/traffic_portal/app/src/common/modules/table/cdnDeliveryServices/TableCDNDeliveryServicesController.js
@@ -17,39 +17,13 @@
  * under the License.
  */
 
-var TableCDNDeliveryServicesController = function(cdn, deliveryServices, $controller, $scope) {
+var TableCDNDeliveryServicesController = function(cdn, deliveryServices, filter, $controller, $scope) {
 
 	// extends the TableDeliveryServicesController to inherit common methods
-	angular.extend(this, $controller('TableDeliveryServicesController', { deliveryServices: deliveryServices, $scope: $scope }));
-
-	let cdnDeliveryServicesTable;
+	angular.extend(this, $controller('TableDeliveryServicesController', { tableName: 'cdnDS', deliveryServices: deliveryServices, filter: filter, $scope: $scope }));
 
 	$scope.cdn = cdn;
-
-	$scope.toggleVisibility = function(colName) {
-		const col = cdnDeliveryServicesTable.column(colName + ':name');
-		col.visible(!col.visible());
-		cdnDeliveryServicesTable.rows().invalidate().draw();
-	};
-
-	angular.element(document).ready(function () {
-		cdnDeliveryServicesTable = $('#cdnDeliveryServicesTable').DataTable({
-			"lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
-			"iDisplayLength": 25,
-			"aaSorting": [],
-			"columns": $scope.columns,
-			"initComplete": function(settings, json) {
-				try {
-					// need to create the show/hide column checkboxes and bind to the current visibility
-					$scope.columns = JSON.parse(localStorage.getItem('DataTables_cdnDeliveryServicesTable_/')).columns;
-				} catch (e) {
-					console.error("Failure to retrieve required column info from localStorage (key=DataTables_cdnDeliveryServicesTable_/):", e);
-				}
-			}
-		});
-	});
-
 };
 
-TableCDNDeliveryServicesController.$inject = ['cdn', 'deliveryServices', '$controller', '$scope'];
+TableCDNDeliveryServicesController.$inject = ['cdn', 'deliveryServices', 'filter', '$controller', '$scope'];
 module.exports = TableCDNDeliveryServicesController;
diff --git a/traffic_portal/app/src/common/modules/table/cdnDeliveryServices/table.cdnDeliveryServices.tpl.html b/traffic_portal/app/src/common/modules/table/cdnDeliveryServices/table.cdnDeliveryServices.tpl.html
index 1aff3fc..5490bd1 100644
--- a/traffic_portal/app/src/common/modules/table/cdnDeliveryServices/table.cdnDeliveryServices.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/cdnDeliveryServices/table.cdnDeliveryServices.tpl.html
@@ -20,167 +20,101 @@ under the License.
 <div class="x_panel">
     <div class="x_title">
         <ol class="breadcrumb pull-left">
-            <li><a ng-click="navigateToPath('/cdns')">CDNs</a></li>
-            <li><a ng-click="navigateToPath('/cdns/' + cdn.id)">{{cdn.name}}</a></li>
+            <li><a href="#!/cdns">CDNs</a></li>
+            <li><a ng-href="#!/cdns/{{cdn.id}}">{{::cdn.name}}</a></li>
             <li class="active">Delivery Services</li>
         </ol>
         <div class="pull-right">
-            <button class="btn btn-default" title="Refresh" ng-click="refresh()"><i class="fa fa-refresh"></i></button>
-            <div 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 class="form-inline" role="search">
+                <input id="quickSearch" name="quickSearch" type="search" class="form-control text-input" placeholder="Quick search..." ng-model="quickSearch" ng-change="onQuickSearchChanged()" aria-label="Search"/>
+                <div class="input-group text-input">
+                    <span class="input-group-addon">
+                        <label for="pageSize">Page size</label>
+                    </span>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                </div>
+                <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 gridOptions.columnApi.getAllColumns() | orderBy:'colDef.headerName'">
+                            <div class="checkbox">
+                                <label><input type="checkbox" ng-checked="c.isVisible()" ng-click="toggleVisibility(c.colId)">{{::c.colDef.headerName}}</label>
+                            </div>
+                        </li>
+                    </menu>
+                </div>
+                <div class="btn-group" role="group" uib-dropdown is-open="more.isopen">
+                    <button name="moreBtn" type="button" class="btn btn-default dropdown-toggle" uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
+                        More&nbsp;
+                        <span class="caret"></span>
+                    </button>
+                    <ul class="dropdown-menu-right dropdown-menu" uib-dropdown-menu>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="clearTableFilters()">Clear Table Filters</button></li>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="exportCSV()">Export CSV</button></li>
+                    </ul>
+                </div>
             </div>
         </div>
         <div class="clearfix"></div>
     </div>
     <div class="x_content">
-        <br>
-        <table id="cdnDeliveryServicesTable" class="table responsive-utilities jambo_table">
-            <thead>
-                <tr class="headings">
-                    <th>Active</th>
-                    <th>Anonymous Blocking</th>
-                    <th>CDN</th>
-                    <th>Check Path</th>
-                    <th>Consistent Hash Query Params</th>
-                    <th>Consistent Hash Regex</th>
-                    <th>Deep Caching Type</th>
-                    <th>Display Name</th>
-                    <th>DNS Bypass CNAME</th>
-                    <th>DNS Bypass IP</th>
-                    <th>DNS Bypass IPv6</th>
-                    <th>DNS Bypass TTL</th>
-                    <th>DNS TTL</th>
-                    <th>DSCP</th>
-                    <th>ECS Enabled</th>
-                    <th>Edge Header Rewrite Rules</th>
-                    <th>First Header Rewrite Rules</th>
-                    <th>FQ Pacing Rate</th>
-                    <th>Geo Limit</th>
-                    <th>Geo Limit Countries</th>
-                    <th>Geo Limit Redirect URL</th>
-                    <th>Geolocation Provider</th>
-                    <th>Geo Miss Latitude</th>
-                    <th>Geo Miss Longitude</th>
-                    <th>Global Max Mbps</th>
-                    <th>Global Max TPS</th>
-                    <th>HTTP Bypass FQDN</th>
-                    <th>ID</th>
-                    <th>Info URL</th>
-                    <th>Initial Dispersion</th>
-                    <th>Inner Header Rewrite Rules</th>
-                    <th>IPv6 Routing</th>
-                    <th>Last Header Rewrite Rules</th>
-                    <th>Last Updated</th>
-                    <th>Long Desc 1</th>
-                    <th>Long Desc 2</th>
-                    <th>Long Desc 3</th>
-                    <th>Max DNS Answers</th>
-                    <th>Max Origin Connections</th>
-                    <th>Max Request Header Bytes</th>
-                    <th>Mid Header Rewrite Rules</th>
-                    <th>Multi-Site Origin</th>
-                    <th>Origin Shield</th>
-                    <th>Origin FQDN</th>
-                    <th>Profile</th>
-                    <th>Protocol</th>
-                    <th>Qstring Handling</th>
-                    <th>Range Request Handling</th>
-                    <th>Regex Remap Expression</th>
-                    <th>Regional Geoblocking</th>
-                    <th>Raw Remap Text</th>
-                    <th>Routing Name</th>
-                    <th>Service Category</th>
-                    <th>Signed</th>
-                    <th>Signing Algorithm</th>
-                    <th>Range Slice Block Size</th>
-                    <th>Tenant</th>
-                    <th>Topology</th>
-                    <th>TR Request Headers</th>
-                    <th>TR Response Headers</th>
-                    <th>Type</th>
-                    <th>XML ID (Key)</th>
-                </tr>
-            </thead>
-            <tbody>
-                <tr ng-click="editDeliveryService(ds)" ng-repeat="ds in ::deliveryServices" context-menu="contextMenuItems">
-                    <td data-search="^{{::ds.active}}$">{{::ds.active}}</td>
-                    <td data-search="^{{::ds.anonymousBlockingEnabled}}$">{{::ds.anonymousBlockingEnabled}}</td>
-                    <td data-search="^{{::ds.cdnName}}$">{{::ds.cdnName}}</td>
-                    <td data-search="^{{::ds.checkPath}}$">{{::ds.checkPath}}</td>
-                    <td data-search="^{{::ds.consistentHashQueryParams}}$">{{::ds.consistentHashQueryParams.join(', ')}}</td>
-                    <td data-search="^{{::ds.consistentHashRegex}}$">{{::ds.consistentHashRegex}}</td>
-                    <td data-search="^{{::ds.deepCachingType}}$">{{::ds.deepCachingType}}</td>
-                    <td data-search="^{{::ds.displayName}}$">{{::ds.displayName}}</td>
-                    <td data-search="^{{::ds.dnsBypassCname}}$">{{::ds.dnsBypassCname}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp}}$">{{::ds.dnsBypassIp}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp6}}$">{{::ds.dnsBypassIp6}}</td>
-                    <td data-search="^{{::ds.dnsBypassTtl}}$">{{::ds.dnsBypassTtl}}</td>
-                    <td data-search="^{{::ds.ccrDnsTtl}}$">{{::ds.ccrDnsTtl}}</td>
-                    <td data-search="^{{::ds.dscp}}$">{{::ds.dscp}}</td>
-                    <td data-search="^{{::ds.ecsEnabled}}$">{{::ds.ecsEnabled}}</td>
-                    <td data-search="^{{::ds.edgeHeaderRewrite}}$">{{::ds.edgeHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.firstHeaderRewrite}}$">{{::ds.firstHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.fqPacingRate}}$">{{::ds.fqPacingRate}}</td>
-                    <td data-search="^{{::geoLimit(ds)}}$">{{::geoLimit(ds)}}</td>
-                    <td data-search="^{{::ds.geoLimitCountries}}$">{{::ds.geoLimitCountries}}</td>
-                    <td data-search="^{{::ds.geoLimitRedirectURL}}$">{{::ds.geoLimitRedirectURL}}</td>
-                    <td data-search="^{{::geoProvider(ds)}}$">{{::geoProvider(ds)}}</td>
-                    <td data-search="^{{::ds.missLat}}$">{{::ds.missLat}}</td>
-                    <td data-search="^{{::ds.missLong}}$">{{::ds.missLong}}</td>
-                    <td data-search="^{{::ds.globalMaxMbps}}$">{{::ds.globalMaxMbps}}</td>
-                    <td data-search="^{{::ds.globalMaxTps}}$">{{::ds.globalMaxTps}}</td>
-                    <td data-search="^{{::ds.httpBypassFqdn}}$">{{::ds.httpBypassFqdn}}</td>
-                    <td data-search="^{{::ds.id}}$">{{::ds.id}}</td>
-                    <td data-search="^{{::ds.infoUrl}}$">{{::ds.infoUrl}}</td>
-                    <td data-search="^{{::ds.initialDispersion}}$">{{::ds.initialDispersion}}</td>
-                    <td data-search="^{{::ds.innerHeaderRewrite}}$">{{::ds.innerHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.ipv6RoutingEnabled}}$">{{::ds.ipv6RoutingEnabled}}</td>
-                    <td data-search="^{{::ds.lastHeaderRewrite}}$">{{::ds.lastHeaderRewrite}}</td>
-                    <td data-search="^{{::getRelativeTime(ds.lastUpdated)}}$" data-order="{{::ds.lastUpdated}}">{{::getRelativeTime(ds.lastUpdated)}}</td>
-                    <td data-search="^{{::ds.longDesc}}$">{{::ds.longDesc}}</td>
-                    <td data-search="^{{::ds.longDesc1}}$">{{::ds.longDesc1}}</td>
-                    <td data-search="^{{::ds.longDesc2}}$">{{::ds.longDesc2}}</td>
-                    <td data-search="^{{::ds.maxDnsAnswers}}$">{{::ds.maxDnsAnswers}}</td>
-                    <td data-search="^{{::ds.maxOriginConnections}}$">{{::ds.maxOriginConnections}}</td>
-                    <td data-search="^{{::ds.maxRequestHeaderBytes}}$">{{::ds.maxRequestHeaderBytes}}</td>
-                    <td data-search="^{{::ds.midHeaderRewrite}}$">{{::ds.midHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.multiSiteOrigin}}$">{{::ds.multiSiteOrigin}}</td>
-                    <td data-search="^{{::ds.originShield}}$">{{::ds.originShield}}</td>
-                    <td data-search="^{{::ds.orgServerFqdn}}$">{{::ds.orgServerFqdn}}</td>
-                    <td data-search="^{{::ds.profileName}}$">{{::ds.profileName}}</td>
-                    <td data-search="^{{::protocol(ds)}}$">{{::protocol(ds)}}</td>
-                    <td data-search="^{{::qstring(ds)}}$">{{::qstring(ds)}}</td>
-                    <td data-search="^{{::rrh(ds)}}$">{{::rrh(ds)}}</td>
-                    <td data-search="^{{::ds.regexRemap}}$">{{::ds.regexRemap}}</td>
-                    <td data-search="^{{::ds.regionalGeoBlocking}}$">{{::ds.regionalGeoBlocking}}</td>
-                    <td data-search="^{{::ds.remapText}}$">{{::ds.remapText}}</td>
-                    <td data-search="^{{::ds.routingName}}$">{{::ds.routingName}}</td>
-                    <td data-search="^{{::ds.serviceCategory}}$">{{::ds.serviceCategory}}</td>
-                    <td data-search="^{{::ds.signed}}$">{{::ds.signed}}</td>
-                    <td data-search="^{{::ds.signingAlgorithm}}$">{{::ds.signingAlgorithm}}</td>
-                    <td data-search="^{{::ds.rangeSliceBlockSize}}$">{{::ds.rangeSliceBlockSize}}</td>
-                    <td data-search="^{{::ds.tenant}}$">{{::ds.tenant}}</td>
-                    <td data-search="^{{::ds.topology}}$">{{::ds.topology}}</td>
-                    <td data-search="^{{::ds.trResponseHeaders}}$">{{::ds.trResponseHeaders}}</td>
-                    <td data-search="^{{::ds.trRequestHeaders}}$">{{::ds.trRequestHeaders}}</td>
-                    <td data-search="^{{::ds.type}}$">{{::ds.type}}</td>
-                    <td name="xmlId" data-search="^{{::ds.xmlId}}$">{{::ds.xmlId}}</td>
-                </tr>
-            </tbody>
-        </table>
+        <div style="height: 740px;" ag-grid="gridOptions" class="ag-theme-alpine"></div>
     </div>
 </div>
 
-
-
-
+<menu id="context-menu" class="dropdown-menu" ng-style="menuStyle" type="contextmenu" ng-show="showMenu">
+    <ul>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}" target="_blank">Open {{ deliveryService.xmlId }} in New Tab</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}">Edit</a>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="clone(deliveryService, $event)">Clone</button>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="confirmDelete(deliveryService, $event)">Delete</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <button type="button" ng-click="viewCharts(deliveryService, $event)">View Charts</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/ssl-keys?type={{deliveryService.type}}">Manage SSL Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/url-sig-keys?type={{deliveryService.type}}">Manage URL Sig Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/uri-signing-keys?type={{deliveryService.type}}">Manage URI Signing Keys</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/jobs?type={{deliveryService.type}}">Manage Invalidation Requests</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') == -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/origins?type={{deliveryService.type}}">Manage Origins</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/regexes?type={{deliveryService.type}}">Manage Regexes</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('DNS') != -1 || deliveryService.type.indexOf('HTTP') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/required-server-capabilities?type={{deliveryService.type}}">Manage Required Server Capabilities</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/servers?type={{deliveryService.type}}">Manage Servers</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/targets?type={{deliveryService.type}}">Manage Targets</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/static-dns-entries?type={{deliveryService.type}}">Manage Static DNS Entries</a>
+        </li>
+    </ul>
+</menu>
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 7b0a649..3ba7245 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
@@ -31,7 +31,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
                 </div>
                 <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">
diff --git a/traffic_portal/app/src/common/modules/table/changeLogs/TableChangeLogsController.js b/traffic_portal/app/src/common/modules/table/changeLogs/TableChangeLogsController.js
index b56dcc2..852925b 100644
--- a/traffic_portal/app/src/common/modules/table/changeLogs/TableChangeLogsController.js
+++ b/traffic_portal/app/src/common/modules/table/changeLogs/TableChangeLogsController.js
@@ -43,7 +43,7 @@ var TableChangeLogsController = function(tableName, changeLogs, $scope, $state,
 			field: "lastUpdated",
 			hide: false,
 			filter: "agDateColumnFilter",
-			tooltipValueGetter: () => dateCellFormatterRelative,
+			tooltipValueGetter: dateCellFormatterRelative,
 			valueFormatter: dateCellFormatterRelative
 		},
 		{
@@ -51,7 +51,7 @@ var TableChangeLogsController = function(tableName, changeLogs, $scope, $state,
 			field: "lastUpdated",
 			hide: false,
 			filter: "agDateColumnFilter",
-			tooltipValueGetter: () => dateCellFormatter,
+			tooltipValueGetter: dateCellFormatter,
 			valueFormatter: dateCellFormatter
 		},
 		{
diff --git a/traffic_portal/app/src/common/modules/table/changeLogs/table.changeLogs.tpl.html b/traffic_portal/app/src/common/modules/table/changeLogs/table.changeLogs.tpl.html
index 4c6f311..3c15220 100644
--- a/traffic_portal/app/src/common/modules/table/changeLogs/table.changeLogs.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/changeLogs/table.changeLogs.tpl.html
@@ -29,7 +29,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" />
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" />
                 </div>
                 <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">
diff --git a/traffic_portal/app/src/common/modules/table/deliveryServiceJobs/table.deliveryServiceJobs.tpl.html b/traffic_portal/app/src/common/modules/table/deliveryServiceJobs/table.deliveryServiceJobs.tpl.html
index 674f65b..4518ebd 100644
--- a/traffic_portal/app/src/common/modules/table/deliveryServiceJobs/table.deliveryServiceJobs.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/deliveryServiceJobs/table.deliveryServiceJobs.tpl.html
@@ -31,7 +31,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
                 </div>
                 <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">
diff --git a/traffic_portal/app/src/common/modules/table/deliveryServiceRequests/TableDeliveryServiceRequestsController.js b/traffic_portal/app/src/common/modules/table/deliveryServiceRequests/TableDeliveryServiceRequestsController.js
index dbae397..5bc3ce3 100644
--- a/traffic_portal/app/src/common/modules/table/deliveryServiceRequests/TableDeliveryServiceRequestsController.js
+++ b/traffic_portal/app/src/common/modules/table/deliveryServiceRequests/TableDeliveryServiceRequestsController.js
@@ -69,7 +69,7 @@ var TableDeliveryServicesRequestsController = function (tableName, dsRequests, $
 			field: "lastUpdated",
 			hide: true,
 			filter: "agDateColumnFilter",
-			tooltipValueGetter: () => dateCellFormatter,
+			tooltipValueGetter: dateCellFormatter,
 			valueFormatter: dateCellFormatter
 		},
 		{
@@ -77,7 +77,7 @@ var TableDeliveryServicesRequestsController = function (tableName, dsRequests, $
 			field: "createdAt",
 			hide: false,
 			filter: "agDateColumnFilter",
-			tooltipValueGetter: () => dateCellFormatter,
+			tooltipValueGetter: dateCellFormatter,
 			valueFormatter: dateCellFormatter
 		}
 	];
@@ -155,7 +155,7 @@ var TableDeliveryServicesRequestsController = function (tableName, dsRequests, $
 			filter: true,
 			sortable: true,
 			resizable: true,
-			tooltipValueGetter: () => defaultTooltip
+			tooltipValueGetter: defaultTooltip
 		},
 		rowClassRules: {
 			'draft-request': function(params) {
diff --git a/traffic_portal/app/src/common/modules/table/deliveryServiceRequests/table.deliveryServiceRequests.tpl.html b/traffic_portal/app/src/common/modules/table/deliveryServiceRequests/table.deliveryServiceRequests.tpl.html
index 35429c5..2e98219 100644
--- a/traffic_portal/app/src/common/modules/table/deliveryServiceRequests/table.deliveryServiceRequests.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/deliveryServiceRequests/table.deliveryServiceRequests.tpl.html
@@ -29,7 +29,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" />
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" />
                 </div>
                 <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">
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 3b83c1d..5958b86 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
@@ -31,7 +31,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
                 </div>
                 <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">
diff --git a/traffic_portal/app/src/common/modules/table/deliveryServices/TableDeliveryServicesController.js b/traffic_portal/app/src/common/modules/table/deliveryServices/TableDeliveryServicesController.js
index 2b03fcb..d2d87ec 100644
--- a/traffic_portal/app/src/common/modules/table/deliveryServices/TableDeliveryServicesController.js
+++ b/traffic_portal/app/src/common/modules/table/deliveryServices/TableDeliveryServicesController.js
@@ -17,30 +17,399 @@
  * under the License.
  */
 
-var TableDeliveryServicesController = function(deliveryServices, $anchorScroll, $scope, $state, $location, $uibModal, $window, deliveryServiceService, deliveryServiceRequestService, dateUtils, deliveryServiceUtils, locationUtils, messageModel, propertiesModel, userModel) {
-
-    let deliveryServicesTable;
-
-    var protocols = deliveryServiceUtils.protocols;
-
-    var qstrings = deliveryServiceUtils.qstrings;
-
-    var geoProviders = deliveryServiceUtils.geoProviders;
-
-    var geoLimits = deliveryServiceUtils.geoLimits;
-
-    var rrhs = deliveryServiceUtils.rrhs;
+var TableDeliveryServicesController = function(tableName, deliveryServices, filter, $anchorScroll, $document, $scope, $state, $location, $uibModal, deliveryServiceService, deliveryServiceRequestService, dateUtils, deliveryServiceUtils, locationUtils, messageModel, propertiesModel, userModel) {
+
+    /**
+     * Gets value to display a default tooltip.
+     */
+    function defaultTooltip(params) {
+        return params.value;
+    }
+
+    /**
+     * Formats the contents of a 'lastUpdated' column cell as "relative to now".
+     */
+    function dateCellFormatter(params) {
+        return params.value ? dateUtils.getRelativeTime(params.value) : params.value;
+    }
+
+    /** The columns of the ag-grid table */
+    const columns = [
+        {
+            headerName: "Active",
+            field: "active",
+            hide: false
+        },
+        {
+            headerName: "Anonymous Blocking",
+            field: "anonymousBlockingEnabled",
+            hide: true
+        },
+        {
+            headerName: "CDN",
+            field: "cdnName",
+            hide: false
+        },
+        {
+            headerName: "Check Path",
+            field: "checkPath",
+            hide: true
+        },
+        {
+            headerName: "Consistent Hash Query Params",
+            field: "consistentHashQueryParams",
+            hide: true,
+            valueFormatter: function(params) {
+                return params.data.consistentHashQueryParams.join(', ');
+            },
+            tooltipValueGetter: function(params) {
+                return params.data.consistentHashQueryParams.join(', ');
+            }
+        },
+        {
+            headerName: "Consistent Hash Regex",
+            field: "consistentHashRegex",
+            hide: true
+        },
+        {
+            headerName: "Deep Caching Type",
+            field: "deepCachingType",
+            hide: true
+        },
+        {
+            headerName: "Display Name",
+            field: "displayName",
+            hide: false
+        },
+        {
+            headerName: "DNS Bypass CNAME",
+            field: "dnsBypassCname",
+            hide: true
+        },
+        {
+            headerName: "DNS Bypass IP",
+            field: "dnsBypassIp",
+            hide: true
+        },
+        {
+            headerName: "DNS Bypass IPv6",
+            field: "dnsBypassIp6",
+            hide: true
+        },
+        {
+            headerName: "DNS Bypass TTL",
+            field: "dnsBypassTtl",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "DNS TTL",
+            field: "ccrDnsTtl",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "DSCP",
+            field: "dscp",
+            hide: false,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "ECS Enabled",
+            field: "ecsEnabled",
+            hide: true
+        },
+        {
+            headerName: "Edge Header Rewrite Rules",
+            field: "edgeHeaderRewrite",
+            hide: true
+        },
+        {
+            headerName: "First Header Rewrite Rules",
+            field: "firstHeaderRewrite",
+            hide: true
+        },
+        {
+            headerName: "FQ Pacing Rate",
+            field: "fqPacingRate",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "Geo Limit",
+            field: "geoLimit",
+            hide: true,
+            valueFormatter: function(params) {
+                return deliveryServiceUtils.geoLimits[params.data.geoLimit];
+            },
+            tooltipValueGetter: function(params) {
+                return deliveryServiceUtils.geoLimits[params.data.geoLimit];
+            }
+        },
+        {
+            headerName: "Geo Limit Countries",
+            field: "geoLimitCountries",
+            hide: true
+        },
+        {
+            headerName: "Geo Limit Redirect URL",
+            field: "geoLimitRedirectURL",
+            hide: true
+        },
+        {
+            headerName: "Geolocation Provider",
+            field: "geoProvider",
+            hide: true,
+            valueFormatter: function(params) {
+                return deliveryServiceUtils.geoProviders[params.data.geoProvider];
+            },
+            tooltipValueGetter: function(params) {
+                return deliveryServiceUtils.geoProviders[params.data.geoProvider];
+            }
+        },
+        {
+            headerName: "Geo Miss Latitude",
+            field: "missLat",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "Geo Miss Longitude",
+            field: "missLong",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "Global Max Mbps",
+            field: "globalMaxMbps",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "Global Max TPS",
+            field: "globalMaxTps",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "HTTP Bypass FQDN",
+            field: "httpBypassFqdn",
+            hide: true
+        },
+        {
+            headerName: "ID",
+            field: "id",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "Info URL",
+            field: "infoUrl",
+            hide: true
+        },
+        {
+            headerName: "Initial Dispersion",
+            field: "initialDispersion",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "Inner Header Rewrite Rules",
+            field: "innerHeaderRewrite",
+            hide: true
+        },
+        {
+            headerName: "IPv6 Routing",
+            field: "ipv6RoutingEnabled",
+            hide: true
+        },
+        {
+            headerName: "Last Header Rewrite Rules",
+            field: "lastHeaderRewrite",
+            hide: true
+        },
+        {
+            headerName: "Last Updated",
+            field: "lastUpdated",
+            hide: true,
+            filter: "agDateColumnFilter",
+            valueFormatter: dateCellFormatter
+        },
+        {
+            headerName: "Long Desc 1",
+            field: "longDesc",
+            hide: true
+        },
+        {
+            headerName: "Long Desc 2",
+            field: "longDesc1",
+            hide: true
+        },
+        {
+            headerName: "Long Desc 3",
+            field: "longDesc2",
+            hide: true
+        },
+        {
+            headerName: "Max DNS Answers",
+            field: "maxDnsAnswers",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "Max Origin Connections",
+            field: "maxOriginConnections",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "Max Request Header Bytes",
+            field: "maxRequestHeaderBytes",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "Mid Header Rewrite Rules",
+            field: "midHeaderRewrite",
+            hide: true
+        },
+        {
+            headerName: "Multi-Site Origin",
+            field: "multiSiteOrigin",
+            hide: true
+        },
+        {
+            headerName: "Origin Shield",
+            field: "originShield",
+            hide: true
+        },
+        {
+            headerName: "Origin FQDN",
+            field: "orgServerFqdn",
+            hide: false
+        },
+        {
+            headerName: "Profile",
+            field: "profileName",
+            hide: true
+        },
+        {
+            headerName: "Protocol",
+            field: "protocol",
+            hide: false,
+            valueFormatter: function(params) {
+                return deliveryServiceUtils.protocols[params.data.protocol];
+            },
+            tooltipValueGetter: function(params) {
+                return deliveryServiceUtils.protocols[params.data.protocol];
+            }
+        },
+        {
+            headerName: "Qstring Handling",
+            field: "qstringIgnore",
+            hide: true,
+            valueFormatter: function(params) {
+                return deliveryServiceUtils.qstrings[params.data.qstringIgnore];
+            },
+            tooltipValueGetter: function(params) {
+                return deliveryServiceUtils.qstrings[params.data.qstringIgnore];
+            }
+        },
+        {
+            headerName: "Range Request Handling",
+            field: "rangeRequestHandling",
+            hide: true,
+            valueFormatter: function(params) {
+                return deliveryServiceUtils.rrhs[params.data.rangeRequestHandling];
+            },
+            tooltipValueGetter: function(params) {
+                return deliveryServiceUtils.rrhs[params.data.rangeRequestHandling];
+            }
+        },
+        {
+            headerName: "Regex Remap Expression",
+            field: "regexRemap",
+            hide: true
+        },
+        {
+            headerName: "Regional Geoblocking",
+            field: "regionalGeoBlocking",
+            hide: true
+        },
+        {
+            headerName: "Raw Remap Text",
+            field: "remapText",
+            hide: true
+        },
+        {
+            headerName: "Routing Name",
+            field: "routingName",
+            hide: true
+        },
+        {
+            headerName: "Service Category",
+            field: "serviceCategory",
+            hide: true
+        },
+        {
+            headerName: "Signed",
+            field: "signed",
+            hide: true
+        },
+        {
+            headerName: "Signing Algorithm",
+            field: "signingAlgorithm",
+            hide: true
+        },
+        {
+            headerName: "Range Slice Block Size",
+            field: "rangeSliceBlockSize",
+            hide: true,
+            filter: "agNumberColumnFilter"
+        },
+        {
+            headerName: "Tenant",
+            field: "tenant",
+            hide: false
+        },
+        {
+            headerName: "Topology",
+            field: "topology",
+            hide: false
+        },
+        {
+            headerName: "TR Request Headers",
+            field: "trRequestHeaders",
+            hide: true
+        },
+        {
+            headerName: "TR Response Headers",
+            field: "trResponseHeaders",
+            hide: true
+        },
+        {
+            headerName: "Type",
+            field: "type",
+            hide: false
+        },
+        {
+            headerName: "XML ID (Key)",
+            field: "xmlId",
+            hide: false
+        }
+    ];
 
-    var dsRequestsEnabled = propertiesModel.properties.dsRequests.enabled;
+    let dsRequestsEnabled = propertiesModel.properties.dsRequests.enabled;
 
-    var showCustomCharts = propertiesModel.properties.deliveryServices.charts.customLink.show;
+    let showCustomCharts = propertiesModel.properties.deliveryServices.charts.customLink.show;
 
     var createDeliveryService = function(typeName) {
         var path = '/delivery-services/new?type=' + typeName;
         locationUtils.navigateToPath(path);
     };
 
-    var clone = function(ds) {
+    $scope.clone = function(ds, event) {
+        event.stopPropagation();
         var params = {
             title: 'Clone Delivery Service: ' + ds.xmlId,
             message: "Please select a content routing category for the clone"
@@ -70,7 +439,8 @@ var TableDeliveryServicesController = function(deliveryServices, $anchorScroll,
         });
     };
 
-    var confirmDelete = function(deliveryService) {
+    $scope.confirmDelete = function(deliveryService, event) {
+        event.stopPropagation();
         var params = {
             title: 'Delete Delivery Service: ' + deliveryService.xmlId,
             key: deliveryService.xmlId
@@ -200,9 +570,23 @@ var TableDeliveryServicesController = function(deliveryServices, $anchorScroll,
         });
     };
 
-    $scope.deliveryServices = deliveryServices;
+    /** All of the delivery services - lastUpdated fields converted to actual Dates */
+    $scope.deliveryServices = deliveryServices.map(
+        function(x) {
+            x.lastUpdated = x.lastUpdated ? new Date(x.lastUpdated.replace("+00", "Z")) : x.lastUpdated;
+        });
+
+    /** The currently selected server - at the moment only used by the context menu */
+    $scope.deliveryService = {
+        xmlId: "",
+        id: -1
+    };
+
+    $scope.quickSearch = '';
+
+    $scope.pageSize = 100;
 
-    $scope.getRelativeTime = dateUtils.getRelativeTime;
+    $scope.mouseDownSelectionText = "";
 
     $scope.navigateToPath = locationUtils.navigateToPath;
 
@@ -212,190 +596,8 @@ var TableDeliveryServicesController = function(deliveryServices, $anchorScroll,
     $scope.PENDING = 3;
     $scope.COMPLETE = 4;
 
-    $scope.columns = [
-        { "name": "Active", "visible": true, "searchable": true },
-        { "name": "Anonymous Blocking", "visible": false, "searchable": false },
-        { "name": "CDN", "visible": true, "searchable": true },
-        { "name": "Check Path", "visible": false, "searchable": false },
-        { "name": "Consistent Hash Query Params", "visible": false, "searchable": false },
-        { "name": "Consistent Hash Regex", "visible": false, "searchable": false },
-        { "name": "Deep Caching Type", "visible": false, "searchable": false },
-        { "name": "Display Name", "visible": true, "searchable": true },
-        { "name": "DNS Bypass CNAME", "visible": false, "searchable": false },
-        { "name": "DNS Bypass IP", "visible": false, "searchable": false },
-        { "name": "DNS Bypass IPv6", "visible": false, "searchable": false },
-        { "name": "DNS Bypass TTL", "visible": false, "searchable": false },
-        { "name": "DNS TTL", "visible": false, "searchable": false },
-        { "name": "DSCP", "visible": true, "searchable": true },
-        { "name": "ECS Enabled", "visible": false, "searchable": false },
-        { "name": "Edge Header Rewrite Rules", "visible": false, "searchable": false },
-        { "name": "First Header Rewrite Rules", "visible": false, "searchable": false },
-        { "name": "FQ Pacing Rate", "visible": false, "searchable": false },
-        { "name": "Geo Limit", "visible": false, "searchable": false },
-        { "name": "Geo Limit Countries", "visible": false, "searchable": false },
-        { "name": "Geo Limit Redirect URL", "visible": false, "searchable": false },
-        { "name": "Geolocation Provider", "visible": false, "searchable": false },
-        { "name": "Geo Miss Latitude", "visible": false, "searchable": false },
-        { "name": "Geo Miss Longitude", "visible": false, "searchable": false },
-        { "name": "Global Max Mbps", "visible": false, "searchable": false },
-        { "name": "Global Max TPS", "visible": false, "searchable": false },
-        { "name": "HTTP Bypass FQDN", "visible": false, "searchable": false },
-        { "name": "ID", "visible": false, "searchable": false },
-        { "name": "Info URL", "visible": true, "searchable": true },
-        { "name": "Initial Dispersion", "visible": false, "searchable": false },
-        { "name": "Inner Header Rewrite Rules", "visible": false, "searchable": false },
-        { "name": "IPv6 Routing", "visible": false, "searchable": false },
-        { "name": "Last Header Rewrite Rules", "visible": false, "searchable": false },
-        { "name": "Last Updated", "visible": false, "searchable": false },
-        { "name": "Long Desc 1", "visible": false, "searchable": false },
-        { "name": "Long Desc 2", "visible": false, "searchable": false },
-        { "name": "Long Desc 3", "visible": false, "searchable": false },
-        { "name": "Max DNS Answers", "visible": false, "searchable": false },
-        { "name": "Max Origin Connections", "visible": false, "searchable": false },
-        { "name": "Max Request Header Bytes", "visible": false, "searchable": false },
-        { "name": "Mid Header Rewrite Rules", "visible": false, "searchable": false },
-        { "name": "Multi-Site Origin", "visible": false, "searchable": false },
-        { "name": "Origin Shield", "visible": false, "searchable": false },
-        { "name": "Origin FQDN", "visible": true, "searchable": true },
-        { "name": "Profile", "visible": true, "searchable": true },
-        { "name": "Protocol", "visible": true, "searchable": true },
-        { "name": "Qstring Handling", "visible": false, "searchable": false },
-        { "name": "Range Request Handling", "visible": false, "searchable": false },
-        { "name": "Regex Remap Expression", "visible": false, "searchable": false },
-        { "name": "Regional Geoblocking", "visible": false, "searchable": false },
-        { "name": "Raw Remap Text", "visible": false, "searchable": false },
-        { "name": "Routing Name", "visible": false, "searchable": false },
-        { "name": "Service Category", "visible": false, "searchable": false },
-        { "name": "Signed", "visible": false, "searchable": false },
-        { "name": "Signing Algorithm", "visible": false, "searchable": false },
-        { "name": "Range Slice Block Size", "visible": false, "searchable": false },
-        { "name": "Tenant", "visible": true, "searchable": true },
-        { "name": "Topology", "visible": true, "searchable": true },
-        { "name": "TR Request Headers", "visible": false, "searchable": false },
-        { "name": "TR Response Headers", "visible": false, "searchable": false },
-        { "name": "Type", "visible": true, "searchable": true },
-        { "name": "XML ID (Key)", "visible": true, "searchable": true }
-    ];
-
-    $scope.contextMenuItems = [
-        {
-            text: 'Open in New Tab',
-            click: function ($itemScope) {
-                $window.open('/#!/delivery-services/' + $itemScope.ds.id + '?type=' + $itemScope.ds.type, '_blank');
-            }
-        },
-        null, // Divider
-        {
-            text: 'Edit',
-            click: function ($itemScope) {
-                $scope.editDeliveryService($itemScope.ds);
-            }
-        },
-        {
-            text: 'Clone',
-            click: function ($itemScope) {
-                clone($itemScope.ds);
-            }
-        },
-        {
-            text: 'Delete',
-            click: function ($itemScope) {
-                confirmDelete($itemScope.ds);
-            }
-        },
-        null, // Divider
-        {
-            text: 'View Charts',
-            click: function ($itemScope, evt) {
-                $scope.viewCharts($itemScope.ds, evt);
-            }
-        },
-        null, // Divider
-        {
-            text: 'Manage SSL Keys',
-            click: function ($itemScope) {
-                locationUtils.navigateToPath('/delivery-services/' + $itemScope.ds.id + '/ssl-keys?type=' + $itemScope.ds.type);
-            }
-        },
-        {
-            text: 'Manage URL Sig Keys',
-            click: function ($itemScope) {
-                locationUtils.navigateToPath('/delivery-services/' + $itemScope.ds.id + '/url-sig-keys?type=' + $itemScope.ds.type);
-            }
-        },
-        {
-            text: 'Manage URI Signing Keys',
-            click: function ($itemScope) {
-                locationUtils.navigateToPath('/delivery-services/' + $itemScope.ds.id + '/uri-signing-keys?type=' + $itemScope.ds.type);
-            }
-        },
-        null, // Divider
-        {
-            text: 'Manage Invalidation Requests',
-            click: function ($itemScope) {
-                locationUtils.navigateToPath('/delivery-services/' + $itemScope.ds.id + '/jobs?type=' + $itemScope.ds.type);
-            }
-        },
-        {
-            text: 'Manage Origins',
-            displayed: function ($itemScope) {
-                // only show for non-steering* delivery services
-                return $itemScope.ds.type.indexOf('STEERING') == -1;
-            },
-            click: function ($itemScope) {
-                locationUtils.navigateToPath('/delivery-services/' + $itemScope.ds.id + '/origins?type=' + $itemScope.ds.type);
-            }
-        },
-        {
-            text: 'Manage Regexes',
-            click: function ($itemScope) {
-                locationUtils.navigateToPath('/delivery-services/' + $itemScope.ds.id + '/regexes?type=' + $itemScope.ds.type);
-            }
-        },
-        {
-            text: 'Manage Required Server Capabilities',
-            displayed: function ($itemScope) {
-                // only show for DNS* or HTTP* delivery services
-                return ($itemScope.ds.type.indexOf('DNS') != -1 || $itemScope.ds.type.indexOf('HTTP') != -1);
-            },
-            click: function ($itemScope) {
-                locationUtils.navigateToPath('/delivery-services/' + $itemScope.ds.id + '/required-server-capabilities?type=' + $itemScope.ds.type);
-            }
-        },
-        {
-            text: 'Manage Servers',
-            click: function ($itemScope) {
-                locationUtils.navigateToPath('/delivery-services/' + $itemScope.ds.id + '/servers?type=' + $itemScope.ds.type);
-            }
-        },
-        {
-            text: 'Manage Targets',
-            displayed: function ($itemScope) {
-                // only show for steering* delivery services
-                return $itemScope.ds.type.indexOf('STEERING') != -1;
-            },
-            click: function ($itemScope) {
-                locationUtils.navigateToPath('/delivery-services/' + $itemScope.ds.id + '/targets?type=' + $itemScope.ds.type);
-            }
-        },
-        {
-            text: 'Manage Static DNS Entries',
-            click: function ($itemScope) {
-                locationUtils.navigateToPath('/delivery-services/' + $itemScope.ds.id + '/static-dns-entries?type=' + $itemScope.ds.type);
-            }
-        }
-    ];
-
-    $scope.editDeliveryService = function(ds) {
-        var path = '/delivery-services/' + ds.id + '?type=' + ds.type;
-        locationUtils.navigateToPath(path);
-    };
-
     $scope.viewCharts = function(ds, $event) {
-        if ($event) {
-            $event.stopPropagation(); // this kills the click event so it doesn't trigger anything else
-        }
-
+        $event.stopPropagation();
         if (showCustomCharts) {
             deliveryServiceUtils.openCharts(ds);
         } else {
@@ -407,26 +609,6 @@ var TableDeliveryServicesController = function(deliveryServices, $anchorScroll,
         $state.reload(); // reloads all the resolves for the view
     };
 
-    $scope.protocol = function(ds) {
-        return protocols[ds.protocol];
-    };
-
-    $scope.qstring = function(ds) {
-        return qstrings[ds.qstringIgnore];
-    };
-
-    $scope.geoProvider = function(ds) {
-        return geoProviders[ds.geoProvider];
-    };
-
-    $scope.geoLimit = function(ds) {
-        return geoLimits[ds.geoLimit];
-    };
-
-    $scope.rrh = function(ds) {
-        return rrhs[ds.rangeRequestHandling];
-    };
-
     $scope.selectDSType = function() {
         var params = {
             title: 'Create Delivery Service',
@@ -485,30 +667,201 @@ var TableDeliveryServicesController = function(deliveryServices, $anchorScroll,
         });
     };
 
-    $scope.toggleVisibility = function(colName) {
-        const col = deliveryServicesTable.column(colName + ':name');
-        col.visible(!col.visible());
-        deliveryServicesTable.rows().invalidate().draw();
+    /** Toggles the visibility of a column that has the ID provided as 'col'. */
+    $scope.toggleVisibility = function(col) {
+        const visible = $scope.gridOptions.columnApi.getColumn(col).isVisible();
+        $scope.gridOptions.columnApi.setColumnVisible(col, !visible);
     };
 
-    angular.element(document).ready(function () {
-        deliveryServicesTable = $('#deliveryServicesTable').DataTable({
-            "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
-            "iDisplayLength": 25,
-            "aaSorting": [],
-            "columns": $scope.columns,
-            "initComplete": function(settings, json) {
+    /** Options, configuration, data and callbacks for the ag-grid table. */
+    $scope.gridOptions = {
+        columnDefs: columns,
+        enableCellTextSelection:true,
+        suppressMenuHide: true,
+        multiSortKey: 'ctrl',
+        alwaysShowVerticalScroll: true,
+        defaultColDef: {
+            filter: true,
+            sortable: true,
+            resizable: true,
+            tooltipValueGetter: defaultTooltip
+        },
+        rowData: deliveryServices,
+        pagination: true,
+        paginationPageSize: $scope.pageSize,
+        rowBuffer: 0,
+        tooltipShowDelay: 500,
+        allowContextMenuWithControlKey: true,
+        preventDefaultOnContextMenu: true,
+        colResizeDefault: "shift",
+        onColumnVisible: function(params) {
+            if (params.visible){
+                return;
+            }
+            const filterModel = $scope.gridOptions.api.getFilterModel();
+            for (let column of params.columns) {
+                if (column.filterActive) {
+                    if (column.colId in filterModel) {
+                        delete filterModel[column.colId];
+                        $scope.gridOptions.api.setFilterModel(filterModel);
+                    }
+                }
+            }
+        },
+        onCellContextMenu: function(params) {
+            $scope.showMenu = true;
+            $scope.menuStyle.left = String(params.event.clientX) + "px";
+            $scope.menuStyle.top = String(params.event.clientY) + "px";
+            $scope.menuStyle.bottom = "unset";
+            $scope.menuStyle.right = "unset";
+            $scope.$apply();
+            const boundingRect = document.getElementById("context-menu").getBoundingClientRect();
+
+            if (boundingRect.bottom > window.innerHeight){
+                $scope.menuStyle.bottom = String(window.innerHeight - params.event.clientY) + "px";
+                $scope.menuStyle.top = "unset";
+            }
+            if (boundingRect.right > window.innerWidth) {
+                $scope.menuStyle.right = String(window.innerWidth - params.event.clientX) + "px";
+                $scope.menuStyle.left = "unset";
+            }
+            $scope.deliveryService = params.data;
+            $scope.$apply();
+        },
+        onCellMouseDown: function() {
+            $scope.mouseDownSelectionText = window.getSelection().toString();
+        },
+        onRowClicked: function(params) {
+            const selection = window.getSelection().toString();
+            if(selection === "" || selection === $scope.mouseDownSelectionText) {
+                locationUtils.navigateToPath('/delivery-services/' + params.data.id + '?type=' + params.data.type);
+                // Event is outside the digest cycle, so we need to trigger one.
+                $scope.$apply();
+            }
+            $scope.mouseDownSelectionText = "";
+        },
+        onColumnResized: function(params) {
+            localStorage.setItem(tableName + "_table_columns", JSON.stringify($scope.gridOptions.columnApi.getColumnState()));
+        },
+        onFirstDataRendered: function(event) {
+            try {
+                const filterState = JSON.parse(localStorage.getItem(tableName + "_table_filters")) || {};
+                // apply any filter provided to the controller
+                Object.assign(filterState, filter);
+                $scope.gridOptions.api.setFilterModel(filterState);
+            } catch (e) {
+                console.error("Failure to load stored filter state:", e);
+            }
+
+            $scope.gridOptions.api.addEventListener("filterChanged", function() {
+                localStorage.setItem(tableName + "_table_filters", JSON.stringify($scope.gridOptions.api.getFilterModel()));
+            });
+        },
+        onGridReady: function() {
+            try { // need to create the show/hide column checkboxes and bind to the current visibility
+                const colstates = JSON.parse(localStorage.getItem(tableName + "_table_columns"));
+                if (colstates) {
+                    if (!$scope.gridOptions.columnApi.setColumnState(colstates)) {
+                        console.error("Failed to load stored column state: one or more columns not found");
+                    }
+                } else {
+                    $scope.gridOptions.api.sizeColumnsToFit();
+                }
+            } catch (e) {
+                console.error("Failure to retrieve required column info from localStorage (key=" + tableName + "_table_columns):", e);
+            }
+
+            try {
+                const sortState = JSON.parse(localStorage.getItem(tableName + "_table_sort"));
+                $scope.gridOptions.api.setSortModel(sortState);
+            } catch (e) {
+                console.error("Failure to load stored sort state:", e);
+            }
+
+            try {
+                $scope.quickSearch = localStorage.getItem(tableName + "_quick_search");
+                $scope.gridOptions.api.setQuickFilter($scope.quickSearch);
+            } catch (e) {
+                console.error("Failure to load stored quick search:", e);
+            }
+
+            try {
+                const ps = localStorage.getItem(tableName + "_page_size");
+                if (ps && ps > 0) {
+                    $scope.pageSize = Number(ps);
+                    $scope.gridOptions.api.paginationSetPageSize($scope.pageSize);
+                }
+            } catch (e) {
+                console.error("Failure to load stored page size:", e);
+            }
+
+            $scope.gridOptions.api.addEventListener("sortChanged", function() {
+                localStorage.setItem(tableName + "_table_sort", JSON.stringify($scope.gridOptions.api.getSortModel()));
+            });
+
+            $scope.gridOptions.api.addEventListener("columnMoved", function() {
+                localStorage.setItem(tableName + "_table_columns", JSON.stringify($scope.gridOptions.columnApi.getColumnState()));
+            });
+
+            $scope.gridOptions.api.addEventListener("columnVisible", function() {
+                $scope.gridOptions.api.sizeColumnsToFit();
                 try {
-                    // need to create the show/hide column checkboxes and bind to the current visibility
-                    $scope.columns = JSON.parse(localStorage.getItem('DataTables_deliveryServicesTable_/')).columns;
+                    const colStates = $scope.gridOptions.columnApi.getColumnState();
+                    localStorage.setItem(tableName + "_table_columns", JSON.stringify(colStates));
                 } catch (e) {
-                    console.error("Failure to retrieve required column info from localStorage (key=DataTables_deliveryServicesTable_/):", e);
+                    console.error("Failed to store column defs to local storage:", e);
                 }
-            }
+            });
+        }
+    };
+
+    /** This is used to position the context menu under the cursor. */
+    $scope.menuStyle = {
+        left: 0,
+        top: 0,
+    };
+
+    /** Controls whether or not the context menu is visible. */
+    $scope.showMenu = false;
+
+    /** Downloads the table as a CSV */
+    $scope.exportCSV = function() {
+        const params = {
+            allColumns: true,
+            fileName: "delivery-services.csv",
+        };
+        $scope.gridOptions.api.exportDataAsCsv(params);
+    };
+
+    $scope.onQuickSearchChanged = function() {
+        $scope.gridOptions.api.setQuickFilter($scope.quickSearch);
+        localStorage.setItem(tableName + "_quick_search", $scope.quickSearch);
+    };
+
+    $scope.onPageSizeChanged = function() {
+        const value = Number($scope.pageSize);
+        $scope.gridOptions.api.paginationSetPageSize(value);
+        localStorage.setItem(tableName + "_page_size", value);
+    };
+
+    $scope.clearTableFilters = function() {
+        // clear the quick search
+        $scope.quickSearch = '';
+        $scope.onQuickSearchChanged();
+        // clear any column filters
+        $scope.gridOptions.api.setFilterModel(null);
+    };
+
+    angular.element(document).ready(function () {
+        // clicks outside the context menu will hide it
+        $document.bind("click", function(e) {
+            $scope.showMenu = false;
+            e.stopPropagation();
+            $scope.$apply();
         });
     });
 
 };
 
-TableDeliveryServicesController.$inject = ['deliveryServices', '$anchorScroll', '$scope', '$state', '$location', '$uibModal', '$window', 'deliveryServiceService', 'deliveryServiceRequestService', 'dateUtils', 'deliveryServiceUtils', 'locationUtils', 'messageModel', 'propertiesModel', 'userModel'];
+TableDeliveryServicesController.$inject = ['tableName', 'deliveryServices', 'filter', '$anchorScroll', '$document', '$scope', '$state', '$location', '$uibModal', 'deliveryServiceService', 'deliveryServiceRequestService', 'dateUtils', 'deliveryServiceUtils', 'locationUtils', 'messageModel', 'propertiesModel', 'userModel'];
 module.exports = TableDeliveryServicesController;
diff --git a/traffic_portal/app/src/common/modules/table/deliveryServices/table.deliveryServices.tpl.html b/traffic_portal/app/src/common/modules/table/deliveryServices/table.deliveryServices.tpl.html
index a4c8586..81aab44 100644
--- a/traffic_portal/app/src/common/modules/table/deliveryServices/table.deliveryServices.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/deliveryServices/table.deliveryServices.tpl.html
@@ -22,170 +22,100 @@ under the License.
         <ol class="breadcrumb pull-left">
             <li class="active">Delivery Services</li>
         </ol>
-        <div class="pull-right" role="group">
-            <button class="btn btn-primary" name="createDeliveryServiceButton" title="Create Delivery Service" ng-click="selectDSType()"><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
-                    <span class="caret"></span>
-                </button>
-                <ul class="dropdown-menu-right dropdown-menu" uib-dropdown-menu>
-                    <li role="menuitem"><a ng-click="compareDSs()">Compare Delivery Services</a></li>
-                </ul>
+        <div class="pull-right">
+            <div class="form-inline" role="search">
+                <input id="quickSearch" name="quickSearch" type="search" class="form-control text-input" placeholder="Quick search..." ng-model="quickSearch" ng-change="onQuickSearchChanged()" aria-label="Search"/>
+                <div class="input-group text-input">
+                    <span class="input-group-addon">
+                        <label for="pageSize">Page size</label>
+                    </span>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                </div>
+                <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 gridOptions.columnApi.getAllColumns() | orderBy:'colDef.headerName'">
+                            <div class="checkbox">
+                                <label><input type="checkbox" ng-checked="c.isVisible()" ng-click="toggleVisibility(c.colId)">{{::c.colDef.headerName}}</label>
+                            </div>
+                        </li>
+                    </menu>
+                </div>
+                <div class="btn-group" role="group" uib-dropdown is-open="more.isopen">
+                    <button name="moreBtn" type="button" class="btn btn-default dropdown-toggle" uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
+                        More&nbsp;
+                        <span class="caret"></span>
+                    </button>
+                    <ul class="dropdown-menu-right dropdown-menu" uib-dropdown-menu>
+                        <li name="createDSMenuItem" role="menuitem"><a ng-click="selectDSType()">Create Delivery Service</a></li>
+                        <li role="menuitem"><a ng-click="compareDSs()">Compare Delivery Services</a></li>
+                        <li class="divider"></li>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="clearTableFilters()">Clear Table Filters</button></li>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="exportCSV()">Export CSV</button></li>
+                    </ul>
+                </div>
             </div>
         </div>
         <div class="clearfix"></div>
     </div>
     <div class="x_content">
-        <br>
-        <table id="deliveryServicesTable" class="table responsive-utilities jambo_table">
-            <thead>
-                <tr class="headings">
-                    <th>Active</th>
-                    <th>Anonymous Blocking</th>
-                    <th>CDN</th>
-                    <th>Check Path</th>
-                    <th>Consistent Hash Query Params</th>
-                    <th>Consistent Hash Regex</th>
-                    <th>Deep Caching Type</th>
-                    <th>Display Name</th>
-                    <th>DNS Bypass CNAME</th>
-                    <th>DNS Bypass IP</th>
-                    <th>DNS Bypass IPv6</th>
-                    <th>DNS Bypass TTL</th>
-                    <th>DNS TTL</th>
-                    <th>DSCP</th>
-                    <th>ECS Enabled</th>
-                    <th>Edge Header Rewrite Rules</th>
-                    <th>First Header Rewrite Rules</th>
-                    <th>FQ Pacing Rate</th>
-                    <th>Geo Limit</th>
-                    <th>Geo Limit Countries</th>
-                    <th>Geo Limit Redirect URL</th>
-                    <th>Geolocation Provider</th>
-                    <th>Geo Miss Latitude</th>
-                    <th>Geo Miss Longitude</th>
-                    <th>Global Max Mbps</th>
-                    <th>Global Max TPS</th>
-                    <th>HTTP Bypass FQDN</th>
-                    <th>ID</th>
-                    <th>Info URL</th>
-                    <th>Initial Dispersion</th>
-                    <th>Inner Header Rewrite Rules</th>
-                    <th>IPv6 Routing</th>
-                    <th>Last Header Rewrite Rules</th>
-                    <th>Last Updated</th>
-                    <th>Long Desc 1</th>
-                    <th>Long Desc 2</th>
-                    <th>Long Desc 3</th>
-                    <th>Max DNS Answers</th>
-                    <th>Max Origin Connections</th>
-                    <th>Max Request Header Bytes</th>
-                    <th>Mid Header Rewrite Rules</th>
-                    <th>Multi-Site Origin</th>
-                    <th>Origin Shield</th>
-                    <th>Origin FQDN</th>
-                    <th>Profile</th>
-                    <th>Protocol</th>
-                    <th>Qstring Handling</th>
-                    <th>Range Request Handling</th>
-                    <th>Regex Remap Expression</th>
-                    <th>Regional Geoblocking</th>
-                    <th>Raw Remap Text</th>
-                    <th>Routing Name</th>
-                    <th>Service Category</th>
-                    <th>Signed</th>
-                    <th>Signing Algorithm</th>
-                    <th>Range Slice Block Size</th>
-                    <th>Tenant</th>
-                    <th>Topology</th>
-                    <th>TR Request Headers</th>
-                    <th>TR Response Headers</th>
-                    <th>Type</th>
-                    <th>XML ID (Key)</th>
-                </tr>
-            </thead>
-            <tbody>
-                <tr ng-click="editDeliveryService(ds)" ng-repeat="ds in ::deliveryServices" context-menu="contextMenuItems">
-                    <td data-search="^{{::ds.active}}$">{{::ds.active}}</td>
-                    <td data-search="^{{::ds.anonymousBlockingEnabled}}$">{{::ds.anonymousBlockingEnabled}}</td>
-                    <td data-search="^{{::ds.cdnName}}$">{{::ds.cdnName}}</td>
-                    <td data-search="^{{::ds.checkPath}}$">{{::ds.checkPath}}</td>
-                    <td data-search="^{{::ds.consistentHashQueryParams}}$">{{::ds.consistentHashQueryParams.join(', ')}}</td>
-                    <td data-search="^{{::ds.consistentHashRegex}}$">{{::ds.consistentHashRegex}}</td>
-                    <td data-search="^{{::ds.deepCachingType}}$">{{::ds.deepCachingType}}</td>
-                    <td data-search="^{{::ds.displayName}}$">{{::ds.displayName}}</td>
-                    <td data-search="^{{::ds.dnsBypassCname}}$">{{::ds.dnsBypassCname}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp}}$">{{::ds.dnsBypassIp}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp6}}$">{{::ds.dnsBypassIp6}}</td>
-                    <td data-search="^{{::ds.dnsBypassTtl}}$">{{::ds.dnsBypassTtl}}</td>
-                    <td data-search="^{{::ds.ccrDnsTtl}}$">{{::ds.ccrDnsTtl}}</td>
-                    <td data-search="^{{::ds.dscp}}$">{{::ds.dscp}}</td>
-                    <td data-search="^{{::ds.ecsEnabled}}$">{{::ds.ecsEnabled}}</td>
-                    <td data-search="^{{::ds.edgeHeaderRewrite}}$">{{::ds.edgeHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.firstHeaderRewrite}}$">{{::ds.firstHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.fqPacingRate}}$">{{::ds.fqPacingRate}}</td>
-                    <td data-search="^{{::geoLimit(ds)}}$">{{::geoLimit(ds)}}</td>
-                    <td data-search="^{{::ds.geoLimitCountries}}$">{{::ds.geoLimitCountries}}</td>
-                    <td data-search="^{{::ds.geoLimitRedirectURL}}$">{{::ds.geoLimitRedirectURL}}</td>
-                    <td data-search="^{{::geoProvider(ds)}}$">{{::geoProvider(ds)}}</td>
-                    <td data-search="^{{::ds.missLat}}$">{{::ds.missLat}}</td>
-                    <td data-search="^{{::ds.missLong}}$">{{::ds.missLong}}</td>
-                    <td data-search="^{{::ds.globalMaxMbps}}$">{{::ds.globalMaxMbps}}</td>
-                    <td data-search="^{{::ds.globalMaxTps}}$">{{::ds.globalMaxTps}}</td>
-                    <td data-search="^{{::ds.httpBypassFqdn}}$">{{::ds.httpBypassFqdn}}</td>
-                    <td data-search="^{{::ds.id}}$">{{::ds.id}}</td>
-                    <td data-search="^{{::ds.infoUrl}}$">{{::ds.infoUrl}}</td>
-                    <td data-search="^{{::ds.initialDispersion}}$">{{::ds.initialDispersion}}</td>
-                    <td data-search="^{{::ds.innerHeaderRewrite}}$">{{::ds.innerHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.ipv6RoutingEnabled}}$">{{::ds.ipv6RoutingEnabled}}</td>
-                    <td data-search="^{{::ds.lastHeaderRewrite}}$">{{::ds.lastHeaderRewrite}}</td>
-                    <td data-search="^{{::getRelativeTime(ds.lastUpdated)}}$" data-order="{{::ds.lastUpdated}}">{{::getRelativeTime(ds.lastUpdated)}}</td>
-                    <td data-search="^{{::ds.longDesc}}$">{{::ds.longDesc}}</td>
-                    <td data-search="^{{::ds.longDesc1}}$">{{::ds.longDesc1}}</td>
-                    <td data-search="^{{::ds.longDesc2}}$">{{::ds.longDesc2}}</td>
-                    <td data-search="^{{::ds.maxDnsAnswers}}$">{{::ds.maxDnsAnswers}}</td>
-                    <td data-search="^{{::ds.maxOriginConnections}}$">{{::ds.maxOriginConnections}}</td>
-                    <td data-search="^{{::ds.maxRequestHeaderBytes}}$">{{::ds.maxRequestHeaderBytes}}</td>
-                    <td data-search="^{{::ds.midHeaderRewrite}}$">{{::ds.midHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.multiSiteOrigin}}$">{{::ds.multiSiteOrigin}}</td>
-                    <td data-search="^{{::ds.originShield}}$">{{::ds.originShield}}</td>
-                    <td data-search="^{{::ds.orgServerFqdn}}$">{{::ds.orgServerFqdn}}</td>
-                    <td data-search="^{{::ds.profileName}}$">{{::ds.profileName}}</td>
-                    <td data-search="^{{::protocol(ds)}}$">{{::protocol(ds)}}</td>
-                    <td data-search="^{{::qstring(ds)}}$">{{::qstring(ds)}}</td>
-                    <td data-search="^{{::rrh(ds)}}$">{{::rrh(ds)}}</td>
-                    <td data-search="^{{::ds.regexRemap}}$">{{::ds.regexRemap}}</td>
-                    <td data-search="^{{::ds.regionalGeoBlocking}}$">{{::ds.regionalGeoBlocking}}</td>
-                    <td data-search="^{{::ds.remapText}}$">{{::ds.remapText}}</td>
-                    <td data-search="^{{::ds.routingName}}$">{{::ds.routingName}}</td>
-                    <td data-search="^{{::ds.serviceCategory}}$">{{::ds.serviceCategory}}</td>
-                    <td data-search="^{{::ds.signed}}$">{{::ds.signed}}</td>
-                    <td data-search="^{{::ds.signingAlgorithm}}$">{{::ds.signingAlgorithm}}</td>
-                    <td data-search="^{{::ds.rangeSliceBlockSize}}$">{{::ds.rangeSliceBlockSize}}</td>
-                    <td data-search="^{{::ds.tenant}}$">{{::ds.tenant}}</td>
-                    <td data-search="^{{::ds.topology}}$">{{::ds.topology}}</td>
-                    <td data-search="^{{::ds.trResponseHeaders}}$">{{::ds.trResponseHeaders}}</td>
-                    <td data-search="^{{::ds.trRequestHeaders}}$">{{::ds.trRequestHeaders}}</td>
-                    <td data-search="^{{::ds.type}}$">{{::ds.type}}</td>
-                    <td name="xmlId" data-search="^{{::ds.xmlId}}$">{{::ds.xmlId}}</td>
-                </tr>
-            </tbody>
-        </table>
+        <div style="height: 740px;" ag-grid="gridOptions" class="ag-theme-alpine"></div>
     </div>
 </div>
 
+<menu id="context-menu" class="dropdown-menu" ng-style="menuStyle" type="contextmenu" ng-show="showMenu">
+    <ul>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}" target="_blank">Open {{ deliveryService.xmlId }} in New Tab</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}">Edit</a>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="clone(deliveryService, $event)">Clone</button>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="confirmDelete(deliveryService, $event)">Delete</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <button type="button" ng-click="viewCharts(deliveryService, $event)">View Charts</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/ssl-keys?type={{deliveryService.type}}">Manage SSL Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/url-sig-keys?type={{deliveryService.type}}">Manage URL Sig Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/uri-signing-keys?type={{deliveryService.type}}">Manage URI Signing Keys</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/jobs?type={{deliveryService.type}}">Manage Invalidation Requests</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') == -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/origins?type={{deliveryService.type}}">Manage Origins</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/regexes?type={{deliveryService.type}}">Manage Regexes</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('DNS') != -1 || deliveryService.type.indexOf('HTTP') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/required-server-capabilities?type={{deliveryService.type}}">Manage Required Server Capabilities</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/servers?type={{deliveryService.type}}">Manage Servers</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/targets?type={{deliveryService.type}}">Manage Targets</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/static-dns-entries?type={{deliveryService.type}}">Manage Static DNS Entries</a>
+        </li>
+    </ul>
+</menu>
diff --git a/traffic_portal/app/src/common/modules/table/jobs/TableJobsController.js b/traffic_portal/app/src/common/modules/table/jobs/TableJobsController.js
index 6cda805..77ed52e 100644
--- a/traffic_portal/app/src/common/modules/table/jobs/TableJobsController.js
+++ b/traffic_portal/app/src/common/modules/table/jobs/TableJobsController.js
@@ -51,7 +51,7 @@ var TableJobsController = function(tableName, jobs, $document, $scope, $state, $
 			field: "startTime",
 			hide: false,
 			filter: "agDateColumnFilter",
-			tooltipValueGetter: () => dateCellFormatter,
+			tooltipValueGetter: dateCellFormatter,
 			valueFormatter: dateCellFormatter
 		},
 		{
@@ -59,7 +59,7 @@ var TableJobsController = function(tableName, jobs, $document, $scope, $state, $
 			field: "expires",
 			hide: false,
 			filter: "agDateColumnFilter",
-			tooltipValueGetter: () => dateCellFormatter,
+			tooltipValueGetter: dateCellFormatter,
 			valueFormatter: dateCellFormatter
 		},
 		{
@@ -95,7 +95,7 @@ var TableJobsController = function(tableName, jobs, $document, $scope, $state, $
 			filter: true,
 			sortable: true,
 			resizable: true,
-			tooltipValueGetter: () => defaultTooltip
+			tooltipValueGetter: defaultTooltip
 		},
 		rowClassRules: {
 			'active-job': function(params) {
diff --git a/traffic_portal/app/src/common/modules/table/jobs/table.jobs.tpl.html b/traffic_portal/app/src/common/modules/table/jobs/table.jobs.tpl.html
index 891a401..7d51c99 100644
--- a/traffic_portal/app/src/common/modules/table/jobs/table.jobs.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/jobs/table.jobs.tpl.html
@@ -29,7 +29,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" />
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" />
                 </div>
                 <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">
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 5cc90c4..ca2c438 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
@@ -31,7 +31,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
                 </div>
                 <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">
diff --git a/traffic_portal/app/src/common/modules/table/profileDeliveryServices/TableProfileDeliveryServicesController.js b/traffic_portal/app/src/common/modules/table/profileDeliveryServices/TableProfileDeliveryServicesController.js
index a4b5408..157b3b6 100644
--- a/traffic_portal/app/src/common/modules/table/profileDeliveryServices/TableProfileDeliveryServicesController.js
+++ b/traffic_portal/app/src/common/modules/table/profileDeliveryServices/TableProfileDeliveryServicesController.js
@@ -17,39 +17,13 @@
  * under the License.
  */
 
-var TableProfileDeliveryServicesController = function(profile, deliveryServices, $controller, $scope) {
+var TableProfileDeliveryServicesController = function(profile, deliveryServices, filter, $controller, $scope) {
 
 	// extends the TableDeliveryServicesController to inherit common methods
-	angular.extend(this, $controller('TableDeliveryServicesController', { deliveryServices: deliveryServices, $scope: $scope }));
-
-	let profileDeliveryServicesTable;
+	angular.extend(this, $controller('TableDeliveryServicesController', { tableName: 'profileDS', deliveryServices: deliveryServices, filter: filter, $scope: $scope }));
 
 	$scope.profile = profile;
-
-	$scope.toggleVisibility = function(colName) {
-		const col = profileDeliveryServicesTable.column(colName + ':name');
-		col.visible(!col.visible());
-		profileDeliveryServicesTable.rows().invalidate().draw();
-	};
-
-	angular.element(document).ready(function () {
-		profileDeliveryServicesTable = $('#profileDeliveryServicesTable').DataTable({
-			"lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
-			"iDisplayLength": 25,
-			"aaSorting": [],
-			"columns": $scope.columns,
-			"initComplete": function(settings, json) {
-				try {
-					// need to create the show/hide column checkboxes and bind to the current visibility
-					$scope.columns = JSON.parse(localStorage.getItem('DataTables_profileDeliveryServicesTable_/')).columns;
-				} catch (e) {
-					console.error("Failure to retrieve required column info from localStorage (key=DataTables_profileDeliveryServicesTable_/):", e);
-				}
-			}
-		});
-	});
-
 };
 
-TableProfileDeliveryServicesController.$inject = ['profile', 'deliveryServices', '$controller', '$scope'];
+TableProfileDeliveryServicesController.$inject = ['profile', 'deliveryServices', 'filter', '$controller', '$scope'];
 module.exports = TableProfileDeliveryServicesController;
diff --git a/traffic_portal/app/src/common/modules/table/profileDeliveryServices/table.profileDeliveryServices.tpl.html b/traffic_portal/app/src/common/modules/table/profileDeliveryServices/table.profileDeliveryServices.tpl.html
index 9383688..92e7f16 100644
--- a/traffic_portal/app/src/common/modules/table/profileDeliveryServices/table.profileDeliveryServices.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/profileDeliveryServices/table.profileDeliveryServices.tpl.html
@@ -20,164 +20,101 @@ under the License.
 <div class="x_panel">
     <div class="x_title">
         <ol class="breadcrumb pull-left">
-            <li><a ng-click="navigateToPath('/profiles')">Profiles</a></li>
-            <li><a ng-click="navigateToPath('/profiles/' + profile.id)">{{::profile.name}}</a></li>
+            <li><a href="#!/profiles">Profiles</a></li>
+            <li><a ng-href="#!/profiles/{{profile.id}}">{{::profile.name}}</a></li>
             <li class="active">Delivery Services</li>
         </ol>
         <div class="pull-right">
-            <button class="btn btn-default" title="Refresh" ng-click="refresh()"><i class="fa fa-refresh"></i></button>
-            <div 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 class="form-inline" role="search">
+                <input id="quickSearch" name="quickSearch" type="search" class="form-control text-input" placeholder="Quick search..." ng-model="quickSearch" ng-change="onQuickSearchChanged()" aria-label="Search"/>
+                <div class="input-group text-input">
+                    <span class="input-group-addon">
+                        <label for="pageSize">Page size</label>
+                    </span>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                </div>
+                <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 gridOptions.columnApi.getAllColumns() | orderBy:'colDef.headerName'">
+                            <div class="checkbox">
+                                <label><input type="checkbox" ng-checked="c.isVisible()" ng-click="toggleVisibility(c.colId)">{{::c.colDef.headerName}}</label>
+                            </div>
+                        </li>
+                    </menu>
+                </div>
+                <div class="btn-group" role="group" uib-dropdown is-open="more.isopen">
+                    <button name="moreBtn" type="button" class="btn btn-default dropdown-toggle" uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
+                        More&nbsp;
+                        <span class="caret"></span>
+                    </button>
+                    <ul class="dropdown-menu-right dropdown-menu" uib-dropdown-menu>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="clearTableFilters()">Clear Table Filters</button></li>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="exportCSV()">Export CSV</button></li>
+                    </ul>
+                </div>
             </div>
         </div>
         <div class="clearfix"></div>
     </div>
     <div class="x_content">
-        <br>
-        <table id="profileDeliveryServicesTable" class="table responsive-utilities jambo_table">
-            <thead>
-                <tr class="headings">
-                    <th>Active</th>
-                    <th>Anonymous Blocking</th>
-                    <th>CDN</th>
-                    <th>Check Path</th>
-                    <th>Consistent Hash Query Params</th>
-                    <th>Consistent Hash Regex</th>
-                    <th>Deep Caching Type</th>
-                    <th>Display Name</th>
-                    <th>DNS Bypass CNAME</th>
-                    <th>DNS Bypass IP</th>
-                    <th>DNS Bypass IPv6</th>
-                    <th>DNS Bypass TTL</th>
-                    <th>DNS TTL</th>
-                    <th>DSCP</th>
-                    <th>ECS Enabled</th>
-                    <th>Edge Header Rewrite Rules</th>
-                    <th>First Header Rewrite Rules</th>
-                    <th>FQ Pacing Rate</th>
-                    <th>Geo Limit</th>
-                    <th>Geo Limit Countries</th>
-                    <th>Geo Limit Redirect URL</th>
-                    <th>Geolocation Provider</th>
-                    <th>Geo Miss Latitude</th>
-                    <th>Geo Miss Longitude</th>
-                    <th>Global Max Mbps</th>
-                    <th>Global Max TPS</th>
-                    <th>HTTP Bypass FQDN</th>
-                    <th>ID</th>
-                    <th>Info URL</th>
-                    <th>Initial Dispersion</th>
-                    <th>Inner Header Rewrite Rules</th>
-                    <th>IPv6 Routing</th>
-                    <th>Last Header Rewrite Rules</th>
-                    <th>Last Updated</th>
-                    <th>Long Desc 1</th>
-                    <th>Long Desc 2</th>
-                    <th>Long Desc 3</th>
-                    <th>Max DNS Answers</th>
-                    <th>Max Origin Connections</th>
-                    <th>Max Request Header Bytes</th>
-                    <th>Mid Header Rewrite Rules</th>
-                    <th>Multi-Site Origin</th>
-                    <th>Origin Shield</th>
-                    <th>Origin FQDN</th>
-                    <th>Profile</th>
-                    <th>Protocol</th>
-                    <th>Qstring Handling</th>
-                    <th>Range Request Handling</th>
-                    <th>Regex Remap Expression</th>
-                    <th>Regional Geoblocking</th>
-                    <th>Raw Remap Text</th>
-                    <th>Routing Name</th>
-                    <th>Service Category</th>
-                    <th>Signed</th>
-                    <th>Signing Algorithm</th>
-                    <th>Range Slice Block Size</th>
-                    <th>Tenant</th>
-                    <th>Topology</th>
-                    <th>TR Request Headers</th>
-                    <th>TR Response Headers</th>
-                    <th>Type</th>
-                    <th>XML ID (Key)</th>
-                </tr>
-            </thead>
-            <tbody>
-                <tr ng-click="editDeliveryService(ds)" ng-repeat="ds in ::deliveryServices" context-menu="contextMenuItems">
-                    <td data-search="^{{::ds.active}}$">{{::ds.active}}</td>
-                    <td data-search="^{{::ds.anonymousBlockingEnabled}}$">{{::ds.anonymousBlockingEnabled}}</td>
-                    <td data-search="^{{::ds.cdnName}}$">{{::ds.cdnName}}</td>
-                    <td data-search="^{{::ds.checkPath}}$">{{::ds.checkPath}}</td>
-                    <td data-search="^{{::ds.consistentHashQueryParams}}$">{{::ds.consistentHashQueryParams.join(', ')}}</td>
-                    <td data-search="^{{::ds.consistentHashRegex}}$">{{::ds.consistentHashRegex}}</td>
-                    <td data-search="^{{::ds.deepCachingType}}$">{{::ds.deepCachingType}}</td>
-                    <td data-search="^{{::ds.displayName}}$">{{::ds.displayName}}</td>
-                    <td data-search="^{{::ds.dnsBypassCname}}$">{{::ds.dnsBypassCname}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp}}$">{{::ds.dnsBypassIp}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp6}}$">{{::ds.dnsBypassIp6}}</td>
-                    <td data-search="^{{::ds.dnsBypassTtl}}$">{{::ds.dnsBypassTtl}}</td>
-                    <td data-search="^{{::ds.ccrDnsTtl}}$">{{::ds.ccrDnsTtl}}</td>
-                    <td data-search="^{{::ds.dscp}}$">{{::ds.dscp}}</td>
-                    <td data-search="^{{::ds.ecsEnabled}}$">{{::ds.ecsEnabled}}</td>
-                    <td data-search="^{{::ds.edgeHeaderRewrite}}$">{{::ds.edgeHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.firstHeaderRewrite}}$">{{::ds.firstHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.fqPacingRate}}$">{{::ds.fqPacingRate}}</td>
-                    <td data-search="^{{::geoLimit(ds)}}$">{{::geoLimit(ds)}}</td>
-                    <td data-search="^{{::ds.geoLimitCountries}}$">{{::ds.geoLimitCountries}}</td>
-                    <td data-search="^{{::ds.geoLimitRedirectURL}}$">{{::ds.geoLimitRedirectURL}}</td>
-                    <td data-search="^{{::geoProvider(ds)}}$">{{::geoProvider(ds)}}</td>
-                    <td data-search="^{{::ds.missLat}}$">{{::ds.missLat}}</td>
-                    <td data-search="^{{::ds.missLong}}$">{{::ds.missLong}}</td>
-                    <td data-search="^{{::ds.globalMaxMbps}}$">{{::ds.globalMaxMbps}}</td>
-                    <td data-search="^{{::ds.globalMaxTps}}$">{{::ds.globalMaxTps}}</td>
-                    <td data-search="^{{::ds.httpBypassFqdn}}$">{{::ds.httpBypassFqdn}}</td>
-                    <td data-search="^{{::ds.id}}$">{{::ds.id}}</td>
-                    <td data-search="^{{::ds.infoUrl}}$">{{::ds.infoUrl}}</td>
-                    <td data-search="^{{::ds.initialDispersion}}$">{{::ds.initialDispersion}}</td>
-                    <td data-search="^{{::ds.innerHeaderRewrite}}$">{{::ds.innerHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.ipv6RoutingEnabled}}$">{{::ds.ipv6RoutingEnabled}}</td>
-                    <td data-search="^{{::ds.lastHeaderRewrite}}$">{{::ds.lastHeaderRewrite}}</td>
-                    <td data-search="^{{::getRelativeTime(ds.lastUpdated)}}$" data-order="{{::ds.lastUpdated}}">{{::getRelativeTime(ds.lastUpdated)}}</td>
-                    <td data-search="^{{::ds.longDesc}}$">{{::ds.longDesc}}</td>
-                    <td data-search="^{{::ds.longDesc1}}$">{{::ds.longDesc1}}</td>
-                    <td data-search="^{{::ds.longDesc2}}$">{{::ds.longDesc2}}</td>
-                    <td data-search="^{{::ds.maxDnsAnswers}}$">{{::ds.maxDnsAnswers}}</td>
-                    <td data-search="^{{::ds.maxOriginConnections}}$">{{::ds.maxOriginConnections}}</td>
-                    <td data-search="^{{::ds.maxRequestHeaderBytes}}$">{{::ds.maxRequestHeaderBytes}}</td>
-                    <td data-search="^{{::ds.midHeaderRewrite}}$">{{::ds.midHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.multiSiteOrigin}}$">{{::ds.multiSiteOrigin}}</td>
-                    <td data-search="^{{::ds.originShield}}$">{{::ds.originShield}}</td>
-                    <td data-search="^{{::ds.orgServerFqdn}}$">{{::ds.orgServerFqdn}}</td>
-                    <td data-search="^{{::ds.profileName}}$">{{::ds.profileName}}</td>
-                    <td data-search="^{{::protocol(ds)}}$">{{::protocol(ds)}}</td>
-                    <td data-search="^{{::qstring(ds)}}$">{{::qstring(ds)}}</td>
-                    <td data-search="^{{::rrh(ds)}}$">{{::rrh(ds)}}</td>
-                    <td data-search="^{{::ds.regexRemap}}$">{{::ds.regexRemap}}</td>
-                    <td data-search="^{{::ds.regionalGeoBlocking}}$">{{::ds.regionalGeoBlocking}}</td>
-                    <td data-search="^{{::ds.remapText}}$">{{::ds.remapText}}</td>
-                    <td data-search="^{{::ds.routingName}}$">{{::ds.routingName}}</td>
-                    <td data-search="^{{::ds.serviceCategory}}$">{{::ds.serviceCategory}}</td>
-                    <td data-search="^{{::ds.signed}}$">{{::ds.signed}}</td>
-                    <td data-search="^{{::ds.signingAlgorithm}}$">{{::ds.signingAlgorithm}}</td>
-                    <td data-search="^{{::ds.rangeSliceBlockSize}}$">{{::ds.rangeSliceBlockSize}}</td>
-                    <td data-search="^{{::ds.tenant}}$">{{::ds.tenant}}</td>
-                    <td data-search="^{{::ds.topology}}$">{{::ds.topology}}</td>
-                    <td data-search="^{{::ds.trResponseHeaders}}$">{{::ds.trResponseHeaders}}</td>
-                    <td data-search="^{{::ds.trRequestHeaders}}$">{{::ds.trRequestHeaders}}</td>
-                    <td data-search="^{{::ds.type}}$">{{::ds.type}}</td>
-                    <td name="xmlId" data-search="^{{::ds.xmlId}}$">{{::ds.xmlId}}</td>
-                </tr>
-            </tbody>
-        </table>
+        <div style="height: 740px;" ag-grid="gridOptions" class="ag-theme-alpine"></div>
     </div>
 </div>
 
+<menu id="context-menu" class="dropdown-menu" ng-style="menuStyle" type="contextmenu" ng-show="showMenu">
+    <ul>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}" target="_blank">Open {{ deliveryService.xmlId }} in New Tab</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}">Edit</a>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="clone(deliveryService, $event)">Clone</button>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="confirmDelete(deliveryService, $event)">Delete</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <button type="button" ng-click="viewCharts(deliveryService, $event)">View Charts</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/ssl-keys?type={{deliveryService.type}}">Manage SSL Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/url-sig-keys?type={{deliveryService.type}}">Manage URL Sig Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/uri-signing-keys?type={{deliveryService.type}}">Manage URI Signing Keys</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/jobs?type={{deliveryService.type}}">Manage Invalidation Requests</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') == -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/origins?type={{deliveryService.type}}">Manage Origins</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/regexes?type={{deliveryService.type}}">Manage Regexes</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('DNS') != -1 || deliveryService.type.indexOf('HTTP') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/required-server-capabilities?type={{deliveryService.type}}">Manage Required Server Capabilities</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/servers?type={{deliveryService.type}}">Manage Servers</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/targets?type={{deliveryService.type}}">Manage Targets</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/static-dns-entries?type={{deliveryService.type}}">Manage Static DNS Entries</a>
+        </li>
+    </ul>
+</menu>
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 2974d3b..f0924db 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
@@ -31,7 +31,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
                 </div>
                 <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">
diff --git a/traffic_portal/app/src/common/modules/table/serverDeliveryServices/TableServerDeliveryServicesController.js b/traffic_portal/app/src/common/modules/table/serverDeliveryServices/TableServerDeliveryServicesController.js
index 0d0fc90..98f0e78 100644
--- a/traffic_portal/app/src/common/modules/table/serverDeliveryServices/TableServerDeliveryServicesController.js
+++ b/traffic_portal/app/src/common/modules/table/serverDeliveryServices/TableServerDeliveryServicesController.js
@@ -17,12 +17,10 @@
  * under the License.
  */
 
-var TableServerDeliveryServicesController = function(server, deliveryServices, $controller, $scope, $state, $uibModal, dateUtils, deliveryServiceUtils, locationUtils, serverUtils, deliveryServiceService, serverService) {
+var TableServerDeliveryServicesController = function(server, deliveryServices, filter, $controller, $scope, $state, $uibModal, dateUtils, deliveryServiceUtils, locationUtils, serverUtils, deliveryServiceService, serverService) {
 
 	// extends the TableDeliveryServicesController to inherit common methods
-	angular.extend(this, $controller('TableDeliveryServicesController', { deliveryServices: deliveryServices, $scope: $scope }));
-
-	let serverDeliveryServicesTable;
+	angular.extend(this, $controller('TableDeliveryServicesController', { tableName: 'serverDS', deliveryServices: deliveryServices, filter: filter, $scope: $scope }));
 
 	var removeDeliveryService = function(dsId) {
 		deliveryServiceService.deleteDeliveryServiceServer(dsId, $scope.server.id)
@@ -35,28 +33,12 @@ var TableServerDeliveryServicesController = function(server, deliveryServices, $
 
 	$scope.server = server[0];
 
-	// adds some items to the base delivery services context menu
-	$scope.contextMenuItems.splice(2, 0,
-		{
-			text: 'Unlink Delivery Service from Server',
-			hasBottomDivider: function() {
-				return true;
-			},
-			click: function ($itemScope) {
-				$scope.confirmRemoveDS($itemScope.ds);
-			}
-		}
-	);
-
 	$scope.isEdge = serverUtils.isEdge;
 
 	$scope.isOrigin = serverUtils.isOrigin;
 
-	$scope.confirmRemoveDS = function(ds, $event) {
-		if ($event) {
-			$event.stopPropagation(); // this kills the click event so it doesn't trigger anything else
-		}
-
+	$scope.confirmRemoveDS = function(ds, event) {
+		event.stopPropagation();
 		var params = {
 			title: 'Remove Delivery Service from Server?',
 			message: 'Are you sure you want to remove ' + ds.xmlId + ' from this server?'
@@ -142,40 +124,7 @@ var TableServerDeliveryServicesController = function(server, deliveryServices, $
 		});
 	};
 
-	$scope.toggleVisibility = function(colName) {
-		const col = serverDeliveryServicesTable.column(colName + ':name');
-		col.visible(!col.visible());
-		serverDeliveryServicesTable.rows().invalidate().draw();
-	};
-
-	$scope.columnFilterFn = function(column) {
-		if (column.name === 'Action') {
-			return false;
-		}
-		return true;
-	};
-
-	angular.element(document).ready(function () {
-		serverDeliveryServicesTable = $('#serverDeliveryServicesTable').DataTable({
-			"lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
-			"iDisplayLength": 25,
-			"aaSorting": [],
-			"columnDefs": [
-				{ 'orderable': false, 'targets': 55 }
-			],
-			"columns": $scope.columns.concat([{ "name": "Action", "visible": true, "searchable": 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_serverDeliveryServicesTable_/')).columns;
-				} catch (e) {
-					console.error("Failure to retrieve required column info from localStorage (key=DataTables_serverDeliveryServicesTable_/):", e);
-				}
-			}
-		});
-	});
-
 };
 
-TableServerDeliveryServicesController.$inject = ['server', 'deliveryServices', '$controller', '$scope', '$state', '$uibModal', 'dateUtils', 'deliveryServiceUtils', 'locationUtils', 'serverUtils', 'deliveryServiceService', 'serverService'];
+TableServerDeliveryServicesController.$inject = ['server', 'deliveryServices', 'filter', '$controller', '$scope', '$state', '$uibModal', 'dateUtils', 'deliveryServiceUtils', 'locationUtils', 'serverUtils', 'deliveryServiceService', 'serverService'];
 module.exports = TableServerDeliveryServicesController;
diff --git a/traffic_portal/app/src/common/modules/table/serverDeliveryServices/table.serverDeliveryServices.tpl.html b/traffic_portal/app/src/common/modules/table/serverDeliveryServices/table.serverDeliveryServices.tpl.html
index 9336d92..4164b6b 100644
--- a/traffic_portal/app/src/common/modules/table/serverDeliveryServices/table.serverDeliveryServices.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/serverDeliveryServices/table.serverDeliveryServices.tpl.html
@@ -20,178 +20,108 @@ under the License.
 <div class="x_panel">
     <div class="x_title">
         <ol class="breadcrumb pull-left">
-            <li><a ng-click="navigateToPath('/servers')">Servers</a></li>
-            <li><a ng-click="navigateToPath('/servers/' + server.id)">{{::server.hostName}}</a></li>
+            <li><a href="#!/servers">Servers</a></li>
+            <li><a ng-href="#!/servers/{{server.id}}">{{::server.hostName}}</a></li>
             <li class="active">Delivery Services</li>
         </ol>
-        <div class="pull-right" role="group">
-            <button class="btn btn-primary" title="Link Delivery Services to Server" ng-show="isEdge(server) || isOrigin(server)" ng-click="selectDeliveryServices()"><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 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' | filter:columnFilterFn">
-                        <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" ng-show="isEdge(server) || isOrigin(server)" uib-dropdown is-open="more.isopen">
-                <button ng-if="isEdge(server) && deliveryServices.length > 0" name="moreBtn" type="button" class="btn btn-default dropdown-toggle" uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
-                    More&nbsp;
-                    <span class="caret"></span>
-                </button>
-                <ul class="dropdown-menu-right dropdown-menu" uib-dropdown-menu>
-                    <li><a class="clone-ds-assignments" ng-click="cloneDsAssignments()">Clone Delivery Service Assignments</a></li>
-                </ul>
+        <div class="pull-right">
+            <div class="form-inline" role="search">
+                <input id="quickSearch" name="quickSearch" type="search" class="form-control text-input" placeholder="Quick search..." ng-model="quickSearch" ng-change="onQuickSearchChanged()" aria-label="Search"/>
+                <div class="input-group text-input">
+                    <span class="input-group-addon">
+                        <label for="pageSize">Page size</label>
+                    </span>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                </div>
+                <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 gridOptions.columnApi.getAllColumns() | orderBy:'colDef.headerName'">
+                            <div class="checkbox">
+                                <label><input type="checkbox" ng-checked="c.isVisible()" ng-click="toggleVisibility(c.colId)">{{::c.colDef.headerName}}</label>
+                            </div>
+                        </li>
+                    </menu>
+                </div>
+                <div class="btn-group" role="group" uib-dropdown is-open="more.isopen">
+                    <button name="moreBtn" type="button" class="btn btn-default dropdown-toggle" uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
+                        More&nbsp;
+                        <span class="caret"></span>
+                    </button>
+                    <ul class="dropdown-menu-right dropdown-menu" uib-dropdown-menu>
+                        <li role="menuitem" ng-show="isEdge(server) || isOrigin(server)"><button class="menu-item-button clone-ds-assignments" type="button" ng-click="selectDeliveryServices()">Assign Delivery Services</button></li>
+                        <li role="menuitem"><button class="menu-item-button clone-ds-assignments" type="button" ng-click="cloneDsAssignments()">Clone Delivery Service Assignments</button></li>
+                        <li class="divider"></li>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="clearTableFilters()">Clear Table Filters</button></li>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="exportCSV()">Export CSV</button></li>
+                    </ul>
+                </div>
             </div>
         </div>
         <div class="clearfix"></div>
     </div>
     <div class="x_content">
-        <br>
-        <table id="serverDeliveryServicesTable" class="table responsive-utilities jambo_table">
-            <thead>
-                <tr class="headings">
-                    <th>Active</th>
-                    <th>Anonymous Blocking</th>
-                    <th>CDN</th>
-                    <th>Check Path</th>
-                    <th>Consistent Hash Query Params</th>
-                    <th>Consistent Hash Regex</th>
-                    <th>Deep Caching Type</th>
-                    <th>Display Name</th>
-                    <th>DNS Bypass CNAME</th>
-                    <th>DNS Bypass IP</th>
-                    <th>DNS Bypass IPv6</th>
-                    <th>DNS Bypass TTL</th>
-                    <th>DNS TTL</th>
-                    <th>DSCP</th>
-                    <th>ECS Enabled</th>
-                    <th>Edge Header Rewrite Rules</th>
-                    <th>First Header Rewrite Rules</th>
-                    <th>FQ Pacing Rate</th>
-                    <th>Geo Limit</th>
-                    <th>Geo Limit Countries</th>
-                    <th>Geo Limit Redirect URL</th>
-                    <th>Geolocation Provider</th>
-                    <th>Geo Miss Latitude</th>
-                    <th>Geo Miss Longitude</th>
-                    <th>Global Max Mbps</th>
-                    <th>Global Max TPS</th>
-                    <th>HTTP Bypass FQDN</th>
-                    <th>ID</th>
-                    <th>Info URL</th>
-                    <th>Initial Dispersion</th>
-                    <th>Inner Header Rewrite Rules</th>
-                    <th>IPv6 Routing</th>
-                    <th>Last Header Rewrite Rules</th>
-                    <th>Last Updated</th>
-                    <th>Long Desc 1</th>
-                    <th>Long Desc 2</th>
-                    <th>Long Desc 3</th>
-                    <th>Max DNS Answers</th>
-                    <th>Max Origin Connections</th>
-                    <th>Max Request Header Bytes</th>
-                    <th>Mid Header Rewrite Rules</th>
-                    <th>Multi-Site Origin</th>
-                    <th>Origin Shield</th>
-                    <th>Origin FQDN</th>
-                    <th>Profile</th>
-                    <th>Protocol</th>
-                    <th>Qstring Handling</th>
-                    <th>Range Request Handling</th>
-                    <th>Regex Remap Expression</th>
-                    <th>Regional Geoblocking</th>
-                    <th>Raw Remap Text</th>
-                    <th>Routing Name</th>
-                    <th>Service Category</th>
-                    <th>Signed</th>
-                    <th>Signing Algorithm</th>
-                    <th>Range Slice Block Size</th>
-                    <th>Tenant</th>
-                    <th>Topology</th>
-                    <th>TR Request Headers</th>
-                    <th>TR Response Headers</th>
-                    <th>Type</th>
-                    <th>XML ID (Key)</th>
-                    <th>Action</th>
-                </tr>
-            </thead>
-            <tbody>
-                <tr ng-click="editDeliveryService(ds)" ng-repeat="ds in ::deliveryServices" context-menu="contextMenuItems">
-                    <td data-search="^{{::ds.active}}$">{{::ds.active}}</td>
-                    <td data-search="^{{::ds.anonymousBlockingEnabled}}$">{{::ds.anonymousBlockingEnabled}}</td>
-                    <td data-search="^{{::ds.cdnName}}$">{{::ds.cdnName}}</td>
-                    <td data-search="^{{::ds.checkPath}}$">{{::ds.checkPath}}</td>
-                    <td data-search="^{{::ds.consistentHashQueryParams}}$">{{::ds.consistentHashQueryParams.join(', ')}}</td>
-                    <td data-search="^{{::ds.consistentHashRegex}}$">{{::ds.consistentHashRegex}}</td>
-                    <td data-search="^{{::ds.deepCachingType}}$">{{::ds.deepCachingType}}</td>
-                    <td data-search="^{{::ds.displayName}}$">{{::ds.displayName}}</td>
-                    <td data-search="^{{::ds.dnsBypassCname}}$">{{::ds.dnsBypassCname}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp}}$">{{::ds.dnsBypassIp}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp6}}$">{{::ds.dnsBypassIp6}}</td>
-                    <td data-search="^{{::ds.dnsBypassTtl}}$">{{::ds.dnsBypassTtl}}</td>
-                    <td data-search="^{{::ds.ccrDnsTtl}}$">{{::ds.ccrDnsTtl}}</td>
-                    <td data-search="^{{::ds.dscp}}$">{{::ds.dscp}}</td>
-                    <td data-search="^{{::ds.ecsEnabled}}$">{{::ds.ecsEnabled}}</td>
-                    <td data-search="^{{::ds.edgeHeaderRewrite}}$">{{::ds.edgeHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.firstHeaderRewrite}}$">{{::ds.firstHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.fqPacingRate}}$">{{::ds.fqPacingRate}}</td>
-                    <td data-search="^{{::geoLimit(ds)}}$">{{::geoLimit(ds)}}</td>
-                    <td data-search="^{{::ds.geoLimitCountries}}$">{{::ds.geoLimitCountries}}</td>
-                    <td data-search="^{{::ds.geoLimitRedirectURL}}$">{{::ds.geoLimitRedirectURL}}</td>
-                    <td data-search="^{{::geoProvider(ds)}}$">{{::geoProvider(ds)}}</td>
-                    <td data-search="^{{::ds.missLat}}$">{{::ds.missLat}}</td>
-                    <td data-search="^{{::ds.missLong}}$">{{::ds.missLong}}</td>
-                    <td data-search="^{{::ds.globalMaxMbps}}$">{{::ds.globalMaxMbps}}</td>
-                    <td data-search="^{{::ds.globalMaxTps}}$">{{::ds.globalMaxTps}}</td>
-                    <td data-search="^{{::ds.httpBypassFqdn}}$">{{::ds.httpBypassFqdn}}</td>
-                    <td data-search="^{{::ds.id}}$">{{::ds.id}}</td>
-                    <td data-search="^{{::ds.infoUrl}}$">{{::ds.infoUrl}}</td>
-                    <td data-search="^{{::ds.initialDispersion}}$">{{::ds.initialDispersion}}</td>
-                    <td data-search="^{{::ds.innerHeaderRewrite}}$">{{::ds.innerHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.ipv6RoutingEnabled}}$">{{::ds.ipv6RoutingEnabled}}</td>
-                    <td data-search="^{{::ds.lastHeaderRewrite}}$">{{::ds.lastHeaderRewrite}}</td>
-                    <td data-search="^{{::getRelativeTime(ds.lastUpdated)}}$" data-order="{{::ds.lastUpdated}}">{{::getRelativeTime(ds.lastUpdated)}}</td>
-                    <td data-search="^{{::ds.longDesc}}$">{{::ds.longDesc}}</td>
-                    <td data-search="^{{::ds.longDesc1}}$">{{::ds.longDesc1}}</td>
-                    <td data-search="^{{::ds.longDesc2}}$">{{::ds.longDesc2}}</td>
-                    <td data-search="^{{::ds.maxDnsAnswers}}$">{{::ds.maxDnsAnswers}}</td>
-                    <td data-search="^{{::ds.maxOriginConnections}}$">{{::ds.maxOriginConnections}}</td>
-                    <td data-search="^{{::ds.maxRequestHeaderBytes}}$">{{::ds.maxRequestHeaderBytes}}</td>
-                    <td data-search="^{{::ds.midHeaderRewrite}}$">{{::ds.midHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.multiSiteOrigin}}$">{{::ds.multiSiteOrigin}}</td>
-                    <td data-search="^{{::ds.originShield}}$">{{::ds.originShield}}</td>
-                    <td data-search="^{{::ds.orgServerFqdn}}$">{{::ds.orgServerFqdn}}</td>
-                    <td data-search="^{{::ds.profileName}}$">{{::ds.profileName}}</td>
-                    <td data-search="^{{::protocol(ds)}}$">{{::protocol(ds)}}</td>
-                    <td data-search="^{{::qstring(ds)}}$">{{::qstring(ds)}}</td>
-                    <td data-search="^{{::rrh(ds)}}$">{{::rrh(ds)}}</td>
-                    <td data-search="^{{::ds.regexRemap}}$">{{::ds.regexRemap}}</td>
-                    <td data-search="^{{::ds.regionalGeoBlocking}}$">{{::ds.regionalGeoBlocking}}</td>
-                    <td data-search="^{{::ds.remapText}}$">{{::ds.remapText}}</td>
-                    <td data-search="^{{::ds.routingName}}$">{{::ds.routingName}}</td>
-                    <td data-search="^{{::ds.serviceCategory}}$">{{::ds.serviceCategory}}</td>
-                    <td data-search="^{{::ds.signed}}$">{{::ds.signed}}</td>
-                    <td data-search="^{{::ds.signingAlgorithm}}$">{{::ds.signingAlgorithm}}</td>
-                    <td data-search="^{{::ds.rangeSliceBlockSize}}$">{{::ds.rangeSliceBlockSize}}</td>
-                    <td data-search="^{{::ds.tenant}}$">{{::ds.tenant}}</td>
-                    <td data-search="^{{::ds.topology}}$">{{::ds.topology}}</td>
-                    <td data-search="^{{::ds.trResponseHeaders}}$">{{::ds.trResponseHeaders}}</td>
-                    <td data-search="^{{::ds.trRequestHeaders}}$">{{::ds.trRequestHeaders}}</td>
-                    <td data-search="^{{::ds.type}}$">{{::ds.type}}</td>
-                    <td name="xmlId" data-search="^{{::ds.xmlId}}$">{{::ds.xmlId}}</td>
-                    <td style="text-align: right;">
-                        <a class="link action-link" title="Unlink Delivery Service from Server" ng-click="confirmRemoveDS(ds, $event)"><i class="fa fa-sm fa-chain-broken"></i></a>
-                    </td>
-                </tr>
-            </tbody>
-        </table>
+        <div style="height: 740px;" ag-grid="gridOptions" class="ag-theme-alpine"></div>
     </div>
 </div>
 
+<menu id="context-menu" class="dropdown-menu" ng-style="menuStyle" type="contextmenu" ng-show="showMenu">
+    <ul>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}" target="_blank">Open {{ deliveryService.xmlId }} in New Tab</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <button type="button" ng-click="confirmRemoveDS(deliveryService, $event)">Remove {{deliveryService.xmlId}}</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}">Edit</a>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="clone(deliveryService, $event)">Clone</button>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="confirmDelete(deliveryService, $event)">Delete</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <button type="button" ng-click="viewCharts(deliveryService, $event)">View Charts</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/ssl-keys?type={{deliveryService.type}}">Manage SSL Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/url-sig-keys?type={{deliveryService.type}}">Manage URL Sig Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/uri-signing-keys?type={{deliveryService.type}}">Manage URI Signing Keys</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/jobs?type={{deliveryService.type}}">Manage Invalidation Requests</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') == -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/origins?type={{deliveryService.type}}">Manage Origins</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/regexes?type={{deliveryService.type}}">Manage Regexes</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('DNS') != -1 || deliveryService.type.indexOf('HTTP') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/required-server-capabilities?type={{deliveryService.type}}">Manage Required Server Capabilities</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/servers?type={{deliveryService.type}}">Manage Servers</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/targets?type={{deliveryService.type}}">Manage Targets</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/static-dns-entries?type={{deliveryService.type}}">Manage Static DNS Entries</a>
+        </li>
+    </ul>
+</menu>
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 f642167..b7c2404 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
@@ -29,7 +29,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
                 </div>
                 <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">
diff --git a/traffic_portal/app/src/common/modules/table/serviceCategoryDeliveryServices/TableServiceCategoryDeliveryServicesController.js b/traffic_portal/app/src/common/modules/table/serviceCategoryDeliveryServices/TableServiceCategoryDeliveryServicesController.js
index 9d1e181..cb70a7d 100644
--- a/traffic_portal/app/src/common/modules/table/serviceCategoryDeliveryServices/TableServiceCategoryDeliveryServicesController.js
+++ b/traffic_portal/app/src/common/modules/table/serviceCategoryDeliveryServices/TableServiceCategoryDeliveryServicesController.js
@@ -17,39 +17,13 @@
  * under the License.
  */
 
-var TableServiceCategoryDeliveryServicesController = function(serviceCategory, deliveryServices, $controller, $scope) {
+var TableServiceCategoryDeliveryServicesController = function(serviceCategory, deliveryServices, filter, $controller, $scope) {
 
 	// extends the TableDeliveryServicesController to inherit common methods
-	angular.extend(this, $controller('TableDeliveryServicesController', { deliveryServices: deliveryServices, $scope: $scope }));
-
-	let serviceCategoryDSsTable;
+	angular.extend(this, $controller('TableDeliveryServicesController', { tableName: 'scDS', deliveryServices: deliveryServices, filter: filter, $scope: $scope }));
 
 	$scope.serviceCategory = serviceCategory;
-
-	$scope.toggleVisibility = function(colName) {
-		const col = serviceCategoryDSsTable.column(colName + ':name');
-		col.visible(!col.visible());
-		serviceCategoryDSsTable.rows().invalidate().draw();
-	};
-
-	angular.element(document).ready(function () {
-		serviceCategoryDSsTable = $('#serviceCategoryDSsTable').DataTable({
-			"lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
-			"iDisplayLength": 25,
-			"aaSorting": [],
-			"columns": $scope.columns,
-			"initComplete": function(settings, json) {
-				try {
-					// need to create the show/hide column checkboxes and bind to the current visibility
-					$scope.columns = JSON.parse(localStorage.getItem('DataTables_serviceCategoryDSsTable_/')).columns;
-				} catch (e) {
-					console.error("Failure to retrieve required column info from localStorage (key=DataTables_serviceCategoryDSsTable_/):", e);
-				}
-			}
-		});
-	});
-
 };
 
-TableServiceCategoryDeliveryServicesController.$inject = ['serviceCategory', 'deliveryServices', '$controller', '$scope'];
+TableServiceCategoryDeliveryServicesController.$inject = ['serviceCategory', 'deliveryServices', 'filter', '$controller', '$scope'];
 module.exports = TableServiceCategoryDeliveryServicesController;
diff --git a/traffic_portal/app/src/common/modules/table/serviceCategoryDeliveryServices/table.serviceCategoryDeliveryServices.tpl.html b/traffic_portal/app/src/common/modules/table/serviceCategoryDeliveryServices/table.serviceCategoryDeliveryServices.tpl.html
index 77a5a05..5623bd2 100644
--- a/traffic_portal/app/src/common/modules/table/serviceCategoryDeliveryServices/table.serviceCategoryDeliveryServices.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/serviceCategoryDeliveryServices/table.serviceCategoryDeliveryServices.tpl.html
@@ -20,164 +20,103 @@ under the License.
 <div class="x_panel">
     <div class="x_title">
         <ol class="breadcrumb pull-left">
-            <li><a ng-click="navigateToPath('/service-categories')">Service Categories</a></li>
-            <li><a ng-click="navigateToPath('/service-categories/edit?name=' + serviceCategory.name)">{{serviceCategory.name}}</a></li>
+            <li><a href="#!/service-categories">Service Categories</a></li>
+            <li><a ng-href="#!/service-categories/edit?name={{serviceCategory.name}}">{{::serviceCategory.name}}</a></li>
             <li class="active">Delivery Services</li>
         </ol>
         <div class="pull-right">
-            <button class="btn btn-default" title="Refresh" ng-click="refresh()"><i class="fa fa-refresh"></i></button>
-            <div 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 class="form-inline" role="search">
+                <input id="quickSearch" name="quickSearch" type="search" class="form-control text-input" placeholder="Quick search..." ng-model="quickSearch" ng-change="onQuickSearchChanged()" aria-label="Search"/>
+                <div class="input-group text-input">
+                    <span class="input-group-addon">
+                        <label for="pageSize">Page size</label>
+                    </span>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                </div>
+                <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 gridOptions.columnApi.getAllColumns() | orderBy:'colDef.headerName'">
+                            <div class="checkbox">
+                                <label><input type="checkbox" ng-checked="c.isVisible()" ng-click="toggleVisibility(c.colId)">{{::c.colDef.headerName}}</label>
+                            </div>
+                        </li>
+                    </menu>
+                </div>
+                <div class="btn-group" role="group" uib-dropdown is-open="more.isopen">
+                    <button name="moreBtn" type="button" class="btn btn-default dropdown-toggle" uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
+                        More&nbsp;
+                        <span class="caret"></span>
+                    </button>
+                    <ul class="dropdown-menu-right dropdown-menu" uib-dropdown-menu>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="clearTableFilters()">Clear Table Filters</button></li>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="exportCSV()">Export CSV</button></li>
+                    </ul>
+                </div>
             </div>
         </div>
         <div class="clearfix"></div>
     </div>
     <div class="x_content">
-        <br>
-        <table id="serviceCategoryDSsTable" class="table responsive-utilities jambo_table">
-            <thead>
-                <tr class="headings">
-                    <th>Active</th>
-                    <th>Anonymous Blocking</th>
-                    <th>CDN</th>
-                    <th>Check Path</th>
-                    <th>Consistent Hash Query Params</th>
-                    <th>Consistent Hash Regex</th>
-                    <th>Deep Caching Type</th>
-                    <th>Display Name</th>
-                    <th>DNS Bypass CNAME</th>
-                    <th>DNS Bypass IP</th>
-                    <th>DNS Bypass IPv6</th>
-                    <th>DNS Bypass TTL</th>
-                    <th>DNS TTL</th>
-                    <th>DSCP</th>
-                    <th>ECS Enabled</th>
-                    <th>Edge Header Rewrite Rules</th>
-                    <th>First Header Rewrite Rules</th>
-                    <th>FQ Pacing Rate</th>
-                    <th>Geo Limit</th>
-                    <th>Geo Limit Countries</th>
-                    <th>Geo Limit Redirect URL</th>
-                    <th>Geolocation Provider</th>
-                    <th>Geo Miss Latitude</th>
-                    <th>Geo Miss Longitude</th>
-                    <th>Global Max Mbps</th>
-                    <th>Global Max TPS</th>
-                    <th>HTTP Bypass FQDN</th>
-                    <th>ID</th>
-                    <th>Info URL</th>
-                    <th>Initial Dispersion</th>
-                    <th>Inner Header Rewrite Rules</th>
-                    <th>IPv6 Routing</th>
-                    <th>Last Header Rewrite Rules</th>
-                    <th>Last Updated</th>
-                    <th>Long Desc 1</th>
-                    <th>Long Desc 2</th>
-                    <th>Long Desc 3</th>
-                    <th>Max DNS Answers</th>
-                    <th>Max Origin Connections</th>
-                    <th>Max Request Header Bytes</th>
-                    <th>Mid Header Rewrite Rules</th>
-                    <th>Multi-Site Origin</th>
-                    <th>Origin Shield</th>
-                    <th>Origin FQDN</th>
-                    <th>Profile</th>
-                    <th>Protocol</th>
-                    <th>Qstring Handling</th>
-                    <th>Range Request Handling</th>
-                    <th>Regex Remap Expression</th>
-                    <th>Regional Geoblocking</th>
-                    <th>Raw Remap Text</th>
-                    <th>Routing Name</th>
-                    <th>Service Category</th>
-                    <th>Signed</th>
-                    <th>Signing Algorithm</th>
-                    <th>Range Slice Block Size</th>
-                    <th>Tenant</th>
-                    <th>Topology</th>
-                    <th>TR Request Headers</th>
-                    <th>TR Response Headers</th>
-                    <th>Type</th>
-                    <th>XML ID (Key)</th>
-                </tr>
-            </thead>
-            <tbody>
-                <tr ng-click="editDeliveryService(ds)" ng-repeat="ds in ::deliveryServices" context-menu="contextMenuItems">
-                    <td data-search="^{{::ds.active}}$">{{::ds.active}}</td>
-                    <td data-search="^{{::ds.anonymousBlockingEnabled}}$">{{::ds.anonymousBlockingEnabled}}</td>
-                    <td data-search="^{{::ds.cdnName}}$">{{::ds.cdnName}}</td>
-                    <td data-search="^{{::ds.checkPath}}$">{{::ds.checkPath}}</td>
-                    <td data-search="^{{::ds.consistentHashQueryParams}}$">{{::ds.consistentHashQueryParams.join(', ')}}</td>
-                    <td data-search="^{{::ds.consistentHashRegex}}$">{{::ds.consistentHashRegex}}</td>
-                    <td data-search="^{{::ds.deepCachingType}}$">{{::ds.deepCachingType}}</td>
-                    <td data-search="^{{::ds.displayName}}$">{{::ds.displayName}}</td>
-                    <td data-search="^{{::ds.dnsBypassCname}}$">{{::ds.dnsBypassCname}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp}}$">{{::ds.dnsBypassIp}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp6}}$">{{::ds.dnsBypassIp6}}</td>
-                    <td data-search="^{{::ds.dnsBypassTtl}}$">{{::ds.dnsBypassTtl}}</td>
-                    <td data-search="^{{::ds.ccrDnsTtl}}$">{{::ds.ccrDnsTtl}}</td>
-                    <td data-search="^{{::ds.dscp}}$">{{::ds.dscp}}</td>
-                    <td data-search="^{{::ds.ecsEnabled}}$">{{::ds.ecsEnabled}}</td>
-                    <td data-search="^{{::ds.edgeHeaderRewrite}}$">{{::ds.edgeHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.firstHeaderRewrite}}$">{{::ds.firstHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.fqPacingRate}}$">{{::ds.fqPacingRate}}</td>
-                    <td data-search="^{{::geoLimit(ds)}}$">{{::geoLimit(ds)}}</td>
-                    <td data-search="^{{::ds.geoLimitCountries}}$">{{::ds.geoLimitCountries}}</td>
-                    <td data-search="^{{::ds.geoLimitRedirectURL}}$">{{::ds.geoLimitRedirectURL}}</td>
-                    <td data-search="^{{::geoProvider(ds)}}$">{{::geoProvider(ds)}}</td>
-                    <td data-search="^{{::ds.missLat}}$">{{::ds.missLat}}</td>
-                    <td data-search="^{{::ds.missLong}}$">{{::ds.missLong}}</td>
-                    <td data-search="^{{::ds.globalMaxMbps}}$">{{::ds.globalMaxMbps}}</td>
-                    <td data-search="^{{::ds.globalMaxTps}}$">{{::ds.globalMaxTps}}</td>
-                    <td data-search="^{{::ds.httpBypassFqdn}}$">{{::ds.httpBypassFqdn}}</td>
-                    <td data-search="^{{::ds.id}}$">{{::ds.id}}</td>
-                    <td data-search="^{{::ds.infoUrl}}$">{{::ds.infoUrl}}</td>
-                    <td data-search="^{{::ds.initialDispersion}}$">{{::ds.initialDispersion}}</td>
-                    <td data-search="^{{::ds.innerHeaderRewrite}}$">{{::ds.innerHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.ipv6RoutingEnabled}}$">{{::ds.ipv6RoutingEnabled}}</td>
-                    <td data-search="^{{::ds.lastHeaderRewrite}}$">{{::ds.lastHeaderRewrite}}</td>
-                    <td data-search="^{{::getRelativeTime(ds.lastUpdated)}}$" data-order="{{::ds.lastUpdated}}">{{::getRelativeTime(ds.lastUpdated)}}</td>
-                    <td data-search="^{{::ds.longDesc}}$">{{::ds.longDesc}}</td>
-                    <td data-search="^{{::ds.longDesc1}}$">{{::ds.longDesc1}}</td>
-                    <td data-search="^{{::ds.longDesc2}}$">{{::ds.longDesc2}}</td>
-                    <td data-search="^{{::ds.maxDnsAnswers}}$">{{::ds.maxDnsAnswers}}</td>
-                    <td data-search="^{{::ds.maxOriginConnections}}$">{{::ds.maxOriginConnections}}</td>
-                    <td data-search="^{{::ds.maxRequestHeaderBytes}}$">{{::ds.maxRequestHeaderBytes}}</td>
-                    <td data-search="^{{::ds.midHeaderRewrite}}$">{{::ds.midHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.multiSiteOrigin}}$">{{::ds.multiSiteOrigin}}</td>
-                    <td data-search="^{{::ds.originShield}}$">{{::ds.originShield}}</td>
-                    <td data-search="^{{::ds.orgServerFqdn}}$">{{::ds.orgServerFqdn}}</td>
-                    <td data-search="^{{::ds.profileName}}$">{{::ds.profileName}}</td>
-                    <td data-search="^{{::protocol(ds)}}$">{{::protocol(ds)}}</td>
-                    <td data-search="^{{::qstring(ds)}}$">{{::qstring(ds)}}</td>
-                    <td data-search="^{{::rrh(ds)}}$">{{::rrh(ds)}}</td>
-                    <td data-search="^{{::ds.regexRemap}}$">{{::ds.regexRemap}}</td>
-                    <td data-search="^{{::ds.regionalGeoBlocking}}$">{{::ds.regionalGeoBlocking}}</td>
-                    <td data-search="^{{::ds.remapText}}$">{{::ds.remapText}}</td>
-                    <td data-search="^{{::ds.routingName}}$">{{::ds.routingName}}</td>
-                    <td data-search="^{{::ds.serviceCategory}}$">{{::ds.serviceCategory}}</td>
-                    <td data-search="^{{::ds.signed}}$">{{::ds.signed}}</td>
-                    <td data-search="^{{::ds.signingAlgorithm}}$">{{::ds.signingAlgorithm}}</td>
-                    <td data-search="^{{::ds.rangeSliceBlockSize}}$">{{::ds.rangeSliceBlockSize}}</td>
-                    <td data-search="^{{::ds.tenant}}$">{{::ds.tenant}}</td>
-                    <td data-search="^{{::ds.topology}}$">{{::ds.topology}}</td>
-                    <td data-search="^{{::ds.trResponseHeaders}}$">{{::ds.trResponseHeaders}}</td>
-                    <td data-search="^{{::ds.trRequestHeaders}}$">{{::ds.trRequestHeaders}}</td>
-                    <td data-search="^{{::ds.type}}$">{{::ds.type}}</td>
-                    <td name="xmlId" data-search="^{{::ds.xmlId}}$">{{::ds.xmlId}}</td>
-                </tr>
-            </tbody>
-        </table>
+        <div style="height: 740px;" ag-grid="gridOptions" class="ag-theme-alpine"></div>
     </div>
 </div>
 
+<menu id="context-menu" class="dropdown-menu" ng-style="menuStyle" type="contextmenu" ng-show="showMenu">
+    <ul>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}" target="_blank">Open {{ deliveryService.xmlId }} in New Tab</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}">Edit</a>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="clone(deliveryService, $event)">Clone</button>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="confirmDelete(deliveryService, $event)">Delete</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <button type="button" ng-click="viewCharts(deliveryService, $event)">View Charts</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/ssl-keys?type={{deliveryService.type}}">Manage SSL Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/url-sig-keys?type={{deliveryService.type}}">Manage URL Sig Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/uri-signing-keys?type={{deliveryService.type}}">Manage URI Signing Keys</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/jobs?type={{deliveryService.type}}">Manage Invalidation Requests</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') == -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/origins?type={{deliveryService.type}}">Manage Origins</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/regexes?type={{deliveryService.type}}">Manage Regexes</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('DNS') != -1 || deliveryService.type.indexOf('HTTP') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/required-server-capabilities?type={{deliveryService.type}}">Manage Required Server Capabilities</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/servers?type={{deliveryService.type}}">Manage Servers</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/targets?type={{deliveryService.type}}">Manage Targets</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/static-dns-entries?type={{deliveryService.type}}">Manage Static DNS Entries</a>
+        </li>
+    </ul>
+</menu>
+
+
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 18bedbd..2a41c8f 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
@@ -32,7 +32,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
                 </div>
                 <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">
diff --git a/traffic_portal/app/src/common/modules/table/tenantDeliveryServices/TableTenantDeliveryServicesController.js b/traffic_portal/app/src/common/modules/table/tenantDeliveryServices/TableTenantDeliveryServicesController.js
index 538ca01..c8c8357 100644
--- a/traffic_portal/app/src/common/modules/table/tenantDeliveryServices/TableTenantDeliveryServicesController.js
+++ b/traffic_portal/app/src/common/modules/table/tenantDeliveryServices/TableTenantDeliveryServicesController.js
@@ -17,39 +17,13 @@
  * under the License.
  */
 
-var TableTenantDeliveryServicesController = function(tenant, deliveryServices, $controller, $scope) {
+var TableTenantDeliveryServicesController = function(tenant, deliveryServices, filter, $controller, $scope) {
 
 	// extends the TableDeliveryServicesController to inherit common methods
-	angular.extend(this, $controller('TableDeliveryServicesController', { deliveryServices: deliveryServices, $scope: $scope }));
-
-	let tenantDSsTable;
+	angular.extend(this, $controller('TableDeliveryServicesController', { tableName: 'tenantDS', deliveryServices: deliveryServices, filter: filter, $scope: $scope }));
 
 	$scope.tenant = tenant;
-
-	$scope.toggleVisibility = function(colName) {
-		const col = tenantDSsTable.column(colName + ':name');
-		col.visible(!col.visible());
-		tenantDSsTable.rows().invalidate().draw();
-	};
-
-	angular.element(document).ready(function () {
-		tenantDSsTable = $('#tenantDSsTable').DataTable({
-			"lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
-			"iDisplayLength": 25,
-			"aaSorting": [],
-			"columns": $scope.columns,
-			"initComplete": function(settings, json) {
-				try {
-					// need to create the show/hide column checkboxes and bind to the current visibility
-					$scope.columns = JSON.parse(localStorage.getItem('DataTables_tenantDSsTable_/')).columns;
-				} catch (e) {
-					console.error("Failure to retrieve required column info from localStorage (key=DataTables_tenantDSsTable_/):", e);
-				}
-			}
-		});
-	});
-
 };
 
-TableTenantDeliveryServicesController.$inject = ['tenant', 'deliveryServices', '$controller', '$scope'];
+TableTenantDeliveryServicesController.$inject = ['tenant', 'deliveryServices', 'filter', '$controller', '$scope'];
 module.exports = TableTenantDeliveryServicesController;
diff --git a/traffic_portal/app/src/common/modules/table/tenantDeliveryServices/table.tenantDeliveryServices.tpl.html b/traffic_portal/app/src/common/modules/table/tenantDeliveryServices/table.tenantDeliveryServices.tpl.html
index a92fdc9..a8ed906 100644
--- a/traffic_portal/app/src/common/modules/table/tenantDeliveryServices/table.tenantDeliveryServices.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/tenantDeliveryServices/table.tenantDeliveryServices.tpl.html
@@ -20,164 +20,101 @@ under the License.
 <div class="x_panel">
     <div class="x_title">
         <ol class="breadcrumb pull-left">
-            <li><a ng-click="navigateToPath('/tenants')">Tenants</a></li>
-            <li><a ng-click="navigateToPath('/tenants/' + tenant.id)">{{::tenant.name}}</a></li>
+            <li><a href="#!/tenants">Tenants</a></li>
+            <li><a ng-href="#!/tenants/{{tenant.id}}">{{::tenant.name}}</a></li>
             <li class="active">Delivery Services</li>
         </ol>
         <div class="pull-right">
-            <button class="btn btn-default" title="Refresh" ng-click="refresh()"><i class="fa fa-refresh"></i></button>
-            <div 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 class="form-inline" role="search">
+                <input id="quickSearch" name="quickSearch" type="search" class="form-control text-input" placeholder="Quick search..." ng-model="quickSearch" ng-change="onQuickSearchChanged()" aria-label="Search"/>
+                <div class="input-group text-input">
+                    <span class="input-group-addon">
+                        <label for="pageSize">Page size</label>
+                    </span>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                </div>
+                <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 gridOptions.columnApi.getAllColumns() | orderBy:'colDef.headerName'">
+                            <div class="checkbox">
+                                <label><input type="checkbox" ng-checked="c.isVisible()" ng-click="toggleVisibility(c.colId)">{{::c.colDef.headerName}}</label>
+                            </div>
+                        </li>
+                    </menu>
+                </div>
+                <div class="btn-group" role="group" uib-dropdown is-open="more.isopen">
+                    <button name="moreBtn" type="button" class="btn btn-default dropdown-toggle" uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
+                        More&nbsp;
+                        <span class="caret"></span>
+                    </button>
+                    <ul class="dropdown-menu-right dropdown-menu" uib-dropdown-menu>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="clearTableFilters()">Clear Table Filters</button></li>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="exportCSV()">Export CSV</button></li>
+                    </ul>
+                </div>
             </div>
         </div>
         <div class="clearfix"></div>
     </div>
     <div class="x_content">
-        <br>
-        <table id="tenantDSsTable" class="table responsive-utilities jambo_table">
-            <thead>
-                <tr class="headings">
-                    <th>Active</th>
-                    <th>Anonymous Blocking</th>
-                    <th>CDN</th>
-                    <th>Check Path</th>
-                    <th>Consistent Hash Query Params</th>
-                    <th>Consistent Hash Regex</th>
-                    <th>Deep Caching Type</th>
-                    <th>Display Name</th>
-                    <th>DNS Bypass CNAME</th>
-                    <th>DNS Bypass IP</th>
-                    <th>DNS Bypass IPv6</th>
-                    <th>DNS Bypass TTL</th>
-                    <th>DNS TTL</th>
-                    <th>DSCP</th>
-                    <th>ECS Enabled</th>
-                    <th>Edge Header Rewrite Rules</th>
-                    <th>First Header Rewrite Rules</th>
-                    <th>FQ Pacing Rate</th>
-                    <th>Geo Limit</th>
-                    <th>Geo Limit Countries</th>
-                    <th>Geo Limit Redirect URL</th>
-                    <th>Geolocation Provider</th>
-                    <th>Geo Miss Latitude</th>
-                    <th>Geo Miss Longitude</th>
-                    <th>Global Max Mbps</th>
-                    <th>Global Max TPS</th>
-                    <th>HTTP Bypass FQDN</th>
-                    <th>ID</th>
-                    <th>Info URL</th>
-                    <th>Initial Dispersion</th>
-                    <th>Inner Header Rewrite Rules</th>
-                    <th>IPv6 Routing</th>
-                    <th>Last Header Rewrite Rules</th>
-                    <th>Last Updated</th>
-                    <th>Long Desc 1</th>
-                    <th>Long Desc 2</th>
-                    <th>Long Desc 3</th>
-                    <th>Max DNS Answers</th>
-                    <th>Max Origin Connections</th>
-                    <th>Max Request Header Bytes</th>
-                    <th>Mid Header Rewrite Rules</th>
-                    <th>Multi-Site Origin</th>
-                    <th>Origin Shield</th>
-                    <th>Origin FQDN</th>
-                    <th>Profile</th>
-                    <th>Protocol</th>
-                    <th>Qstring Handling</th>
-                    <th>Range Request Handling</th>
-                    <th>Regex Remap Expression</th>
-                    <th>Regional Geoblocking</th>
-                    <th>Raw Remap Text</th>
-                    <th>Routing Name</th>
-                    <th>Service Category</th>
-                    <th>Signed</th>
-                    <th>Signing Algorithm</th>
-                    <th>Range Slice Block Size</th>
-                    <th>Tenant</th>
-                    <th>Topology</th>
-                    <th>TR Request Headers</th>
-                    <th>TR Response Headers</th>
-                    <th>Type</th>
-                    <th>XML ID (Key)</th>
-                </tr>
-            </thead>
-            <tbody>
-                <tr ng-click="editDeliveryService(ds)" ng-repeat="ds in ::deliveryServices" context-menu="contextMenuItems">
-                    <td data-search="^{{::ds.active}}$">{{::ds.active}}</td>
-                    <td data-search="^{{::ds.anonymousBlockingEnabled}}$">{{::ds.anonymousBlockingEnabled}}</td>
-                    <td data-search="^{{::ds.cdnName}}$">{{::ds.cdnName}}</td>
-                    <td data-search="^{{::ds.checkPath}}$">{{::ds.checkPath}}</td>
-                    <td data-search="^{{::ds.consistentHashQueryParams}}$">{{::ds.consistentHashQueryParams.join(', ')}}</td>
-                    <td data-search="^{{::ds.consistentHashRegex}}$">{{::ds.consistentHashRegex}}</td>
-                    <td data-search="^{{::ds.deepCachingType}}$">{{::ds.deepCachingType}}</td>
-                    <td data-search="^{{::ds.displayName}}$">{{::ds.displayName}}</td>
-                    <td data-search="^{{::ds.dnsBypassCname}}$">{{::ds.dnsBypassCname}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp}}$">{{::ds.dnsBypassIp}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp6}}$">{{::ds.dnsBypassIp6}}</td>
-                    <td data-search="^{{::ds.dnsBypassTtl}}$">{{::ds.dnsBypassTtl}}</td>
-                    <td data-search="^{{::ds.ccrDnsTtl}}$">{{::ds.ccrDnsTtl}}</td>
-                    <td data-search="^{{::ds.dscp}}$">{{::ds.dscp}}</td>
-                    <td data-search="^{{::ds.ecsEnabled}}$">{{::ds.ecsEnabled}}</td>
-                    <td data-search="^{{::ds.edgeHeaderRewrite}}$">{{::ds.edgeHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.firstHeaderRewrite}}$">{{::ds.firstHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.fqPacingRate}}$">{{::ds.fqPacingRate}}</td>
-                    <td data-search="^{{::geoLimit(ds)}}$">{{::geoLimit(ds)}}</td>
-                    <td data-search="^{{::ds.geoLimitCountries}}$">{{::ds.geoLimitCountries}}</td>
-                    <td data-search="^{{::ds.geoLimitRedirectURL}}$">{{::ds.geoLimitRedirectURL}}</td>
-                    <td data-search="^{{::geoProvider(ds)}}$">{{::geoProvider(ds)}}</td>
-                    <td data-search="^{{::ds.missLat}}$">{{::ds.missLat}}</td>
-                    <td data-search="^{{::ds.missLong}}$">{{::ds.missLong}}</td>
-                    <td data-search="^{{::ds.globalMaxMbps}}$">{{::ds.globalMaxMbps}}</td>
-                    <td data-search="^{{::ds.globalMaxTps}}$">{{::ds.globalMaxTps}}</td>
-                    <td data-search="^{{::ds.httpBypassFqdn}}$">{{::ds.httpBypassFqdn}}</td>
-                    <td data-search="^{{::ds.id}}$">{{::ds.id}}</td>
-                    <td data-search="^{{::ds.infoUrl}}$">{{::ds.infoUrl}}</td>
-                    <td data-search="^{{::ds.initialDispersion}}$">{{::ds.initialDispersion}}</td>
-                    <td data-search="^{{::ds.innerHeaderRewrite}}$">{{::ds.innerHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.ipv6RoutingEnabled}}$">{{::ds.ipv6RoutingEnabled}}</td>
-                    <td data-search="^{{::ds.lastHeaderRewrite}}$">{{::ds.lastHeaderRewrite}}</td>
-                    <td data-search="^{{::getRelativeTime(ds.lastUpdated)}}$" data-order="{{::ds.lastUpdated}}">{{::getRelativeTime(ds.lastUpdated)}}</td>
-                    <td data-search="^{{::ds.longDesc}}$">{{::ds.longDesc}}</td>
-                    <td data-search="^{{::ds.longDesc1}}$">{{::ds.longDesc1}}</td>
-                    <td data-search="^{{::ds.longDesc2}}$">{{::ds.longDesc2}}</td>
-                    <td data-search="^{{::ds.maxDnsAnswers}}$">{{::ds.maxDnsAnswers}}</td>
-                    <td data-search="^{{::ds.maxOriginConnections}}$">{{::ds.maxOriginConnections}}</td>
-                    <td data-search="^{{::ds.maxRequestHeaderBytes}}$">{{::ds.maxRequestHeaderBytes}}</td>
-                    <td data-search="^{{::ds.midHeaderRewrite}}$">{{::ds.midHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.multiSiteOrigin}}$">{{::ds.multiSiteOrigin}}</td>
-                    <td data-search="^{{::ds.originShield}}$">{{::ds.originShield}}</td>
-                    <td data-search="^{{::ds.orgServerFqdn}}$">{{::ds.orgServerFqdn}}</td>
-                    <td data-search="^{{::ds.profileName}}$">{{::ds.profileName}}</td>
-                    <td data-search="^{{::protocol(ds)}}$">{{::protocol(ds)}}</td>
-                    <td data-search="^{{::qstring(ds)}}$">{{::qstring(ds)}}</td>
-                    <td data-search="^{{::rrh(ds)}}$">{{::rrh(ds)}}</td>
-                    <td data-search="^{{::ds.regexRemap}}$">{{::ds.regexRemap}}</td>
-                    <td data-search="^{{::ds.regionalGeoBlocking}}$">{{::ds.regionalGeoBlocking}}</td>
-                    <td data-search="^{{::ds.remapText}}$">{{::ds.remapText}}</td>
-                    <td data-search="^{{::ds.routingName}}$">{{::ds.routingName}}</td>
-                    <td data-search="^{{::ds.serviceCategory}}$">{{::ds.serviceCategory}}</td>
-                    <td data-search="^{{::ds.signed}}$">{{::ds.signed}}</td>
-                    <td data-search="^{{::ds.signingAlgorithm}}$">{{::ds.signingAlgorithm}}</td>
-                    <td data-search="^{{::ds.rangeSliceBlockSize}}$">{{::ds.rangeSliceBlockSize}}</td>
-                    <td data-search="^{{::ds.tenant}}$">{{::ds.tenant}}</td>
-                    <td data-search="^{{::ds.topology}}$">{{::ds.topology}}</td>
-                    <td data-search="^{{::ds.trResponseHeaders}}$">{{::ds.trResponseHeaders}}</td>
-                    <td data-search="^{{::ds.trRequestHeaders}}$">{{::ds.trRequestHeaders}}</td>
-                    <td data-search="^{{::ds.type}}$">{{::ds.type}}</td>
-                    <td name="xmlId" data-search="^{{::ds.xmlId}}$">{{::ds.xmlId}}</td>
-                </tr>
-            </tbody>
-        </table>
+        <div style="height: 740px;" ag-grid="gridOptions" class="ag-theme-alpine"></div>
     </div>
 </div>
 
+<menu id="context-menu" class="dropdown-menu" ng-style="menuStyle" type="contextmenu" ng-show="showMenu">
+    <ul>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}" target="_blank">Open {{ deliveryService.xmlId }} in New Tab</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}">Edit</a>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="clone(deliveryService, $event)">Clone</button>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="confirmDelete(deliveryService, $event)">Delete</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <button type="button" ng-click="viewCharts(deliveryService, $event)">View Charts</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/ssl-keys?type={{deliveryService.type}}">Manage SSL Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/url-sig-keys?type={{deliveryService.type}}">Manage URL Sig Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/uri-signing-keys?type={{deliveryService.type}}">Manage URI Signing Keys</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/jobs?type={{deliveryService.type}}">Manage Invalidation Requests</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') == -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/origins?type={{deliveryService.type}}">Manage Origins</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/regexes?type={{deliveryService.type}}">Manage Regexes</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('DNS') != -1 || deliveryService.type.indexOf('HTTP') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/required-server-capabilities?type={{deliveryService.type}}">Manage Required Server Capabilities</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/servers?type={{deliveryService.type}}">Manage Servers</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/targets?type={{deliveryService.type}}">Manage Targets</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/static-dns-entries?type={{deliveryService.type}}">Manage Static DNS Entries</a>
+        </li>
+    </ul>
+</menu>
diff --git a/traffic_portal/app/src/common/modules/table/topologyCacheGroups/table.topologyCacheGroups.tpl.html b/traffic_portal/app/src/common/modules/table/topologyCacheGroups/table.topologyCacheGroups.tpl.html
index 6641412..35c949f 100644
--- a/traffic_portal/app/src/common/modules/table/topologyCacheGroups/table.topologyCacheGroups.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/topologyCacheGroups/table.topologyCacheGroups.tpl.html
@@ -20,8 +20,8 @@ under the License.
 <div class="x_panel">
     <div class="x_title">
         <ol class="breadcrumb pull-left">
-            <li><a ng-click="navigateToPath('/topologies')">Topologies</a></li>
-            <li><a name="topLink" ng-click="navigateToPath('/topologies/edit?name=' + topology.name)">{{::topology.name}}</a></li>
+            <li><a href="#!/topologies">Topologies</a></li>
+            <li><a name="topLink" ng-href="#!/topologies/edit?name={{topology.name}}">{{::topology.name}}</a></li>
             <li class="active">Cache Groups</li>
         </ol>
         <div class="pull-right">
diff --git a/traffic_portal/app/src/common/modules/table/topologyDeliveryServices/TableTopologyDeliveryServicesController.js b/traffic_portal/app/src/common/modules/table/topologyDeliveryServices/TableTopologyDeliveryServicesController.js
index f4166a8..c2719dd 100644
--- a/traffic_portal/app/src/common/modules/table/topologyDeliveryServices/TableTopologyDeliveryServicesController.js
+++ b/traffic_portal/app/src/common/modules/table/topologyDeliveryServices/TableTopologyDeliveryServicesController.js
@@ -17,39 +17,13 @@
  * under the License.
  */
 
-var TableTopologyDeliveryServicesController = function(topologies, deliveryServices, $controller, $scope) {
+var TableTopologyDeliveryServicesController = function(topologies, deliveryServices, filter, $controller, $scope) {
 
 	// extends the TableDeliveryServicesController to inherit common methods
-	angular.extend(this, $controller('TableDeliveryServicesController', { deliveryServices: deliveryServices, $scope: $scope }));
-
-	let topologyDSsTable;
+	angular.extend(this, $controller('TableDeliveryServicesController', { tableName: 'topDS', deliveryServices: deliveryServices, filter: filter, $scope: $scope }));
 
 	$scope.topology = topologies[0];
-
-	$scope.toggleVisibility = function(colName) {
-		const col = topologyDSsTable.column(colName + ':name');
-		col.visible(!col.visible());
-		topologyDSsTable.rows().invalidate().draw();
-	};
-
-	angular.element(document).ready(function () {
-		topologyDSsTable = $('#topologyDSsTable').DataTable({
-			"lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
-			"iDisplayLength": 25,
-			"aaSorting": [],
-			"columns": $scope.columns,
-			"initComplete": function(settings, json) {
-				try {
-					// need to create the show/hide column checkboxes and bind to the current visibility
-					$scope.columns = JSON.parse(localStorage.getItem('DataTables_topologyDSsTable_/')).columns;
-				} catch (e) {
-					console.error("Failure to retrieve required column info from localStorage (key=DataTables_topologyDSsTable_/):", e);
-				}
-			}
-		});
-	});
-
 };
 
-TableTopologyDeliveryServicesController.$inject = ['topologies', 'deliveryServices', '$controller', '$scope'];
+TableTopologyDeliveryServicesController.$inject = ['topologies', 'deliveryServices', 'filter', '$controller', '$scope'];
 module.exports = TableTopologyDeliveryServicesController;
diff --git a/traffic_portal/app/src/common/modules/table/topologyDeliveryServices/table.topologyDeliveryServices.tpl.html b/traffic_portal/app/src/common/modules/table/topologyDeliveryServices/table.topologyDeliveryServices.tpl.html
index c1efad0..0a67d8f 100644
--- a/traffic_portal/app/src/common/modules/table/topologyDeliveryServices/table.topologyDeliveryServices.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/topologyDeliveryServices/table.topologyDeliveryServices.tpl.html
@@ -20,164 +20,101 @@ under the License.
 <div class="x_panel">
     <div class="x_title">
         <ol class="breadcrumb pull-left">
-            <li><a ng-click="navigateToPath('/topologies')">Topologies</a></li>
-            <li><a name="topLink" ng-click="navigateToPath('/topologies/edit?name=' + topology.name)">{{::topology.name}}</a></li>
+            <li><a href="#!/topologies">Topologies</a></li>
+            <li><a name="topLink" ng-href="#!/topologies/edit?name={{topology.name}}">{{::topology.name}}</a></li>
             <li class="active">Delivery Services</li>
         </ol>
         <div class="pull-right">
-            <button type="button" class="btn btn-default" title="Refresh" ng-click="refresh()"><i class="fa fa-refresh"></i></button>
-            <div 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 class="form-inline" role="search">
+                <input id="quickSearch" name="quickSearch" type="search" class="form-control text-input" placeholder="Quick search..." ng-model="quickSearch" ng-change="onQuickSearchChanged()" aria-label="Search"/>
+                <div class="input-group text-input">
+                    <span class="input-group-addon">
+                        <label for="pageSize">Page size</label>
+                    </span>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                </div>
+                <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 gridOptions.columnApi.getAllColumns() | orderBy:'colDef.headerName'">
+                            <div class="checkbox">
+                                <label><input type="checkbox" ng-checked="c.isVisible()" ng-click="toggleVisibility(c.colId)">{{::c.colDef.headerName}}</label>
+                            </div>
+                        </li>
+                    </menu>
+                </div>
+                <div class="btn-group" role="group" uib-dropdown is-open="more.isopen">
+                    <button name="moreBtn" type="button" class="btn btn-default dropdown-toggle" uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
+                        More&nbsp;
+                        <span class="caret"></span>
+                    </button>
+                    <ul class="dropdown-menu-right dropdown-menu" uib-dropdown-menu>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="clearTableFilters()">Clear Table Filters</button></li>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="exportCSV()">Export CSV</button></li>
+                    </ul>
+                </div>
             </div>
         </div>
         <div class="clearfix"></div>
     </div>
-        <div class="x_content">
-        <br>
-        <table id="topologyDSsTable" class="table responsive-utilities jambo_table">
-            <thead>
-            <tr class="headings">
-                <th>Active</th>
-                <th>Anonymous Blocking</th>
-                <th>CDN</th>
-                <th>Check Path</th>
-                <th>Consistent Hash Query Params</th>
-                <th>Consistent Hash Regex</th>
-                <th>Deep Caching Type</th>
-                <th>Display Name</th>
-                <th>DNS Bypass CNAME</th>
-                <th>DNS Bypass IP</th>
-                <th>DNS Bypass IPv6</th>
-                <th>DNS Bypass TTL</th>
-                <th>DNS TTL</th>
-                <th>DSCP</th>
-                <th>ECS Enabled</th>
-                <th>Edge Header Rewrite Rules</th>
-                <th>First Header Rewrite Rules</th>
-                <th>FQ Pacing Rate</th>
-                <th>Geo Limit</th>
-                <th>Geo Limit Countries</th>
-                <th>Geo Limit Redirect URL</th>
-                <th>Geolocation Provider</th>
-                <th>Geo Miss Latitude</th>
-                <th>Geo Miss Longitude</th>
-                <th>Global Max Mbps</th>
-                <th>Global Max TPS</th>
-                <th>HTTP Bypass FQDN</th>
-                <th>ID</th>
-                <th>Info URL</th>
-                <th>Initial Dispersion</th>
-                <th>Inner Header Rewrite Rules</th>
-                <th>IPv6 Routing</th>
-                <th>Last Header Rewrite Rules</th>
-                <th>Last Updated</th>
-                <th>Long Desc 1</th>
-                <th>Long Desc 2</th>
-                <th>Long Desc 3</th>
-                <th>Max DNS Answers</th>
-                <th>Max Origin Connections</th>
-                <th>Max Request Header Bytes</th>
-                <th>Mid Header Rewrite Rules</th>
-                <th>Multi-Site Origin</th>
-                <th>Origin Shield</th>
-                <th>Origin FQDN</th>
-                <th>Profile</th>
-                <th>Protocol</th>
-                <th>Qstring Handling</th>
-                <th>Range Request Handling</th>
-                <th>Regex Remap Expression</th>
-                <th>Regional Geoblocking</th>
-                <th>Raw Remap Text</th>
-                <th>Routing Name</th>
-                <th>Service Category</th>
-                <th>Signed</th>
-                <th>Signing Algorithm</th>
-                <th>Range Slice Block Size</th>
-                <th>Tenant</th>
-                <th>Topology</th>
-                <th>TR Request Headers</th>
-                <th>TR Response Headers</th>
-                <th>Type</th>
-                <th>XML ID (Key)</th>
-            </tr>
-            </thead>
-            <tbody>
-            <tr ng-click="editDeliveryService(ds)" ng-repeat="ds in ::deliveryServices" context-menu="contextMenuItems">
-                <td data-search="^{{::ds.active}}$">{{::ds.active}}</td>
-                <td data-search="^{{::ds.anonymousBlockingEnabled}}$">{{::ds.anonymousBlockingEnabled}}</td>
-                <td data-search="^{{::ds.cdnName}}$">{{::ds.cdnName}}</td>
-                <td data-search="^{{::ds.checkPath}}$">{{::ds.checkPath}}</td>
-                <td data-search="^{{::ds.consistentHashQueryParams}}$">{{::ds.consistentHashQueryParams.join(', ')}}</td>
-                <td data-search="^{{::ds.consistentHashRegex}}$">{{::ds.consistentHashRegex}}</td>
-                <td data-search="^{{::ds.deepCachingType}}$">{{::ds.deepCachingType}}</td>
-                <td data-search="^{{::ds.displayName}}$">{{::ds.displayName}}</td>
-                <td data-search="^{{::ds.dnsBypassCname}}$">{{::ds.dnsBypassCname}}</td>
-                <td data-search="^{{::ds.dnsBypassIp}}$">{{::ds.dnsBypassIp}}</td>
-                <td data-search="^{{::ds.dnsBypassIp6}}$">{{::ds.dnsBypassIp6}}</td>
-                <td data-search="^{{::ds.dnsBypassTtl}}$">{{::ds.dnsBypassTtl}}</td>
-                <td data-search="^{{::ds.ccrDnsTtl}}$">{{::ds.ccrDnsTtl}}</td>
-                <td data-search="^{{::ds.dscp}}$">{{::ds.dscp}}</td>
-                <td data-search="^{{::ds.ecsEnabled}}$">{{::ds.ecsEnabled}}</td>
-                <td data-search="^{{::ds.edgeHeaderRewrite}}$">{{::ds.edgeHeaderRewrite}}</td>
-                <td data-search="^{{::ds.firstHeaderRewrite}}$">{{::ds.firstHeaderRewrite}}</td>
-                <td data-search="^{{::ds.fqPacingRate}}$">{{::ds.fqPacingRate}}</td>
-                <td data-search="^{{::geoLimit(ds)}}$">{{::geoLimit(ds)}}</td>
-                <td data-search="^{{::ds.geoLimitCountries}}$">{{::ds.geoLimitCountries}}</td>
-                <td data-search="^{{::ds.geoLimitRedirectURL}}$">{{::ds.geoLimitRedirectURL}}</td>
-                <td data-search="^{{::geoProvider(ds)}}$">{{::geoProvider(ds)}}</td>
-                <td data-search="^{{::ds.missLat}}$">{{::ds.missLat}}</td>
-                <td data-search="^{{::ds.missLong}}$">{{::ds.missLong}}</td>
-                <td data-search="^{{::ds.globalMaxMbps}}$">{{::ds.globalMaxMbps}}</td>
-                <td data-search="^{{::ds.globalMaxTps}}$">{{::ds.globalMaxTps}}</td>
-                <td data-search="^{{::ds.httpBypassFqdn}}$">{{::ds.httpBypassFqdn}}</td>
-                <td data-search="^{{::ds.id}}$">{{::ds.id}}</td>
-                <td data-search="^{{::ds.infoUrl}}$">{{::ds.infoUrl}}</td>
-                <td data-search="^{{::ds.initialDispersion}}$">{{::ds.initialDispersion}}</td>
-                <td data-search="^{{::ds.innerHeaderRewrite}}$">{{::ds.innerHeaderRewrite}}</td>
-                <td data-search="^{{::ds.ipv6RoutingEnabled}}$">{{::ds.ipv6RoutingEnabled}}</td>
-                <td data-search="^{{::ds.lastHeaderRewrite}}$">{{::ds.lastHeaderRewrite}}</td>
-                <td data-search="^{{::getRelativeTime(ds.lastUpdated)}}$" data-order="{{::ds.lastUpdated}}">{{::getRelativeTime(ds.lastUpdated)}}</td>
-                <td data-search="^{{::ds.longDesc}}$">{{::ds.longDesc}}</td>
-                <td data-search="^{{::ds.longDesc1}}$">{{::ds.longDesc1}}</td>
-                <td data-search="^{{::ds.longDesc2}}$">{{::ds.longDesc2}}</td>
-                <td data-search="^{{::ds.maxDnsAnswers}}$">{{::ds.maxDnsAnswers}}</td>
-                <td data-search="^{{::ds.maxOriginConnections}}$">{{::ds.maxOriginConnections}}</td>
-                <td data-search="^{{::ds.maxRequestHeaderBytes}}$">{{::ds.maxRequestHeaderBytes}}</td>
-                <td data-search="^{{::ds.midHeaderRewrite}}$">{{::ds.midHeaderRewrite}}</td>
-                <td data-search="^{{::ds.multiSiteOrigin}}$">{{::ds.multiSiteOrigin}}</td>
-                <td data-search="^{{::ds.originShield}}$">{{::ds.originShield}}</td>
-                <td data-search="^{{::ds.orgServerFqdn}}$">{{::ds.orgServerFqdn}}</td>
-                <td data-search="^{{::ds.profileName}}$">{{::ds.profileName}}</td>
-                <td data-search="^{{::protocol(ds)}}$">{{::protocol(ds)}}</td>
-                <td data-search="^{{::qstring(ds)}}$">{{::qstring(ds)}}</td>
-                <td data-search="^{{::rrh(ds)}}$">{{::rrh(ds)}}</td>
-                <td data-search="^{{::ds.regexRemap}}$">{{::ds.regexRemap}}</td>
-                <td data-search="^{{::ds.regionalGeoBlocking}}$">{{::ds.regionalGeoBlocking}}</td>
-                <td data-search="^{{::ds.remapText}}$">{{::ds.remapText}}</td>
-                <td data-search="^{{::ds.routingName}}$">{{::ds.routingName}}</td>
-                <td data-search="^{{::ds.serviceCategory}}$">{{::ds.serviceCategory}}</td>
-                <td data-search="^{{::ds.signed}}$">{{::ds.signed}}</td>
-                <td data-search="^{{::ds.signingAlgorithm}}$">{{::ds.signingAlgorithm}}</td>
-                <td data-search="^{{::ds.rangeSliceBlockSize}}$">{{::ds.rangeSliceBlockSize}}</td>
-                <td data-search="^{{::ds.tenant}}$">{{::ds.tenant}}</td>
-                <td data-search="^{{::ds.topology}}$">{{::ds.topology}}</td>
-                <td data-search="^{{::ds.trResponseHeaders}}$">{{::ds.trResponseHeaders}}</td>
-                <td data-search="^{{::ds.trRequestHeaders}}$">{{::ds.trRequestHeaders}}</td>
-                <td data-search="^{{::ds.type}}$">{{::ds.type}}</td>
-                <td name="xmlId" data-search="^{{::ds.xmlId}}$">{{::ds.xmlId}}</td>
-            </tr>
-            </tbody>
-        </table>
+    <div class="x_content">
+        <div style="height: 740px;" ag-grid="gridOptions" class="ag-theme-alpine"></div>
     </div>
 </div>
 
+<menu id="context-menu" class="dropdown-menu" ng-style="menuStyle" type="contextmenu" ng-show="showMenu">
+    <ul>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}" target="_blank">Open {{ deliveryService.xmlId }} in New Tab</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}">Edit</a>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="clone(deliveryService, $event)">Clone</button>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="confirmDelete(deliveryService, $event)">Delete</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <button type="button" ng-click="viewCharts(deliveryService, $event)">View Charts</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/ssl-keys?type={{deliveryService.type}}">Manage SSL Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/url-sig-keys?type={{deliveryService.type}}">Manage URL Sig Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/uri-signing-keys?type={{deliveryService.type}}">Manage URI Signing Keys</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/jobs?type={{deliveryService.type}}">Manage Invalidation Requests</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') == -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/origins?type={{deliveryService.type}}">Manage Origins</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/regexes?type={{deliveryService.type}}">Manage Regexes</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('DNS') != -1 || deliveryService.type.indexOf('HTTP') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/required-server-capabilities?type={{deliveryService.type}}">Manage Required Server Capabilities</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/servers?type={{deliveryService.type}}">Manage Servers</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/targets?type={{deliveryService.type}}">Manage Targets</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/static-dns-entries?type={{deliveryService.type}}">Manage Static DNS Entries</a>
+        </li>
+    </ul>
+</menu>
diff --git a/traffic_portal/app/src/common/modules/table/topologyServers/table.topologyServers.tpl.html b/traffic_portal/app/src/common/modules/table/topologyServers/table.topologyServers.tpl.html
index e8fa020..9315497 100644
--- a/traffic_portal/app/src/common/modules/table/topologyServers/table.topologyServers.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/topologyServers/table.topologyServers.tpl.html
@@ -31,7 +31,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
                 </div>
                 <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">
diff --git a/traffic_portal/app/src/common/modules/table/typeDeliveryServices/TableTypeDeliveryServicesController.js b/traffic_portal/app/src/common/modules/table/typeDeliveryServices/TableTypeDeliveryServicesController.js
index adb8a74..79e15e3 100644
--- a/traffic_portal/app/src/common/modules/table/typeDeliveryServices/TableTypeDeliveryServicesController.js
+++ b/traffic_portal/app/src/common/modules/table/typeDeliveryServices/TableTypeDeliveryServicesController.js
@@ -17,39 +17,13 @@
  * under the License.
  */
 
-var TableTypeDeliveryServicesController = function(type, deliveryServices, $controller, $scope) {
+var TableTypeDeliveryServicesController = function(type, deliveryServices, filter, $controller, $scope) {
 
 	// extends the TableDeliveryServicesController to inherit common methods
-	angular.extend(this, $controller('TableDeliveryServicesController', { deliveryServices: deliveryServices, $scope: $scope }));
-
-	let typeDeliveryServicesTable;
+	angular.extend(this, $controller('TableDeliveryServicesController', { tableName: 'typeDS', deliveryServices: deliveryServices, filter: filter, $scope: $scope }));
 
 	$scope.type = type;
-
-	$scope.toggleVisibility = function(colName) {
-		const col = typeDeliveryServicesTable.column(colName + ':name');
-		col.visible(!col.visible());
-		typeDeliveryServicesTable.rows().invalidate().draw();
-	};
-
-	angular.element(document).ready(function () {
-		typeDeliveryServicesTable = $('#typeDeliveryServicesTable').DataTable({
-			"lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
-			"iDisplayLength": 25,
-			"aaSorting": [],
-			"columns": $scope.columns,
-			"initComplete": function(settings, json) {
-				try {
-					// need to create the show/hide column checkboxes and bind to the current visibility
-					$scope.columns = JSON.parse(localStorage.getItem('DataTables_typeDeliveryServicesTable_/')).columns;
-				} catch (e) {
-					console.error("Failure to retrieve required column info from localStorage (key=DataTables_typeDeliveryServicesTable_/):", e);
-				}
-			}
-		});
-	});
-
 };
 
-TableTypeDeliveryServicesController.$inject = ['type', 'deliveryServices', '$controller', '$scope'];
+TableTypeDeliveryServicesController.$inject = ['type', 'deliveryServices', 'filter', '$controller', '$scope'];
 module.exports = TableTypeDeliveryServicesController;
diff --git a/traffic_portal/app/src/common/modules/table/typeDeliveryServices/table.typeDeliveryServices.tpl.html b/traffic_portal/app/src/common/modules/table/typeDeliveryServices/table.typeDeliveryServices.tpl.html
index 99aeaff..527f823 100644
--- a/traffic_portal/app/src/common/modules/table/typeDeliveryServices/table.typeDeliveryServices.tpl.html
+++ b/traffic_portal/app/src/common/modules/table/typeDeliveryServices/table.typeDeliveryServices.tpl.html
@@ -20,164 +20,101 @@ under the License.
 <div class="x_panel">
     <div class="x_title">
         <ol class="breadcrumb pull-left">
-            <li><a ng-click="navigateToPath('/types')">Types</a></li>
-            <li><a ng-click="navigateToPath('/types/' + type.id)">{{::type.name}}</a></li>
+            <li><a href="#!/types">Types</a></li>
+            <li><a ng-href="#!/types/{{type.id}}">{{::type.name}}</a></li>
             <li class="active">Delivery Services</li>
         </ol>
         <div class="pull-right">
-            <button class="btn btn-default" title="Refresh" ng-click="refresh()"><i class="fa fa-refresh"></i></button>
-            <div 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 class="form-inline" role="search">
+                <input id="quickSearch" name="quickSearch" type="search" class="form-control text-input" placeholder="Quick search..." ng-model="quickSearch" ng-change="onQuickSearchChanged()" aria-label="Search"/>
+                <div class="input-group text-input">
+                    <span class="input-group-addon">
+                        <label for="pageSize">Page size</label>
+                    </span>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                </div>
+                <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 gridOptions.columnApi.getAllColumns() | orderBy:'colDef.headerName'">
+                            <div class="checkbox">
+                                <label><input type="checkbox" ng-checked="c.isVisible()" ng-click="toggleVisibility(c.colId)">{{::c.colDef.headerName}}</label>
+                            </div>
+                        </li>
+                    </menu>
+                </div>
+                <div class="btn-group" role="group" uib-dropdown is-open="more.isopen">
+                    <button name="moreBtn" type="button" class="btn btn-default dropdown-toggle" uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
+                        More&nbsp;
+                        <span class="caret"></span>
+                    </button>
+                    <ul class="dropdown-menu-right dropdown-menu" uib-dropdown-menu>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="clearTableFilters()">Clear Table Filters</button></li>
+                        <li role="menuitem"><button class="menu-item-button" type="button" ng-click="exportCSV()">Export CSV</button></li>
+                    </ul>
+                </div>
             </div>
         </div>
         <div class="clearfix"></div>
     </div>
     <div class="x_content">
-        <br>
-        <table id="typeDeliveryServicesTable" class="table responsive-utilities jambo_table">
-            <thead>
-                <tr class="headings">
-                    <th>Active</th>
-                    <th>Anonymous Blocking</th>
-                    <th>CDN</th>
-                    <th>Check Path</th>
-                    <th>Consistent Hash Query Params</th>
-                    <th>Consistent Hash Regex</th>
-                    <th>Deep Caching Type</th>
-                    <th>Display Name</th>
-                    <th>DNS Bypass CNAME</th>
-                    <th>DNS Bypass IP</th>
-                    <th>DNS Bypass IPv6</th>
-                    <th>DNS Bypass TTL</th>
-                    <th>DNS TTL</th>
-                    <th>DSCP</th>
-                    <th>ECS Enabled</th>
-                    <th>Edge Header Rewrite Rules</th>
-                    <th>First Header Rewrite Rules</th>
-                    <th>FQ Pacing Rate</th>
-                    <th>Geo Limit</th>
-                    <th>Geo Limit Countries</th>
-                    <th>Geo Limit Redirect URL</th>
-                    <th>Geolocation Provider</th>
-                    <th>Geo Miss Latitude</th>
-                    <th>Geo Miss Longitude</th>
-                    <th>Global Max Mbps</th>
-                    <th>Global Max TPS</th>
-                    <th>HTTP Bypass FQDN</th>
-                    <th>ID</th>
-                    <th>Info URL</th>
-                    <th>Initial Dispersion</th>
-                    <th>Inner Header Rewrite Rules</th>
-                    <th>IPv6 Routing</th>
-                    <th>Last Header Rewrite Rules</th>
-                    <th>Last Updated</th>
-                    <th>Long Desc 1</th>
-                    <th>Long Desc 2</th>
-                    <th>Long Desc 3</th>
-                    <th>Max DNS Answers</th>
-                    <th>Max Origin Connections</th>
-                    <th>Max Request Header Bytes</th>
-                    <th>Mid Header Rewrite Rules</th>
-                    <th>Multi-Site Origin</th>
-                    <th>Origin Shield</th>
-                    <th>Origin FQDN</th>
-                    <th>Profile</th>
-                    <th>Protocol</th>
-                    <th>Qstring Handling</th>
-                    <th>Range Request Handling</th>
-                    <th>Regex Remap Expression</th>
-                    <th>Regional Geoblocking</th>
-                    <th>Raw Remap Text</th>
-                    <th>Routing Name</th>
-                    <th>Service Category</th>
-                    <th>Signed</th>
-                    <th>Signing Algorithm</th>
-                    <th>Range Slice Block Size</th>
-                    <th>Tenant</th>
-                    <th>Topology</th>
-                    <th>TR Request Headers</th>
-                    <th>TR Response Headers</th>
-                    <th>Type</th>
-                    <th>XML ID (Key)</th>
-                </tr>
-            </thead>
-            <tbody>
-                <tr ng-click="editDeliveryService(ds)" ng-repeat="ds in ::deliveryServices" context-menu="contextMenuItems">
-                    <td data-search="^{{::ds.active}}$">{{::ds.active}}</td>
-                    <td data-search="^{{::ds.anonymousBlockingEnabled}}$">{{::ds.anonymousBlockingEnabled}}</td>
-                    <td data-search="^{{::ds.cdnName}}$">{{::ds.cdnName}}</td>
-                    <td data-search="^{{::ds.checkPath}}$">{{::ds.checkPath}}</td>
-                    <td data-search="^{{::ds.consistentHashQueryParams}}$">{{::ds.consistentHashQueryParams.join(', ')}}</td>
-                    <td data-search="^{{::ds.consistentHashRegex}}$">{{::ds.consistentHashRegex}}</td>
-                    <td data-search="^{{::ds.deepCachingType}}$">{{::ds.deepCachingType}}</td>
-                    <td data-search="^{{::ds.displayName}}$">{{::ds.displayName}}</td>
-                    <td data-search="^{{::ds.dnsBypassCname}}$">{{::ds.dnsBypassCname}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp}}$">{{::ds.dnsBypassIp}}</td>
-                    <td data-search="^{{::ds.dnsBypassIp6}}$">{{::ds.dnsBypassIp6}}</td>
-                    <td data-search="^{{::ds.dnsBypassTtl}}$">{{::ds.dnsBypassTtl}}</td>
-                    <td data-search="^{{::ds.ccrDnsTtl}}$">{{::ds.ccrDnsTtl}}</td>
-                    <td data-search="^{{::ds.dscp}}$">{{::ds.dscp}}</td>
-                    <td data-search="^{{::ds.ecsEnabled}}$">{{::ds.ecsEnabled}}</td>
-                    <td data-search="^{{::ds.edgeHeaderRewrite}}$">{{::ds.edgeHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.firstHeaderRewrite}}$">{{::ds.firstHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.fqPacingRate}}$">{{::ds.fqPacingRate}}</td>
-                    <td data-search="^{{::geoLimit(ds)}}$">{{::geoLimit(ds)}}</td>
-                    <td data-search="^{{::ds.geoLimitCountries}}$">{{::ds.geoLimitCountries}}</td>
-                    <td data-search="^{{::ds.geoLimitRedirectURL}}$">{{::ds.geoLimitRedirectURL}}</td>
-                    <td data-search="^{{::geoProvider(ds)}}$">{{::geoProvider(ds)}}</td>
-                    <td data-search="^{{::ds.missLat}}$">{{::ds.missLat}}</td>
-                    <td data-search="^{{::ds.missLong}}$">{{::ds.missLong}}</td>
-                    <td data-search="^{{::ds.globalMaxMbps}}$">{{::ds.globalMaxMbps}}</td>
-                    <td data-search="^{{::ds.globalMaxTps}}$">{{::ds.globalMaxTps}}</td>
-                    <td data-search="^{{::ds.httpBypassFqdn}}$">{{::ds.httpBypassFqdn}}</td>
-                    <td data-search="^{{::ds.id}}$">{{::ds.id}}</td>
-                    <td data-search="^{{::ds.infoUrl}}$">{{::ds.infoUrl}}</td>
-                    <td data-search="^{{::ds.initialDispersion}}$">{{::ds.initialDispersion}}</td>
-                    <td data-search="^{{::ds.innerHeaderRewrite}}$">{{::ds.innerHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.ipv6RoutingEnabled}}$">{{::ds.ipv6RoutingEnabled}}</td>
-                    <td data-search="^{{::ds.lastHeaderRewrite}}$">{{::ds.lastHeaderRewrite}}</td>
-                    <td data-search="^{{::getRelativeTime(ds.lastUpdated)}}$" data-order="{{::ds.lastUpdated}}">{{::getRelativeTime(ds.lastUpdated)}}</td>
-                    <td data-search="^{{::ds.longDesc}}$">{{::ds.longDesc}}</td>
-                    <td data-search="^{{::ds.longDesc1}}$">{{::ds.longDesc1}}</td>
-                    <td data-search="^{{::ds.longDesc2}}$">{{::ds.longDesc2}}</td>
-                    <td data-search="^{{::ds.maxDnsAnswers}}$">{{::ds.maxDnsAnswers}}</td>
-                    <td data-search="^{{::ds.maxOriginConnections}}$">{{::ds.maxOriginConnections}}</td>
-                    <td data-search="^{{::ds.maxRequestHeaderBytes}}$">{{::ds.maxRequestHeaderBytes}}</td>
-                    <td data-search="^{{::ds.midHeaderRewrite}}$">{{::ds.midHeaderRewrite}}</td>
-                    <td data-search="^{{::ds.multiSiteOrigin}}$">{{::ds.multiSiteOrigin}}</td>
-                    <td data-search="^{{::ds.originShield}}$">{{::ds.originShield}}</td>
-                    <td data-search="^{{::ds.orgServerFqdn}}$">{{::ds.orgServerFqdn}}</td>
-                    <td data-search="^{{::ds.profileName}}$">{{::ds.profileName}}</td>
-                    <td data-search="^{{::protocol(ds)}}$">{{::protocol(ds)}}</td>
-                    <td data-search="^{{::qstring(ds)}}$">{{::qstring(ds)}}</td>
-                    <td data-search="^{{::rrh(ds)}}$">{{::rrh(ds)}}</td>
-                    <td data-search="^{{::ds.regexRemap}}$">{{::ds.regexRemap}}</td>
-                    <td data-search="^{{::ds.regionalGeoBlocking}}$">{{::ds.regionalGeoBlocking}}</td>
-                    <td data-search="^{{::ds.remapText}}$">{{::ds.remapText}}</td>
-                    <td data-search="^{{::ds.routingName}}$">{{::ds.routingName}}</td>
-                    <td data-search="^{{::ds.serviceCategory}}$">{{::ds.serviceCategory}}</td>
-                    <td data-search="^{{::ds.signed}}$">{{::ds.signed}}</td>
-                    <td data-search="^{{::ds.signingAlgorithm}}$">{{::ds.signingAlgorithm}}</td>
-                    <td data-search="^{{::ds.rangeSliceBlockSize}}$">{{::ds.rangeSliceBlockSize}}</td>
-                    <td data-search="^{{::ds.tenant}}$">{{::ds.tenant}}</td>
-                    <td data-search="^{{::ds.topology}}$">{{::ds.topology}}</td>
-                    <td data-search="^{{::ds.trResponseHeaders}}$">{{::ds.trResponseHeaders}}</td>
-                    <td data-search="^{{::ds.trRequestHeaders}}$">{{::ds.trRequestHeaders}}</td>
-                    <td data-search="^{{::ds.type}}$">{{::ds.type}}</td>
-                    <td name="xmlId" data-search="^{{::ds.xmlId}}$">{{::ds.xmlId}}</td>
-                </tr>
-            </tbody>
-        </table>
+        <div style="height: 740px;" ag-grid="gridOptions" class="ag-theme-alpine"></div>
     </div>
 </div>
 
+<menu id="context-menu" class="dropdown-menu" ng-style="menuStyle" type="contextmenu" ng-show="showMenu">
+    <ul>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}" target="_blank">Open {{ deliveryService.xmlId }} in New Tab</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}?type={{deliveryService.type}}">Edit</a>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="clone(deliveryService, $event)">Clone</button>
+        </li>
+        <li role="menuitem">
+            <button type="button" ng-click="confirmDelete(deliveryService, $event)">Delete</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <button type="button" ng-click="viewCharts(deliveryService, $event)">View Charts</button>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/ssl-keys?type={{deliveryService.type}}">Manage SSL Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/url-sig-keys?type={{deliveryService.type}}">Manage URL Sig Keys</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/uri-signing-keys?type={{deliveryService.type}}">Manage URI Signing Keys</a>
+        </li>
+        <hr class="divider"/>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/jobs?type={{deliveryService.type}}">Manage Invalidation Requests</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') == -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/origins?type={{deliveryService.type}}">Manage Origins</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/regexes?type={{deliveryService.type}}">Manage Regexes</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('DNS') != -1 || deliveryService.type.indexOf('HTTP') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/required-server-capabilities?type={{deliveryService.type}}">Manage Required Server Capabilities</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/servers?type={{deliveryService.type}}">Manage Servers</a>
+        </li>
+        <li role="menuitem" ng-if="deliveryService.type.indexOf('STEERING') != -1">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/targets?type={{deliveryService.type}}">Manage Targets</a>
+        </li>
+        <li role="menuitem">
+            <a ng-href="#!/delivery-services/{{deliveryService.id}}/static-dns-entries?type={{deliveryService.type}}">Manage Static DNS Entries</a>
+        </li>
+    </ul>
+</menu>
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 57637da..04d3d57 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
@@ -31,7 +31,7 @@ under the License.
                     <span class="input-group-addon">
                         <label for="pageSize">Page size</label>
                     </span>
-                    <input id="pageSize" name="pageSize" type="number" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
+                    <input id="pageSize" name="pageSize" type="number" min="1" class="form-control" placeholder="100" ng-model="pageSize" ng-change="onPageSizeChanged()" aria-label="Page Size"/>
                 </div>
                 <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">
diff --git a/traffic_portal/app/src/modules/private/cdns/deliveryServices/index.js b/traffic_portal/app/src/modules/private/cdns/deliveryServices/index.js
index c11c814..64b8fc3 100644
--- a/traffic_portal/app/src/modules/private/cdns/deliveryServices/index.js
+++ b/traffic_portal/app/src/modules/private/cdns/deliveryServices/index.js
@@ -32,6 +32,15 @@ module.exports = angular.module('trafficPortal.private.cdns.deliveryServices', [
 							},
 							deliveryServices: function($stateParams, deliveryServiceService) {
 								return deliveryServiceService.getDeliveryServices({ cdn: $stateParams.cdnId });
+							},
+							filter: function(cdn) {
+								return {
+									cdnName: {
+										filterType: "text",
+										type: "equals",
+										filter: cdn.name
+									}
+								}
 							}
 						}
 					}
diff --git a/traffic_portal/app/src/modules/private/deliveryServices/list/index.js b/traffic_portal/app/src/modules/private/deliveryServices/list/index.js
index b0eaf32..b81c926 100644
--- a/traffic_portal/app/src/modules/private/deliveryServices/list/index.js
+++ b/traffic_portal/app/src/modules/private/deliveryServices/list/index.js
@@ -27,8 +27,14 @@ module.exports = angular.module('trafficPortal.private.deliveryServices.list', [
                         templateUrl: 'common/modules/table/deliveryServices/table.deliveryServices.tpl.html',
                         controller: 'TableDeliveryServicesController',
                         resolve: {
+                            tableName: function() {
+                                return 'ds';
+                            },
                             deliveryServices: function(deliveryServiceService) {
                                 return deliveryServiceService.getDeliveryServices();
+                            },
+                            filter: function() {
+                                return null;
                             }
                         }
                     }
diff --git a/traffic_portal/app/src/modules/private/profiles/deliveryServices/index.js b/traffic_portal/app/src/modules/private/profiles/deliveryServices/index.js
index 9057e3f..04ad1d6 100644
--- a/traffic_portal/app/src/modules/private/profiles/deliveryServices/index.js
+++ b/traffic_portal/app/src/modules/private/profiles/deliveryServices/index.js
@@ -32,6 +32,15 @@ module.exports = angular.module('trafficPortal.private.profiles.deliveryServices
 							},
 							deliveryServices: function($stateParams, deliveryServiceService) {
 								return deliveryServiceService.getDeliveryServices({ profile: $stateParams.profileId });
+							},
+							filter: function(profile) {
+								return {
+									profileName: {
+										filterType: "text",
+										type: "equals",
+										filter: profile.name
+									}
+								}
 							}
 						}
 					}
diff --git a/traffic_portal/app/src/modules/private/servers/deliveryServices/index.js b/traffic_portal/app/src/modules/private/servers/deliveryServices/index.js
index a3e2161..b926897 100644
--- a/traffic_portal/app/src/modules/private/servers/deliveryServices/index.js
+++ b/traffic_portal/app/src/modules/private/servers/deliveryServices/index.js
@@ -32,6 +32,9 @@ module.exports = angular.module('trafficPortal.private.servers.deliveryServices'
 							},
 							deliveryServices: function($stateParams, deliveryServiceService) {
 								return deliveryServiceService.getServerDeliveryServices($stateParams.serverId);
+							},
+							filter: function() {
+								return null;
 							}
 						}
 					}
diff --git a/traffic_portal/app/src/modules/private/serviceCategories/deliveryServices/index.js b/traffic_portal/app/src/modules/private/serviceCategories/deliveryServices/index.js
index ac93794..49733cb 100644
--- a/traffic_portal/app/src/modules/private/serviceCategories/deliveryServices/index.js
+++ b/traffic_portal/app/src/modules/private/serviceCategories/deliveryServices/index.js
@@ -32,6 +32,15 @@ module.exports = angular.module('trafficPortal.private.serviceCategories.deliver
 							},
 							deliveryServices: function(serviceCategory, deliveryServiceService) {
 								return deliveryServiceService.getDeliveryServices({ serviceCategory: serviceCategory.name });
+							},
+							filter: function(serviceCategory) {
+								return {
+									serviceCategory: {
+										filterType: "text",
+										type: "equals",
+										filter: serviceCategory.name
+									}
+								}
 							}
 						}
 					}
diff --git a/traffic_portal/app/src/modules/private/tenants/deliveryServices/index.js b/traffic_portal/app/src/modules/private/tenants/deliveryServices/index.js
index b633ac4..c9fb4f7 100644
--- a/traffic_portal/app/src/modules/private/tenants/deliveryServices/index.js
+++ b/traffic_portal/app/src/modules/private/tenants/deliveryServices/index.js
@@ -35,6 +35,18 @@ module.exports = angular.module('trafficPortal.private.tenants.deliveryServices'
 									return deliveryServiceService.getDeliveryServices({ accessibleTo: tenant.id });
 								}
 								return deliveryServiceService.getDeliveryServices({ tenant: tenant.id });
+							},
+							filter: function($stateParams, tenant) {
+								if ($stateParams.all && $stateParams.all === 'true') {
+									return null;
+								}
+								return {
+									tenant: {
+										filterType: "text",
+										type: "equals",
+										filter: tenant.name
+									}
+								}
 							}
 						}
 					}
diff --git a/traffic_portal/app/src/modules/private/topologies/deliveryServices/index.js b/traffic_portal/app/src/modules/private/topologies/deliveryServices/index.js
index 80aa1a2..c3ffbc3 100644
--- a/traffic_portal/app/src/modules/private/topologies/deliveryServices/index.js
+++ b/traffic_portal/app/src/modules/private/topologies/deliveryServices/index.js
@@ -32,6 +32,15 @@ module.exports = angular.module('trafficPortal.private.topologies.deliveryServic
 							},
 							deliveryServices: function(topologies, deliveryServiceService) {
 								return deliveryServiceService.getDeliveryServices({ topology: topologies[0].name });
+							},
+							filter: function(topologies) {
+								return {
+									topology: {
+										filterType: "text",
+										type: "equals",
+										filter: topologies[0].name
+									}
+								}
 							}
 						}
 					}
diff --git a/traffic_portal/app/src/modules/private/types/deliveryServices/index.js b/traffic_portal/app/src/modules/private/types/deliveryServices/index.js
index 3e22d00..157194b 100644
--- a/traffic_portal/app/src/modules/private/types/deliveryServices/index.js
+++ b/traffic_portal/app/src/modules/private/types/deliveryServices/index.js
@@ -32,6 +32,15 @@ module.exports = angular.module('trafficPortal.private.types.deliveryServices',
 							},
 							deliveryServices: function($stateParams, deliveryServiceService) {
 								return deliveryServiceService.getDeliveryServices({ type: $stateParams.typeId });
+							},
+							filter: function(type) {
+								return {
+									type: {
+										filterType: "text",
+										type: "equals",
+										filter: type.name
+									}
+								}
 							}
 						}
 					}
diff --git a/traffic_portal/test/end_to_end/deliveryServices/delivery-services-spec.js b/traffic_portal/test/end_to_end/deliveryServices/delivery-services-spec.js
index ce273a9..e52d96b 100644
--- a/traffic_portal/test/end_to_end/deliveryServices/delivery-services-spec.js
+++ b/traffic_portal/test/end_to_end/deliveryServices/delivery-services-spec.js
@@ -54,7 +54,6 @@ describe('Traffic Portal Delivery Services Suite', function() {
 		staticDNShostName: "static-dns-xml-id-" + commonFunctions.shuffle('abcdefghijklmonpqrstuvwxyz'),
 		staticDNSTTL: 0,
 		staticDNSAddress: "cdn.test.com."
-
 	};
 
 	it('should open delivery services page', function() {
@@ -63,16 +62,12 @@ describe('Traffic Portal Delivery Services Suite', function() {
 		expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/delivery-services");
 	});
 
-	it('should verify CSV link exists ', function() {
-		console.log("Verify CSV button exists");
-		expect(element(by.css('.dt-button.buttons-csv')).isPresent()).toBe(true);
-	});
-
 	// ANY_MAP delivery service
 
 	it('should click new delivery service and select ANY_MAP category from the dropdown', function() {
 		console.log('Clicked Create New and selecting ANY_MAP');
-		browser.driver.findElement(by.name('createDeliveryServiceButton')).click();
+		pageData.moreBtn.click();
+		pageData.createDSMenuItem.click();
 		expect(pageData.selectFormSubmitButton.isEnabled()).toBe(false);
 		browser.driver.findElement(by.name('selectFormDropdown')).sendKeys('ANY_MAP');
 		expect(pageData.selectFormSubmitButton.isEnabled()).toBe(true);
@@ -103,40 +98,29 @@ describe('Traffic Portal Delivery Services Suite', function() {
 		// all required fields have been set, create button should be enabled
 		expect(pageData.createButton.isEnabled()).toBe(true);
 		pageData.createButton.click();
-
-		browser.wait(ec.presenceOf(element(by.className("alert"))), 5000);
-		browser.wait(ec.presenceOf(element(by.className("alert-success"))), 5000);
-	});
-
-	it('should back out to delivery services page and verify the new ANY_MAP delivery service and update it', function() {
-		console.log('Verifying that ' + mockVals.anyMapXmlId + ' exists');
-		browser.setLocation("delivery-services");
-		expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/delivery-services");
+		browser.sleep(1000);
+		expect($('div.alert-success').isDisplayed()).toBe(true);
 	});
 
 	it('should toggle the visibility of the first table column ', function() {
-		console.log("Toggle visibilty of first column");
+		console.log("Toggling visiblity of column");
+		browser.setLocation("delivery-services");
+		browser.sleep(1000);
 		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);
-		element.all(by.id("deliveryServicesTable")).then(function() {
-			let tableColumns = element.all(by.css('#deliveryServicesTable tr:first-child th'));
-			expect(tableColumns.count()).toBe(11);
-		});
+		let tableColumns = element.all(by.css('.ag-header-cell'));
+		expect(tableColumns.count()).toBe(9);
 	});
 
-	it('should update the ANY_MAP delivery service', function() {
+	it('should verify the new ANY_MAP delivery service and update it', function() {
 		console.log('Updating the ANY_MAP delivery service for ' + mockVals.anyMapXmlId);
-		pageData.searchFilter.clear().then(function() {
-			pageData.searchFilter.sendKeys(mockVals.anyMapXmlId);
-		});
-		element.all(by.repeater('ds in ::deliveryServices')).filter(function(row){
-			return row.element(by.name('xmlId')).getText().then(function(val){
-				return val.toString() === mockVals.anyMapXmlId.toString();
-			});
-		}).get(0).click();
+		browser.sleep(1000);
+		let row = element(by.cssContainingText('.ag-cell', mockVals.anyMapXmlId));
+		browser.actions().click(row).perform();
+		browser.sleep(1000);
 		expect(pageData.updateButton.isEnabled()).toBe(false);
 		expect(pageData.xmlId.getAttribute('readonly')).toBe('true');
 		pageData.displayName.clear().then(function() {
@@ -147,11 +131,12 @@ describe('Traffic Portal Delivery Services Suite', function() {
 		expect(pageData.displayName.getText() === "Updated display name");
 	});
 
-	it('should navigate back to the ANY_MAP delivery service and delete it', function() {
+	it('should delete the ANY_MAP delivery service', function() {
 		console.log('Deleting ' + mockVals.anyMapXmlId);
 		pageData.deleteButton.click();
 		pageData.confirmWithNameInput.sendKeys(mockVals.anyMapXmlId);
 		pageData.deletePermanentlyButton.click();
+		expect($('div.alert-success').isDisplayed()).toBe(true);
 		expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/delivery-services");
 	});
 
@@ -159,7 +144,8 @@ describe('Traffic Portal Delivery Services Suite', function() {
 
 	it('should click new delivery service and select DNS category from the dropdown', function() {
 		console.log('Clicked Create New and selecting DNS');
-		browser.driver.findElement(by.name('createDeliveryServiceButton')).click();
+		pageData.moreBtn.click();
+		pageData.createDSMenuItem.click();
 		expect(pageData.selectFormSubmitButton.isEnabled()).toBe(false);
 		browser.driver.findElement(by.name('selectFormDropdown')).sendKeys('DNS');
 		expect(pageData.selectFormSubmitButton.isEnabled()).toBe(true);
@@ -192,24 +178,17 @@ describe('Traffic Portal Delivery Services Suite', function() {
 		// all required fields have been set, create button should be enabled
 		expect(pageData.createButton.isEnabled()).toBe(true);
 		pageData.createButton.click();
-	});
-
-	it('should back out to delivery services page and verify the new DNS delivery service and update it', function() {
-		console.log('Verifying that ' + mockVals.dnsXmlId + ' exists');
-		browser.setLocation("delivery-services");
-		expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/delivery-services");
+		browser.sleep(1000);
+		expect($('div.alert-success').isDisplayed()).toBe(true);
 	});
 
 	it('should update the DNS delivery service', function() {
 		console.log('Updating the DNS delivery service for ' + mockVals.dnsXmlId);
-		pageData.searchFilter.clear().then(function() {
-			pageData.searchFilter.sendKeys(mockVals.dnsXmlId);
-		});
-		element.all(by.repeater('ds in ::deliveryServices')).filter(function(row){
-			return row.element(by.name('xmlId')).getText().then(function(val){
-				return val.toString() === mockVals.dnsXmlId.toString();
-			});
-		}).get(0).click();
+		browser.setLocation("delivery-services");
+		browser.sleep(1000);
+		let row = element(by.cssContainingText('.ag-cell', mockVals.dnsXmlId));
+		browser.actions().click(row).perform();
+		browser.sleep(1000);
 		expect(pageData.updateButton.isEnabled()).toBe(false);
 		expect(pageData.xmlId.getAttribute('readonly')).toBe('true');
 		pageData.displayName.clear().then(function() {
@@ -227,11 +206,11 @@ describe('Traffic Portal Delivery Services Suite', function() {
 		expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toMatch(commonFunctions.urlPath(browser.baseUrl)+"#!/delivery-services/[0-9]+/servers");
 		pageData.moreBtn.click();
 		expect(pageData.selectServersMenuItem.isEnabled()).toBe(true);
-		expect(pageData.selectServersMenuItem.getText() === 'Assign Servers');
 		pageData.selectServersMenuItem.click();
 		browser.wait(ec.presenceOf(pageData.selectAllCB), 5000);
 		pageData.selectAllCB.click();
 		pageData.selectFormSubmitButton.click();
+		browser.sleep(1000);
 		expect($('div.alert-success').isDisplayed()).toBe(true);
 	});
 
@@ -257,6 +236,7 @@ describe('Traffic Portal Delivery Services Suite', function() {
 		pageData.deleteButton.click();
 		pageData.confirmWithNameInput.sendKeys(mockVals.dnsXmlId);
 		pageData.deletePermanentlyButton.click();
+		expect($('div.alert-success').isDisplayed()).toBe(true);
 		expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/delivery-services");
 	});
 
@@ -264,7 +244,8 @@ describe('Traffic Portal Delivery Services Suite', function() {
 
 	it('should click new delivery service and select HTTP category from the dropdown', function() {
 		console.log('Clicked Create New and selecting HTTP');
-		browser.driver.findElement(by.name('createDeliveryServiceButton')).click();
+		pageData.moreBtn.click();
+		pageData.createDSMenuItem.click();
 		expect(pageData.selectFormSubmitButton.isEnabled()).toBe(false);
 		browser.driver.findElement(by.name('selectFormDropdown')).sendKeys('HTTP');
 		expect(pageData.selectFormSubmitButton.isEnabled()).toBe(true);
@@ -299,24 +280,17 @@ describe('Traffic Portal Delivery Services Suite', function() {
 		// set topology
 		commonFunctions.selectDropdownbyNum(pageData.topology, 1);
 		pageData.createButton.click();
-	});
-
-	it('should back out to delivery services page and verify the new HTTP delivery service and update it', function() {
-		console.log('Verifying that ' + mockVals.httpXmlId + ' exists');
-		browser.setLocation("delivery-services");
-		expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/delivery-services");
+		browser.sleep(1000);
+		expect($('div.alert-success').isDisplayed()).toBe(true);
 	});
 
 	it('should update the HTTP delivery service', function() {
 		console.log('Updating the HTTP delivery service for ' + mockVals.httpXmlId);
-		pageData.searchFilter.clear().then(function() {
-			pageData.searchFilter.sendKeys(mockVals.httpXmlId);
-		});
-		element.all(by.repeater('ds in ::deliveryServices')).filter(function(row){
-			return row.element(by.name('xmlId')).getText().then(function(val){
-				return val.toString() === mockVals.httpXmlId.toString();
-			});
-		}).get(0).click();
+		browser.setLocation("delivery-services");
+		browser.sleep(1000);
+		let row = element(by.cssContainingText('.ag-cell', mockVals.httpXmlId));
+		browser.actions().click(row).perform();
+		browser.sleep(1000);
 		expect(pageData.updateButton.isEnabled()).toBe(false);
 		expect(pageData.xmlId.getAttribute('readonly')).toBe('true');
 		pageData.displayName.clear().then(function() {
@@ -382,7 +356,8 @@ describe('Traffic Portal Delivery Services Suite', function() {
 		console.log('Clicked Create New and selecting Steering');
 		browser.setLocation("delivery-services");
 		browser.sleep(250);
-		browser.driver.findElement(by.name('createDeliveryServiceButton')).click();
+		pageData.moreBtn.click();
+		pageData.createDSMenuItem.click();
 		expect(pageData.selectFormSubmitButton.isEnabled()).toBe(false);
 		browser.driver.findElement(by.name('selectFormDropdown')).sendKeys('STEERING');
 		expect(pageData.selectFormSubmitButton.isEnabled()).toBe(true);
@@ -413,24 +388,17 @@ describe('Traffic Portal Delivery Services Suite', function() {
 		// all required fields have been set, create button should be enabled
 		expect(pageData.createButton.isEnabled()).toBe(true);
 		pageData.createButton.click();
-	});
-
-	it('should back out to delivery services page and verify the new Steering delivery service and update it', function() {
-		console.log('Verifying that ' + mockVals.steeringXmlId + ' exists');
-		browser.setLocation("delivery-services");
-		expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/delivery-services");
+		browser.sleep(1000);
+		expect($('div.alert-success').isDisplayed()).toBe(true);
 	});
 
 	it('should update the Steering delivery service', function() {
 		console.log('Updating the Steering delivery service for ' + mockVals.steeringXmlId);
-		pageData.searchFilter.clear().then(function() {
-			pageData.searchFilter.sendKeys(mockVals.steeringXmlId);
-		});
-		element.all(by.repeater('ds in ::deliveryServices')).filter(function(row){
-			return row.element(by.name('xmlId')).getText().then(function(val){
-				return val.toString() === mockVals.steeringXmlId.toString();
-			});
-		}).get(0).click();
+		browser.setLocation("delivery-services");
+		browser.sleep(1000);
+		let row = element(by.cssContainingText('.ag-cell', mockVals.steeringXmlId));
+		browser.actions().click(row).perform();
+		browser.sleep(1000);
 		expect(pageData.updateButton.isEnabled()).toBe(false);
 		expect(pageData.xmlId.getAttribute('readonly')).toBe('true');
 		pageData.displayName.clear().then(function() {
@@ -446,6 +414,7 @@ describe('Traffic Portal Delivery Services Suite', function() {
 		pageData.deleteButton.click();
 		pageData.confirmWithNameInput.sendKeys(mockVals.steeringXmlId);
 		pageData.deletePermanentlyButton.click();
+		expect($('div.alert-success').isDisplayed()).toBe(true);
 		expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/delivery-services");
 	});
 
diff --git a/traffic_portal/test/end_to_end/deliveryServices/pageData.js b/traffic_portal/test/end_to_end/deliveryServices/pageData.js
index f17a010..b673ce6 100644
--- a/traffic_portal/test/end_to_end/deliveryServices/pageData.js
+++ b/traffic_portal/test/end_to_end/deliveryServices/pageData.js
@@ -19,9 +19,10 @@
 
 module.exports = function(){
 	this.moreBtn=element(by.name('moreBtn'));
+	this.createDSMenuItem=element(by.name('createDSMenuItem'));
 	this.viewStaticCapabilitiesMenuItem=element(by.css('a[ng-click*=viewStaticDnsEntries]'));
 	this.addCapabilityBtn=element(by.name('addCapabilityBtn'));
-	this.manageServersMenuItem=element(by.css('a[ng-click*=viewServers]'));
+	this.manageServersMenuItem=element(by.css('button[ng-click*=viewServers]'));
 	this.selectServersMenuItem=element(by.name('selectServersMenuItem'));
 	this.selectAllCB=element(by.id('selectAllCB'));
 	this.dsLink=element(by.name('dsLink'));