You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by kd...@apache.org on 2018/02/09 19:25:43 UTC

[1/5] nifi-registry git commit: [NIFIREG-126] adding some polish and testing around deep links

Repository: nifi-registry
Updated Branches:
  refs/heads/master ed86f1a9a -> 1bb1e2b65


http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/services/nf-registry.api.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.api.spec.js b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.api.spec.js
index fcb8181..c544d22 100644
--- a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.api.spec.js
+++ b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.api.spec.js
@@ -39,13 +39,12 @@ var ngMoment = require('angular2-moment');
 var rxjs = require('rxjs/Rx');
 var ngCommonHttp = require('@angular/common/http');
 var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
-var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js');
 var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 var NfLoginComponent = require('nifi-registry/components/login/nf-registry-login.js');
 var NfUserLoginComponent = require('nifi-registry/components/login/dialogs/nf-registry-user-login.js');
 var nfRegistryAuthGuardService = require('nifi-registry/services/nf-registry.auth-guard.service.js');
 
-xdescribe('NfRegistry API w/ Angular testing utils', function () {
+describe('NfRegistry API w/ Angular testing utils', function () {
     var nfRegistryApi;
     var nfRegistryService;
 
@@ -80,7 +79,6 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
                 nfRegistryAuthGuardService.NfRegistryWorkflowsAdministrationAuthGuard,
                 nfRegistryAuthGuardService.NfRegistryLoginAuthGuard,
                 nfRegistryAuthGuardService.NfRegistryResourcesAuthGuard,
-                NfRegistryAuthService,
                 NfRegistryApi,
                 NfStorage,
                 {
@@ -179,28 +177,6 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
         httpMock.verify();
     }));
 
-    it('should fail to GET to load the current user.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
-        // Spy
-        spyOn(nfRegistryApi.router, 'navigateByUrl').and.callFake(function () {
-        });
-
-        // api call
-        nfRegistryApi.loadCurrentUser().subscribe(function (response) {
-            var navigateByUrlCall = nfRegistryApi.router.navigateByUrl.calls.first();
-            expect(navigateByUrlCall.args[0]).toBe('/nifi-registry/login');
-        });
-
-        // the request it made
-        req = httpMock.expectOne('/nifi-registry-api/access');
-        expect(req.request.method).toEqual('GET');
-
-        // Next, fulfill the request by transmitting a response.
-        req.flush(null, {status: 401, statusText: 'GET current user mock error'});
-
-        // Finally, assert that there are no outstanding requests.
-        httpMock.verify();
-    }));
-
     it('should GET droplet snapshot metadata.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
         // api call
         nfRegistryApi.getDropletSnapshotMetadata('flow/test').subscribe(function (response) {
@@ -292,7 +268,7 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
         nfRegistryApi.getDroplet('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc', 'flows', '2e04b4fb-9513-47bb-aa74-1ae34616bfdc').subscribe(function (response) {
             expect(response.message).toEqual('Http failure response for /nifi-registry-api/buckets/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc/flows/2e04b4fb-9513-47bb-aa74-1ae34616bfdc: 401 GET droplet mock error');
             var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
-            expect(dialogServiceCall.args[0].title).toBe('Error');
+            expect(dialogServiceCall.args[0].title).toBe('Flow Not Found');
             expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/buckets/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc/flows/2e04b4fb-9513-47bb-aa74-1ae34616bfdc: 401 GET droplet mock error');
             expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
             expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
@@ -360,18 +336,9 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
     }));
 
     it('should fail to GET all droplets across all buckets.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
-        // Spy
-        spyOn(nfRegistryApi.dialogService, 'openConfirm').and.callFake(function () {
-        });
-
         // api call
         nfRegistryApi.getDroplets().subscribe(function (response) {
             expect(response.message).toEqual('Http failure response for /nifi-registry-api/items: 401 GET droplet mock error');
-            var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
-            expect(dialogServiceCall.args[0].title).toBe('Error');
-            expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/items: 401 GET droplet mock error');
-            expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
-            expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
         });
 
         // the request it made
@@ -419,18 +386,9 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
     }));
 
     it('should fail to GET all droplets across a single bucket.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
-        // Spy
-        spyOn(nfRegistryApi.dialogService, 'openConfirm').and.callFake(function () {
-        });
-
         // api call
         nfRegistryApi.getDroplets('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc').subscribe(function (response) {
             expect(response.message).toEqual('Http failure response for /nifi-registry-api/items/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc: 401 GET droplet mock error');
-            var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
-            expect(dialogServiceCall.args[0].title).toBe('Error');
-            expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/items/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc: 401 GET droplet mock error');
-            expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
-            expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
         });
 
         // the request it made
@@ -571,15 +529,6 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
     }));
 
     it('should GET bucket by ID.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
-        // Spy
-        spyOn(nfRegistryApi.dialogService, 'openConfirm').and.callFake(function () {
-            return {
-                afterClosed: function () {
-                    return rxjs.Observable.of(true);
-                }
-            }
-        });
-
         // api call
         nfRegistryApi.getBucket('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc').subscribe(function (response) {
             expect(response.identifier).toEqual('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc');
@@ -613,7 +562,7 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
         nfRegistryApi.getBucket('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc').subscribe(function (response) {
             expect(response.message).toEqual('Http failure response for /nifi-registry-api/buckets/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc: 401 GET bucket mock error');
             var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
-            expect(dialogServiceCall.args[0].title).toBe('Error');
+            expect(dialogServiceCall.args[0].title).toBe('Bucket Not Found');
             expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/buckets/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc: 401 GET bucket mock error');
             expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
             expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
@@ -659,7 +608,7 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
         nfRegistryApi.getBuckets().subscribe(function (response) {
             expect(response.message).toEqual('Http failure response for /nifi-registry-api/buckets: 401 GET metadata mock error');
             var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
-            expect(dialogServiceCall.args[0].title).toBe('Error');
+            expect(dialogServiceCall.args[0].title).toBe('Buckets Not Found');
             expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/buckets: 401 GET metadata mock error');
             expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
             expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
@@ -676,6 +625,89 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
         httpMock.verify();
     }));
 
+    it('should PUT to update a bucket name.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // api call
+        nfRegistryApi.updateBucket('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc', 'Bucket #1').subscribe(function (response) {
+            expect(response[0].identifier).toEqual('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc');
+            expect(response[0].name).toEqual('Bucket #1');
+        });
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/buckets/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc');
+        expect(req.request.method).toEqual('PUT');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush([{
+            'identifier': '2f7f9e54-dc09-4ceb-aa58-9fe581319cdc',
+            'name': 'Bucket #1'
+        }]);
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should fail to PUT to update a bucket name.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // api call
+        nfRegistryApi.updateBucket('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc', 'Bucket #1').subscribe(function (response) {
+            expect(response.message).toEqual('Http failure response for /nifi-registry-api/buckets/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc: 401 PUT to update a bucket name mock error');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/buckets/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc');
+        expect(req.request.method).toEqual('PUT');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush('Http failure response for /nifi-registry-api/buckets/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc: 401 PUT to update a bucket name mock error', {status: 401, statusText: 'PUT to update a bucket name mock error'});
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should GET user by id.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // api call
+        nfRegistryApi.getUser('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc').subscribe(function (response) {
+            expect(response[0].identifier).toEqual('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc');
+            expect(response[0].name).toEqual('User #1');
+        });
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/tenants/users/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc');
+        expect(req.request.method).toEqual('GET');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush([{
+            'identifier': '2f7f9e54-dc09-4ceb-aa58-9fe581319cdc',
+            'name': 'User #1'
+        }]);
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should fail to GET user by id.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // Spy
+        spyOn(nfRegistryApi.dialogService, 'openConfirm').and.callFake(function () {
+        });
+
+        // api call
+        nfRegistryApi.getUser('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc').subscribe(function (response) {
+            expect(response.message).toEqual('Http failure response for /nifi-registry-api/tenants/users/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc: 401 GET user by id mock error');
+            var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
+            expect(dialogServiceCall.args[0].title).toBe('User Not Found');
+            expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/tenants/users/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc: 401 GET user by id mock error');
+            expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
+            expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/tenants/users/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc');
+        expect(req.request.method).toEqual('GET');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush('Http failure response for /nifi-registry-api/tenants/users/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc: 401 GET user by id mock error', {status: 401, statusText: 'GET user by id mock error', error: 'test'});
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
     it('should POST to add a new user.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
         // api call
         nfRegistryApi.addUser('test').subscribe(function (response) {
@@ -721,6 +753,43 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
         httpMock.verify();
     }));
 
+    it('should PUT to update a user name.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // api call
+        nfRegistryApi.updateUser('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc', 'user #1').subscribe(function (response) {
+            expect(response[0].identifier).toEqual('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc');
+            expect(response[0].name).toEqual('user #1');
+        });
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/tenants/users/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc');
+        expect(req.request.method).toEqual('PUT');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush([{
+            'identifier': '2f7f9e54-dc09-4ceb-aa58-9fe581319cdc',
+            'name': 'user #1'
+        }]);
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should fail to PUT to update a user name.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // api call
+        nfRegistryApi.updateUser('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc', 'user #1').subscribe(function (response) {
+            expect(response.message).toEqual('Http failure response for /nifi-registry-api/tenants/users/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc: 401 PUT to update a user name mock error');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/tenants/users/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc');
+        expect(req.request.method).toEqual('PUT');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush('Http failure response for /nifi-registry-api/tenants/users/2f7f9e54-dc09-4ceb-aa58-9fe581319cdc: 401 PUT to update a user name mock error', {status: 401, statusText: 'PUT to update a user name mock error'});
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
     it('should GET users.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
         // api call
         nfRegistryApi.getUsers().subscribe(function (response) {
@@ -750,7 +819,7 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
         nfRegistryApi.getUsers().subscribe(function (response) {
             expect(response.message).toEqual('Http failure response for /nifi-registry-api/tenants/users: 401 GET users mock error');
             var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
-            expect(dialogServiceCall.args[0].title).toBe('Error');
+            expect(dialogServiceCall.args[0].title).toBe('Users Not Found');
             expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/tenants/users: 401 GET users mock error');
             expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
             expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
@@ -842,7 +911,7 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
         nfRegistryApi.getUserGroups().subscribe(function (response) {
             expect(response.message).toEqual('Http failure response for /nifi-registry-api/tenants/user-groups: 401 GET user groups mock error');
             var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
-            expect(dialogServiceCall.args[0].title).toBe('Error');
+            expect(dialogServiceCall.args[0].title).toBe('Groups Not Found');
             expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/tenants/user-groups: 401 GET user groups mock error');
             expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
             expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
@@ -859,6 +928,267 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
         httpMock.verify();
     }));
 
+    it('should GET resource policies by resource identifier.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // api call
+        nfRegistryApi.getResourcePoliciesById('read', '/buckets', '123').subscribe(function (response) {
+            expect(response[0].identifier).toEqual('123');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/policies/read/buckets/123');
+        expect(req.request.method).toEqual('GET');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush([{
+            'identifier': '123'
+        }]);
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should fail to GET resource policies by resource identifier.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // Spy
+        spyOn(nfRegistryApi.dialogService, 'openConfirm').and.callFake(function () {
+        });
+
+        // api call
+        nfRegistryApi.getResourcePoliciesById('read', '/buckets', '123').subscribe(function (response) {
+            expect(response.message).toEqual('Http failure response for /nifi-registry-api/policies/read/buckets/123: 401 GET get resource policies by id mock error');
+            var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
+            expect(dialogServiceCall.args[0].title).toBe('Error');
+            expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/policies/read/buckets/123: 401 GET get resource policies by id mock error');
+            expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
+            expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/policies/read/buckets/123');
+        expect(req.request.method).toEqual('GET');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush('Http failure response for /nifi-registry-api/policies/read/buckets/123: 401 GET get resource policies by id mock error', {status: 401, statusText: 'GET get resource policies by id mock error'});
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should GET policy action resource.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // api call
+        nfRegistryApi.getPolicyActionResource('read', '/buckets').subscribe(function (response) {
+            expect(response[0].identifier).toEqual('123');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/policies/read/buckets');
+        expect(req.request.method).toEqual('GET');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush([{
+            'identifier': '123'
+        }]);
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should fail to GET policy action resource.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // Spy
+        spyOn(nfRegistryApi.dialogService, 'openConfirm').and.callFake(function () {
+        });
+
+        // api call
+        nfRegistryApi.getPolicyActionResource('read', '/buckets').subscribe(function (response) {
+            expect(response.message).toEqual('Http failure response for /nifi-registry-api/policies/read/buckets: 401 GET policy action resource mock error');
+            var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
+            expect(dialogServiceCall.args[0].title).toBe('Error');
+            expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/policies/read/buckets: 401 GET policy action resource mock error');
+            expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
+            expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/policies/read/buckets');
+        expect(req.request.method).toEqual('GET');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush('Http failure response for /nifi-registry-api/policies/read/buckets: 401 GET policy action resource mock error', {status: 401, statusText: 'GET policy action resource mock error'});
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should PUT policy action resource.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // api call
+        nfRegistryApi.putPolicyActionResource('123', 'read', '/buckets', [], []).subscribe(function (response) {
+            expect(response[0].identifier).toEqual('123');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/policies/123');
+        expect(req.request.method).toEqual('PUT');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush([{
+            'identifier': '123'
+        }]);
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should fail to PUT policy action resource.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // Spy
+        spyOn(nfRegistryApi.dialogService, 'openConfirm').and.callFake(function () {
+        });
+
+        // api call
+        nfRegistryApi.putPolicyActionResource('123', 'read', '/buckets', [], []).subscribe(function (response) {
+            expect(response.message).toEqual('Http failure response for /nifi-registry-api/policies/123: 401 PUT policy action resource mock error');
+            var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
+            expect(dialogServiceCall.args[0].title).toBe('Error');
+            expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/policies/123: 401 PUT policy action resource mock error');
+            expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
+            expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/policies/123');
+        expect(req.request.method).toEqual('PUT');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush('Http failure response for /nifi-registry-api/policies/123: 401 PUT policy action resource mock error', {status: 401, statusText: 'PUT policy action resource mock error'});
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should POST policy action resource.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // api call
+        nfRegistryApi.postPolicyActionResource('read', '/buckets', [], []).subscribe(function (response) {
+            expect(response[0].identifier).toEqual('123');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/policies');
+        expect(req.request.method).toEqual('POST');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush([{
+            'identifier': '123'
+        }]);
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should fail to POST policy action resource.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // Spy
+        spyOn(nfRegistryApi.dialogService, 'openConfirm').and.callFake(function () {
+        });
+
+        // api call
+        nfRegistryApi.postPolicyActionResource('read', '/buckets', [], []).subscribe(function (response) {
+            expect(response.message).toEqual('Http failure response for /nifi-registry-api/policies: 401 POST policy action resource mock error');
+            var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
+            expect(dialogServiceCall.args[0].title).toBe('Error');
+            expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/policies: 401 POST policy action resource mock error');
+            expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
+            expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/policies');
+        expect(req.request.method).toEqual('POST');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush('Http failure response for /nifi-registry-api/policies: 401 POST policy action resource mock error', {status: 401, statusText: 'POST policy action resource mock error'});
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should POST to login.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // api call
+        nfRegistryApi.postToLogin('username', 'password').subscribe(function (response) {
+            expect(response).toEqual('abc');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/access/token/login');
+        expect(req.request.method).toEqual('POST');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush('abc');
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should fail to POST to login.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // Spy
+        spyOn(nfRegistryApi.dialogService, 'openConfirm').and.callFake(function () {
+        });
+
+        // api call
+        nfRegistryApi.postToLogin('username', 'password').subscribe(function (response) {
+            expect(response).toEqual('');
+            var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
+            expect(dialogServiceCall.args[0].title).toBe('Error');
+            expect(dialogServiceCall.args[0].message).toBe('Please contact your System Administrator.');
+            expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
+            expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/access/token/login');
+        expect(req.request.method).toEqual('POST');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush('Http failure response for /nifi-registry-api/access/token/login: 401 POST to login mock error', {status: 401, statusText: 'POST to login mock error'});
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should GET all access policies.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // api call
+        nfRegistryApi.getPolicies().subscribe(function (response) {
+            expect(response[0].identifier).toEqual('123');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/policies');
+        expect(req.request.method).toEqual('GET');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush([
+            {
+                "identifier": "123",
+            }
+        ]);
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
+    it('should fail to GET all access policies.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
+        // api call
+        nfRegistryApi.getPolicies().subscribe(function (response) {
+            expect(response.message).toEqual('Http failure response for /nifi-registry-api/policies: 401 GET policies mock error');
+        });
+
+        // the request it made
+        req = httpMock.expectOne('/nifi-registry-api/policies');
+        expect(req.request.method).toEqual('GET');
+
+        // Next, fulfill the request by transmitting a response.
+        req.flush('Http failure response for /nifi-registry-api/policies: 401 GET policies mock error', {status: 401, statusText: 'GET policies mock error'});
+
+        // Finally, assert that there are no outstanding requests.
+        httpMock.verify();
+    }));
+
     it('should GET a user group.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
         // api call
         nfRegistryApi.getUserGroup(123).subscribe(function (response) {
@@ -888,7 +1218,7 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
         nfRegistryApi.getUserGroup(123).subscribe(function (response) {
             expect(response.message).toEqual('Http failure response for /nifi-registry-api/tenants/user-groups/123: 401 GET user groups mock error');
             var dialogServiceCall = nfRegistryApi.dialogService.openConfirm.calls.first();
-            expect(dialogServiceCall.args[0].title).toBe('Error');
+            expect(dialogServiceCall.args[0].title).toBe('Group Not Found');
             expect(dialogServiceCall.args[0].message).toBe('Http failure response for /nifi-registry-api/tenants/user-groups/123: 401 GET user groups mock error');
             expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
             expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
@@ -1033,15 +1363,12 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
     }));
 
     it('should fail to PUT to update a user group.', ngCoreTesting.inject([ngCommonHttpTesting.HttpTestingController], function (httpMock) {
-        // Spy
-        spyOn(nfRegistryApi.dialogService, 'openConfirm').and.callFake(function () {
-        });
-
         // api call
         nfRegistryApi.updateUserGroup('123', 'Group #1', [{
             identity: 'User #1',
             identifier: '9999'
         }]).subscribe(function (response) {
+            expect(response.message).toEqual('Http failure response for /nifi-registry-api/tenants/user-groups/123: 401 PUT to update a user group name mock error');
         });
 
         // the request it made
@@ -1049,7 +1376,7 @@ xdescribe('NfRegistry API w/ Angular testing utils', function () {
         expect(req.request.method).toEqual('PUT');
 
         // Next, fulfill the request by transmitting a response.
-        req.flush(null, {status: 401, statusText: 'PUT user groups mock error'});
+        req.flush('Http failure response for /nifi-registry-api/tenants/user-groups/123: 401 PUT to update a user group name mock error', {status: 401, statusText: 'PUT to update a user group name mock error'});
 
         // Finally, assert that there are no outstanding requests.
         httpMock.verify();

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth-guard.service.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth-guard.service.js b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth-guard.service.js
index a2f34f3..39a2289 100644
--- a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth-guard.service.js
+++ b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth-guard.service.js
@@ -16,15 +16,27 @@
  */
 
 var NfRegistryService = require('nifi-registry/services/nf-registry.service.js');
+var NfStorage = require('nifi-registry/services/nf-storage.service.js');
+var ngRouter = require('@angular/router');
+var fdsDialogsModule = require('@fluid-design-system/dialogs');
+var NfRegistryApi = require('nifi-registry/services/nf-registry.api.js');
 
 /**
  * NfRegistryUsersAdministrationAuthGuard constructor.
  *
- * @param nfRegistryService                 The nfRegistryService module.
+ * @param nfRegistryService         The nfRegistryService module.
+ * @param nfRegistryApi             The nfRegistryApi module.
+ * @param nfStorage                 The NfStorage module.
+ * @param router                    The angular router module.
+ * @param fdsDialogService          The FDS dialog service.
  * @constructor
  */
-function NfRegistryUsersAdministrationAuthGuard(nfRegistryService) {
+function NfRegistryUsersAdministrationAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, fdsDialogService) {
     this.nfRegistryService = nfRegistryService;
+    this.nfRegistryApi = nfRegistryApi;
+    this.nfStorage = nfStorage;
+    this.router = router;
+    this.dialogService = fdsDialogService;
 };
 
 NfRegistryUsersAdministrationAuthGuard.prototype = {
@@ -48,24 +60,54 @@ NfRegistryUsersAdministrationAuthGuard.prototype = {
         this.nfRegistryService.redirectUrl = url;
 
         // attempt kerberos authentication
-        this.nfRegistryService.api.ticketExchange().subscribe(function (jwt) {
-            self.nfRegistryService.api.loadCurrentUser().subscribe(function (currentUser) {
-                self.nfRegistryService.currentUser = currentUser;
-                if (currentUser.anonymous === false) {
-                    // render the logout button if there is a token locally
-                    if (self.nfRegistryService.nfStorage.getItem('jwt') !== null) {
-                        self.nfRegistryService.currentUser.canLogout = true;
+        this.nfRegistryApi.ticketExchange().subscribe(function (jwt) {
+            self.nfRegistryApi.loadCurrentUser().subscribe(function (currentUser) {
+                // there is no anonymous access and we don't know this user - open the login page which handles login/registration/etc
+                if (currentUser.error) {
+                    if (currentUser.error.status === 401) {
+                        self.nfStorage.removeItem('jwt');
+                        self.router.navigateByUrl('/nifi-registry/login');
                     }
+                } else {
+                    self.nfRegistryService.currentUser = currentUser;
+                    if (currentUser.anonymous === false) {
+                        // render the logout button if there is a token locally
+                        if (self.nfStorage.getItem('jwt') !== null) {
+                            self.nfRegistryService.currentUser.canLogout = true;
+                        }
 
-                    // redirect to explorer perspective if not admin
-                    if (!currentUser.resourcePermissions.anyTopLevelResource.canRead) {
-                        self.nfRegistryService.router.navigateByUrl('/nifi-registry/explorer');
+                        // redirect to explorer perspective if not admin
+                        if (!currentUser.resourcePermissions.anyTopLevelResource.canRead) {
+                            self.dialogService.openConfirm({
+                                title: 'Access denied',
+                                message: 'Please contact your system administrator.',
+                                acceptButton: 'Ok',
+                                acceptButtonColor: 'fds-warn'
+                            });
+                            self.router.navigateByUrl('/nifi-registry/explorer');
+                        } else {
+                            if (currentUser.resourcePermissions.tenants.canRead) {
+                                self.router.navigateByUrl(url);
+                            } else {
+                                self.dialogService.openConfirm({
+                                    title: 'Access denied',
+                                    message: 'Please contact your system administrator.',
+                                    acceptButton: 'Ok',
+                                    acceptButtonColor: 'fds-warn'
+                                });
+                                self.router.navigateByUrl('/nifi-registry/explorer');
+                            }
+                        }
                     } else {
-                        self.nfRegistryService.router.navigateByUrl(url);
+                        // registry security not configured, redirect to workflow perspective
+                        self.dialogService.openConfirm({
+                            title: 'Not Applicable',
+                            message: 'User administration is not configured for this registry.',
+                            acceptButton: 'Ok',
+                            acceptButtonColor: 'fds-warn'
+                        });
+                        self.router.navigateByUrl('/nifi-registry/administration/workflow');
                     }
-                } else {
-                    // navigate to the login page
-                    self.nfRegistryService.router.navigateByUrl('/nifi-registry/login');
                 }
             });
         });
@@ -75,17 +117,29 @@ NfRegistryUsersAdministrationAuthGuard.prototype = {
 };
 
 NfRegistryUsersAdministrationAuthGuard.parameters = [
-    NfRegistryService
+    NfRegistryService,
+    NfRegistryApi,
+    NfStorage,
+    ngRouter.Router,
+    fdsDialogsModule.FdsDialogService
 ];
 
 /**
  * NfRegistryWorkflowsAdministrationAuthGuard constructor.
  *
- * @param nfRegistryService                 The nfRegistryService module.
+ * @param nfRegistryService         The nfRegistryService module.
+ * @param nfRegistryApi             The nfRegistryApi module.
+ * @param nfStorage                 The NfStorage module.
+ * @param router                    The angular router module.
+ * @param fdsDialogService          The FDS dialog service.
  * @constructor
  */
-function NfRegistryWorkflowsAdministrationAuthGuard(nfRegistryService) {
+function NfRegistryWorkflowsAdministrationAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, fdsDialogService) {
     this.nfRegistryService = nfRegistryService;
+    this.nfRegistryApi = nfRegistryApi;
+    this.nfStorage = nfStorage;
+    this.router = router;
+    this.dialogService = fdsDialogService;
 };
 
 NfRegistryWorkflowsAdministrationAuthGuard.prototype = {
@@ -109,28 +163,48 @@ NfRegistryWorkflowsAdministrationAuthGuard.prototype = {
         this.nfRegistryService.redirectUrl = url;
 
         // attempt kerberos authentication
-        this.nfRegistryService.api.ticketExchange().subscribe(function (jwt) {
-            self.nfRegistryService.api.loadCurrentUser().subscribe(function (currentUser) {
-                self.nfRegistryService.currentUser = currentUser;
-                if (currentUser.anonymous === false) {
-                    // render the logout button if there is a token locally
-                    if (self.nfRegistryService.nfStorage.getItem('jwt') !== null) {
-                        self.nfRegistryService.currentUser.canLogout = true;
+        this.nfRegistryApi.ticketExchange().subscribe(function (jwt) {
+            self.nfRegistryApi.loadCurrentUser().subscribe(function (currentUser) {
+                // there is no anonymous access and we don't know this user - open the login page which handles login/registration/etc
+                if (currentUser.error) {
+                    if (currentUser.error.status === 401) {
+                        self.nfStorage.removeItem('jwt');
+                        self.router.navigateByUrl('/nifi-registry/login');
                     }
+                } else {
+                    self.nfRegistryService.currentUser = currentUser;
+                    if (currentUser.anonymous === false) {
+                        // render the logout button if there is a token locally
+                        if (self.nfStorage.getItem('jwt') !== null) {
+                            self.nfRegistryService.currentUser.canLogout = true;
+                        }
 
-                    // redirect to explorer perspective if not admin
-                    if (!currentUser.resourcePermissions.anyTopLevelResource.canRead) {
-                        self.nfRegistryService.router.navigateByUrl('/nifi-registry/explorer');
-                    } else {
-                        if (currentUser.resourcePermissions.buckets) {
-                            self.nfRegistryService.router.navigateByUrl(url);
+                        // redirect to explorer perspective if not admin
+                        if (!currentUser.resourcePermissions.anyTopLevelResource.canRead) {
+                            self.dialogService.openConfirm({
+                                title: 'Access denied',
+                                message: 'Please contact your system administrator.',
+                                acceptButton: 'Ok',
+                                acceptButtonColor: 'fds-warn'
+                            });
+                            self.router.navigateByUrl('/nifi-registry/explorer');
                         } else {
-                            self.nfRegistryService.router.navigateByUrl('/nifi-registry/administration/users');
+                            if (currentUser.resourcePermissions.buckets.canRead) {
+                                self.router.navigateByUrl(url);
+                            } else {
+                                self.dialogService.openConfirm({
+                                    title: 'Access denied',
+                                    message: 'Please contact your system administrator.',
+                                    acceptButton: 'Ok',
+                                    acceptButtonColor: 'fds-warn'
+                                });
+                                self.router.navigateByUrl('/nifi-registry/administration/users');
+                            }
                         }
+                    } else {
+                        // registry security not configured, allow access to workflow perspective
+                        self.router.navigateByUrl(url);
                     }
-                } else {
-                    // Navigate to the login page
-                    self.nfRegistryService.router.navigateByUrl(url);
                 }
             });
         });
@@ -140,17 +214,27 @@ NfRegistryWorkflowsAdministrationAuthGuard.prototype = {
 };
 
 NfRegistryWorkflowsAdministrationAuthGuard.parameters = [
-    NfRegistryService
+    NfRegistryService,
+    NfRegistryApi,
+    NfStorage,
+    ngRouter.Router,
+    fdsDialogsModule.FdsDialogService
 ];
 
 /**
  * NfRegistryLoginAuthGuard constructor.
  *
- * @param nfRegistryService                 The nfRegistryService module.
+ * @param nfRegistryService         The nfRegistryService module.
+ * @param nfRegistryApi             The nfRegistryApi module.
+ * @param nfStorage                 The NfStorage module.
+ * @param router                    The angular router module.
  * @constructor
  */
-function NfRegistryLoginAuthGuard(nfRegistryService) {
+function NfRegistryLoginAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router) {
     this.nfRegistryService = nfRegistryService;
+    this.nfRegistryApi = nfRegistryApi;
+    this.nfStorage = nfStorage;
+    this.router = router;
 };
 
 NfRegistryLoginAuthGuard.prototype = {
@@ -170,19 +254,22 @@ NfRegistryLoginAuthGuard.prototype = {
         var self = this;
         if (this.nfRegistryService.currentUser.anonymous) { return true; }
         // attempt kerberos authentication
-        this.nfRegistryService.api.ticketExchange().subscribe(function (jwt) {
-            self.nfRegistryService.api.loadCurrentUser().subscribe(function (currentUser) {
+        this.nfRegistryApi.ticketExchange().subscribe(function (jwt) {
+            self.nfRegistryApi.loadCurrentUser().subscribe(function (currentUser) {
                 self.nfRegistryService.currentUser = currentUser;
                 if (currentUser.anonymous === false) {
                     // render the logout button if there is a token locally
-                    if (self.nfRegistryService.nfStorage.getItem('jwt') !== null) {
+                    if (self.nfStorage.getItem('jwt') !== null) {
                         self.nfRegistryService.currentUser.canLogout = true;
                     }
                     self.nfRegistryService.currentUser.canActivateResourcesAuthGuard = true;
-                    self.nfRegistryService.router.navigateByUrl(self.nfRegistryService.redirectUrl);
+                    self.router.navigateByUrl(self.nfRegistryService.redirectUrl);
                 } else {
-                    self.nfRegistryService.currentUser.anonymous = true;
-                    self.nfRegistryService.router.navigateByUrl('/nifi-registry/login');
+                    if(self.nfRegistryService.currentUser.anonymous){
+                        self.router.navigateByUrl('/nifi-registry');
+                    } else {
+                        self.router.navigateByUrl(url);
+                    }
                 }
             });
         });
@@ -192,17 +279,26 @@ NfRegistryLoginAuthGuard.prototype = {
 };
 
 NfRegistryLoginAuthGuard.parameters = [
-    NfRegistryService
+    NfRegistryService,
+    NfRegistryApi,
+    NfStorage,
+    ngRouter.Router
 ];
 
 /**
  * NfRegistryResourcesAuthGuard constructor.
  *
- * @param nfRegistryService                 The nfRegistryService module.
+ * @param nfRegistryService         The nfRegistryService module.
+ * @param nfRegistryApi             The nfRegistryApi module.
+ * @param nfStorage                 The NfStorage module.
+ * @param router                    The angular router module.
  * @constructor
  */
-function NfRegistryResourcesAuthGuard(nfRegistryService) {
+function NfRegistryResourcesAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router) {
     this.nfRegistryService = nfRegistryService;
+    this.nfRegistryApi = nfRegistryApi;
+    this.nfStorage = nfStorage;
+    this.router = router;
 };
 
 NfRegistryResourcesAuthGuard.prototype = {
@@ -226,24 +322,32 @@ NfRegistryResourcesAuthGuard.prototype = {
         this.nfRegistryService.redirectUrl = url;
 
         // attempt kerberos authentication
-        this.nfRegistryService.api.ticketExchange().subscribe(function (jwt) {
-            self.nfRegistryService.api.loadCurrentUser().subscribe(function (currentUser) {
-                self.nfRegistryService.currentUser = currentUser;
-                if (!currentUser || currentUser.anonymous === false) {
-                    if(self.nfRegistryService.nfStorage.hasItem('jwt')){
-                        self.nfRegistryService.currentUser.canLogout = true;
-                        self.nfRegistryService.currentUser.canActivateResourcesAuthGuard = true;
-                        self.nfRegistryService.router.navigateByUrl(url);
-                    } else {
-                        self.nfRegistryService.router.navigateByUrl('/nifi-registry/login');
+        this.nfRegistryApi.ticketExchange().subscribe(function (jwt) {
+            self.nfRegistryApi.loadCurrentUser().subscribe(function (currentUser) {
+                // there is no anonymous access and we don't know this user - open the login page which handles login/registration/etc
+                if (currentUser.error) {
+                    if (currentUser.error.status === 401) {
+                        self.nfStorage.removeItem('jwt');
+                        self.router.navigateByUrl('/nifi-registry/login');
                     }
-                } else if (currentUser.anonymous === true) {
-                    // render the logout button if there is a token locally
-                    if (self.nfRegistryService.nfStorage.getItem('jwt') !== null) {
-                        self.nfRegistryService.currentUser.canLogout = true;
+                } else {
+                    self.nfRegistryService.currentUser = currentUser;
+                    if (!currentUser || currentUser.anonymous === false) {
+                        if(self.nfStorage.hasItem('jwt')){
+                            self.nfRegistryService.currentUser.canLogout = true;
+                            self.nfRegistryService.currentUser.canActivateResourcesAuthGuard = true;
+                            self.router.navigateByUrl(url);
+                        } else {
+                            self.router.navigateByUrl('/nifi-registry/login');
+                        }
+                    } else if (currentUser.anonymous === true) {
+                        // render the logout button if there is a token locally
+                        if (self.nfStorage.getItem('jwt') !== null) {
+                            self.nfRegistryService.currentUser.canLogout = true;
+                        }
+                        self.nfRegistryService.currentUser.canActivateResourcesAuthGuard = true;
+                        self.router.navigateByUrl(url);
                     }
-                    self.nfRegistryService.currentUser.canActivateResourcesAuthGuard = true;
-                    self.nfRegistryService.router.navigateByUrl(url);
                 }
             });
         });
@@ -253,7 +357,10 @@ NfRegistryResourcesAuthGuard.prototype = {
 };
 
 NfRegistryResourcesAuthGuard.parameters = [
-    NfRegistryService
+    NfRegistryService,
+    NfRegistryApi,
+    NfStorage,
+    ngRouter.Router
 ];
 
 module.exports = {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth-guard.service.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth-guard.service.spec.js b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth-guard.service.spec.js
new file mode 100644
index 0000000..211f257
--- /dev/null
+++ b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth-guard.service.spec.js
@@ -0,0 +1,629 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the 'License'); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var nfRegistryAuthGuardService = require('nifi-registry/services/nf-registry.auth-guard.service.js');
+var NfRegistryService = require('nifi-registry/services/nf-registry.service.js');
+var NfStorage = require('nifi-registry/services/nf-storage.service.js');
+var rxjs = require('rxjs/Rx');
+
+describe('NfRegistry Auth Guard Service NfRegistryResourcesAuthGuard isolated unit tests', function () {
+    var nfRegistryService;
+    var nfRegistryUsersAdministrationAuthGuard;
+    var nfRegistryWorkflowsAdministrationAuthGuard;
+    var nfRegistryLoginAuthGuard;
+    var nfRegistryResourcesAuthGuard;
+    var nfRegistryApi;
+    var nfStorage;
+    var router;
+    var dialogService;
+
+    beforeEach(function () {
+        router = {
+            navigateByUrl: function () {
+            }
+        };
+        dialogService = {
+            openConfirm: function () {
+            }
+        };
+        nfRegistryApi = {
+            ticketExchange: function () {
+            },
+            loadCurrentUser: function () {
+            }
+        };
+        nfStorage = new NfStorage();
+        nfRegistryService = new NfRegistryService(nfRegistryApi, nfStorage, {}, router, dialogService, {});
+
+        // Spy
+        spyOn(router, 'navigateByUrl');
+        spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(dialogService, 'openConfirm');
+    });
+
+    it('should navigate to test url (registry security not configured) ', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: true
+        }));
+        spyOn(nfStorage, 'getItem').and.callFake(function () {
+        }).and.returnValue(true);
+
+        nfRegistryResourcesAuthGuard = new nfRegistryAuthGuardService.NfRegistryResourcesAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router);
+
+        // The function to test
+        nfRegistryResourcesAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.currentUser.canLogout).toBe(true);
+        expect(nfRegistryService.currentUser.canActivateResourcesAuthGuard).toBe(true);
+        expect(nfRegistryService.currentUser.anonymous).toBe(true);
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('test');
+    });
+
+    it('should navigate to test url (registry security configured and we know who you are) ', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: false
+        }));
+        spyOn(nfStorage, 'hasItem').and.callFake(function () {
+        }).and.returnValue(true);
+
+        nfRegistryResourcesAuthGuard = new nfRegistryAuthGuardService.NfRegistryResourcesAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router);
+
+        // The function to test
+        nfRegistryResourcesAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.currentUser.canLogout).toBe(true);
+        expect(nfRegistryService.currentUser.canActivateResourcesAuthGuard).toBe(true);
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('test');
+    });
+
+    it('should navigate to login', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: false
+        }));
+
+        nfRegistryResourcesAuthGuard = new nfRegistryAuthGuardService.NfRegistryResourcesAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router);
+
+        // The function to test
+        nfRegistryResourcesAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('/nifi-registry/login');
+    });
+
+    it('should navigate to login (error loading current user)', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            error: {
+                status: 401
+            }
+        }));
+        spyOn(nfStorage, 'removeItem');
+
+        nfRegistryResourcesAuthGuard = new nfRegistryAuthGuardService.NfRegistryResourcesAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, dialogService);
+
+        // The function to test
+        nfRegistryResourcesAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfStorage.removeItem).toHaveBeenCalled();
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('/nifi-registry/login');
+    });
+});
+
+describe('NfRegistry Auth Guard Service NfRegistryLoginAuthGuard isolated unit tests', function () {
+    var nfRegistryService;
+    var nfRegistryUsersAdministrationAuthGuard;
+    var nfRegistryWorkflowsAdministrationAuthGuard;
+    var nfRegistryLoginAuthGuard;
+    var nfRegistryResourcesAuthGuard;
+    var nfRegistryApi;
+    var nfStorage;
+    var router;
+    var dialogService;
+
+    beforeEach(function () {
+        router = {
+            navigateByUrl: function () {
+            }
+        };
+        dialogService = {
+            openConfirm: function () {
+            }
+        };
+        nfRegistryApi = {
+            ticketExchange: function () {
+            },
+            loadCurrentUser: function () {
+            }
+        };
+        nfStorage = new NfStorage();
+        nfRegistryService = new NfRegistryService(nfRegistryApi, nfStorage, {}, router, dialogService, {});
+
+        // Spy
+        spyOn(router, 'navigateByUrl');
+        spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(dialogService, 'openConfirm');
+    });
+
+    it('should navigate to base nifi-registry url', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: true
+        }));
+        nfRegistryLoginAuthGuard = new nfRegistryAuthGuardService.NfRegistryLoginAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router);
+
+        // The function to test
+        nfRegistryLoginAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.currentUser.anonymous).toBe(true);
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('/nifi-registry');
+    });
+
+    it('should navigate to test url', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: false
+        }));
+        nfRegistryLoginAuthGuard = new nfRegistryAuthGuardService.NfRegistryLoginAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router);
+
+        // The function to test
+        nfRegistryLoginAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.currentUser.canActivateResourcesAuthGuard).toBe(true);
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('/nifi-registry/explorer/grid-list');
+    });
+});
+
+describe('NfRegistry Auth Guard Service NfRegistryUsersAdministrationAuthGuard isolated unit tests', function () {
+    var nfRegistryService;
+    var nfRegistryUsersAdministrationAuthGuard;
+    var nfRegistryWorkflowsAdministrationAuthGuard;
+    var nfRegistryLoginAuthGuard;
+    var nfRegistryResourcesAuthGuard;
+    var nfRegistryApi;
+    var nfStorage;
+    var router;
+    var dialogService;
+
+    beforeEach(function () {
+        router = {
+            navigateByUrl: function () {
+            }
+        };
+        dialogService = {
+            openConfirm: function () {
+            }
+        };
+        nfRegistryApi = {
+            ticketExchange: function () {
+            },
+            loadCurrentUser: function () {
+            }
+        };
+        nfStorage = new NfStorage();
+        nfRegistryService = new NfRegistryService(nfRegistryApi, nfStorage, {}, router, dialogService, {});
+
+        // Spy
+        spyOn(router, 'navigateByUrl');
+        spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(dialogService, 'openConfirm');
+    });
+
+    it('should navigate to login', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            error: {
+                status: 401
+            }
+        }));
+        nfRegistryUsersAdministrationAuthGuard = new nfRegistryAuthGuardService.NfRegistryUsersAdministrationAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, dialogService);
+
+        // The function to test
+        nfRegistryUsersAdministrationAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.redirectUrl).toBe('test');
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('/nifi-registry/login');
+    });
+
+    it('should deny access (registry security not configured) and navigate to administration workflow perspective', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: true
+        }));
+        nfRegistryUsersAdministrationAuthGuard = new nfRegistryAuthGuardService.NfRegistryUsersAdministrationAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, dialogService);
+
+        // The function to test
+        nfRegistryUsersAdministrationAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.redirectUrl).toBe('test');
+        var dialogServiceCall = dialogService.openConfirm.calls.first();
+        expect(dialogServiceCall.args[0].title).toBe('Not Applicable');
+        expect(dialogServiceCall.args[0].message).toBe('User administration is not configured for this registry.');
+        expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
+        expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('/nifi-registry/administration/workflow');
+    });
+
+    it('should deny access (non-admin) and navigate to explorer perspective', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: false,
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        nfRegistryUsersAdministrationAuthGuard = new nfRegistryAuthGuardService.NfRegistryUsersAdministrationAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, dialogService);
+
+        // The function to test
+        nfRegistryUsersAdministrationAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.redirectUrl).toBe('test');
+        var dialogServiceCall = dialogService.openConfirm.calls.first();
+        expect(dialogServiceCall.args[0].title).toBe('Access denied');
+        expect(dialogServiceCall.args[0].message).toBe('Please contact your system administrator.');
+        expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
+        expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('/nifi-registry/explorer');
+    });
+
+    it('should deny access (no tenants permissions) and navigate to explorer perspective', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: false,
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: true,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        nfRegistryUsersAdministrationAuthGuard = new nfRegistryAuthGuardService.NfRegistryUsersAdministrationAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, dialogService);
+
+        // The function to test
+        nfRegistryUsersAdministrationAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.redirectUrl).toBe('test');
+        var dialogServiceCall = dialogService.openConfirm.calls.first();
+        expect(dialogServiceCall.args[0].title).toBe('Access denied');
+        expect(dialogServiceCall.args[0].message).toBe('Please contact your system administrator.');
+        expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
+        expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('/nifi-registry/explorer');
+    });
+
+    it('should deny access (no tenants permissions) and navigate to test url', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: false,
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: true,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: true,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        nfRegistryUsersAdministrationAuthGuard = new nfRegistryAuthGuardService.NfRegistryUsersAdministrationAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, dialogService);
+
+        // The function to test
+        nfRegistryUsersAdministrationAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.redirectUrl).toBe('test');
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('test');
+    });
+});
+
+describe('NfRegistry Auth Guard Service NfRegistryWorkflowsAdministrationAuthGuard isolated unit tests', function () {
+    var nfRegistryService;
+    var nfRegistryUsersAdministrationAuthGuard;
+    var nfRegistryWorkflowsAdministrationAuthGuard;
+    var nfRegistryLoginAuthGuard;
+    var nfRegistryResourcesAuthGuard;
+    var nfRegistryApi;
+    var nfStorage;
+    var router;
+    var dialogService;
+
+    beforeEach(function () {
+        router = {
+            navigateByUrl: function () {
+            }
+        };
+        dialogService = {
+            openConfirm: function () {
+            }
+        };
+        nfRegistryApi = {
+            ticketExchange: function () {
+            },
+            loadCurrentUser: function () {
+            }
+        };
+        nfStorage = new NfStorage();
+        nfRegistryService = new NfRegistryService(nfRegistryApi, nfStorage, {}, router, dialogService, {});
+
+        // Spy
+        spyOn(router, 'navigateByUrl');
+        spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(dialogService, 'openConfirm');
+    });
+
+    it('should navigate to login', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            error: {
+                status: 401
+            }
+        }));
+        nfRegistryWorkflowsAdministrationAuthGuard = new nfRegistryAuthGuardService.NfRegistryWorkflowsAdministrationAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, dialogService);
+
+        // The function to test
+        nfRegistryWorkflowsAdministrationAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.redirectUrl).toBe('test');
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('/nifi-registry/login');
+    });
+
+    it('should (registry security not configured) navigate to test url', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: true
+        }));
+        nfRegistryWorkflowsAdministrationAuthGuard = new nfRegistryAuthGuardService.NfRegistryWorkflowsAdministrationAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, dialogService);
+
+        // The function to test
+        nfRegistryWorkflowsAdministrationAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.redirectUrl).toBe('test');
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('test');
+    });
+
+    it('should deny access (non-admin) and navigate to explorer perspective', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: false,
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        nfRegistryWorkflowsAdministrationAuthGuard = new nfRegistryAuthGuardService.NfRegistryWorkflowsAdministrationAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, dialogService);
+
+        // The function to test
+        nfRegistryWorkflowsAdministrationAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.redirectUrl).toBe('test');
+        var dialogServiceCall = dialogService.openConfirm.calls.first();
+        expect(dialogServiceCall.args[0].title).toBe('Access denied');
+        expect(dialogServiceCall.args[0].message).toBe('Please contact your system administrator.');
+        expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
+        expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('/nifi-registry/explorer');
+    });
+
+    it('should deny access (no buckets permissions) and navigate to users administration perspective', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: false,
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: true,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        nfRegistryWorkflowsAdministrationAuthGuard = new nfRegistryAuthGuardService.NfRegistryWorkflowsAdministrationAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, dialogService);
+
+        // The function to test
+        nfRegistryWorkflowsAdministrationAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.redirectUrl).toBe('test');
+        var dialogServiceCall = dialogService.openConfirm.calls.first();
+        expect(dialogServiceCall.args[0].title).toBe('Access denied');
+        expect(dialogServiceCall.args[0].message).toBe('Please contact your system administrator.');
+        expect(dialogServiceCall.args[0].acceptButton).toBe('Ok');
+        expect(dialogServiceCall.args[0].acceptButtonColor).toBe('fds-warn');
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('/nifi-registry/administration/users');
+    });
+
+    it('should deny access (no tenants permissions) and navigate to test url', function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            anonymous: false,
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: true,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: true,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        nfRegistryWorkflowsAdministrationAuthGuard = new nfRegistryAuthGuardService.NfRegistryWorkflowsAdministrationAuthGuard(nfRegistryService, nfRegistryApi, nfStorage, router, dialogService);
+
+        // The function to test
+        nfRegistryWorkflowsAdministrationAuthGuard.canActivate({}, {url: 'test'});
+
+        //assertions
+        expect(nfRegistryService.redirectUrl).toBe('test');
+        var navigateByUrlCall = router.navigateByUrl.calls.first();
+        expect(navigateByUrlCall.args[0]).toBe('test');
+    });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth.service.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth.service.js b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth.service.js
deleted file mode 100644
index f2f143d..0000000
--- a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.auth.service.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var NfStorage = require('nifi-registry/services/nf-storage.service.js');
-
-/**
- * NfRegistryAuth constructor.
- *
- * @param nfStorage             The NfStorage module.
- * @constructor
- */
-function NfRegistryAuth(nfStorage) {
-    this.nfStorage = nfStorage;
-};
-
-NfRegistryAuth.prototype = {
-    constructor: NfRegistryAuth,
-
-    /**
-     * Gets the jwt token.
-     * @returns {*}
-     */
-    getToken: function () {
-        return this.nfStorage.getItem('jwt');
-    }
-};
-
-NfRegistryAuth.parameters = [
-    NfStorage
-];
-
-module.exports = NfRegistryAuth;

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.js b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.js
index e6b2b79..3e6bc6a 100644
--- a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.js
+++ b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.js
@@ -810,31 +810,6 @@ NfRegistryService.prototype = {
     },
 
     /**
-     * Loads the current user and updates the current user locally.
-     *
-     * @returns xhr
-     */
-    loadCurrentUser: function () {
-        var self = this;
-        // get the current user
-        return rxjs.Observable.of(this.api.loadCurrentUser().subscribe(function (currentUser) {
-            // if the user is logged, we want to determine if they were logged in using a certificate
-            if (currentUser.anonymous === false) {
-                // render the users name
-                self.currentUser = currentUser;
-
-                // render the logout button if there is a token locally
-                if (self.nfStorage.getItem('jwt') !== null) {
-                    self.currentUser.canLogout = true;
-                }
-            } else {
-                // set the anonymous user label
-                self.nfRegistryService.currentUser.identity = 'Anonymous';
-            }
-        }));
-    },
-
-    /**
      * Adds a `searchTerm` to the `usersSearchTerms` and filters the `users` amd `groups`.
      *
      * @param {string} searchTerm   The search term to add.

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.spec.js b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.spec.js
index 054bf86..1341abd 100644
--- a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.spec.js
+++ b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.spec.js
@@ -41,7 +41,6 @@ var fdsDialogsModule = require('@fluid-design-system/dialogs');
 var ngRouter = require('@angular/router');
 var ngCommonHttp = require('@angular/common/http');
 var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
-var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js');
 var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 var NfLoginComponent = require('nifi-registry/components/login/nf-registry-login.js');
 var NfUserLoginComponent = require('nifi-registry/components/login/dialogs/nf-registry-user-login.js');
@@ -707,7 +706,6 @@ describe('NfRegistry Service w/ Angular testing utils', function () {
             ],
             providers: [
                 NfRegistryService,
-                NfRegistryAuthService,
                 NfRegistryApi,
                 NfStorage,
                 {
@@ -733,7 +731,7 @@ describe('NfRegistry Service w/ Angular testing utils', function () {
         });
         spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {
         }).and.returnValue(rxjs.Observable.of({}));
-        spyOn(nfRegistryService, 'loadCurrentUser').and.callFake(function () {
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
         }).and.returnValue(rxjs.Observable.of({}));
     });
 

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/services/nf-registry.token.interceptor.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.token.interceptor.js b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.token.interceptor.js
index e1abb95..cc2f703 100644
--- a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.token.interceptor.js
+++ b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.token.interceptor.js
@@ -15,14 +15,16 @@
  * limitations under the License.
  */
 
-var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js');
+var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 
 /**
  * NfRegistryTokenInterceptor constructor.
+ *
+ * @param nfStorage             The NfStorage module.
  * @constructor
  */
-function NfRegistryTokenInterceptor(nfRegistryAuthService) {
-    this.auth = nfRegistryAuthService;
+function NfRegistryTokenInterceptor(nfStorage) {
+    this.nfStorage = nfStorage;
 };
 
 NfRegistryTokenInterceptor.prototype = {
@@ -36,7 +38,7 @@ NfRegistryTokenInterceptor.prototype = {
      * @returns {Observable HTTPEvent}
      */
     intercept: function(request, next) {
-        var token = this.auth.getToken();
+        var token = this.nfStorage.getItem('jwt');
         if(token) {
             request = request.clone({headers: request.headers.set('Authorization', 'Bearer ' + token)});
         }
@@ -44,6 +46,8 @@ NfRegistryTokenInterceptor.prototype = {
     }
 };
 
-NfRegistryTokenInterceptor.parameters = [NfRegistryAuthService];
+NfRegistryTokenInterceptor.parameters = [
+    NfStorage
+];
 
 module.exports = NfRegistryTokenInterceptor;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/systemjs.builder.config.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/systemjs.builder.config.js b/nifi-registry-web-ui/src/main/webapp/systemjs.builder.config.js
index e181ec6..fda4f9f 100644
--- a/nifi-registry-web-ui/src/main/webapp/systemjs.builder.config.js
+++ b/nifi-registry-web-ui/src/main/webapp/systemjs.builder.config.js
@@ -98,7 +98,6 @@
             'nifi-registry/services/nf-registry.api.js': 'services/nf-registry.api.js',
             'nifi-registry/services/nf-registry.service.js': 'services/nf-registry.service.js',
             'nifi-registry/services/nf-storage.service.js': 'services/nf-storage.service.js',
-            'nifi-registry/services/nf-registry.auth.service.js': 'services/nf-registry.auth.service.js',
             'nifi-registry/services/nf-registry.auth-guard.service.js': 'services/nf-registry.auth-guard.service.js',
             'nifi-registry/services/nf-registry.token.interceptor.js': 'services/nf-registry.token.interceptor.js',
             'nifi-registry/components/page-not-found/nf-registry-page-not-found.js': 'components/page-not-found/nf-registry-page-not-found.js',


[2/5] nifi-registry git commit: [NIFIREG-126] adding some polish and testing around deep links

Posted by kd...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.spec.js b/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.spec.js
new file mode 100644
index 0000000..e27da78
--- /dev/null
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.spec.js
@@ -0,0 +1,766 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the 'License'); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var NfRegistryRoutes = require('nifi-registry/nf-registry.routes.js');
+var ngCoreTesting = require('@angular/core/testing');
+var ngCommon = require('@angular/common');
+var ngRouter = require('@angular/router');
+var NfRegistry = require('nifi-registry/nf-registry.js');
+var NfRegistryApi = require('nifi-registry/services/nf-registry.api.js');
+var NfRegistryService = require('nifi-registry/services/nf-registry.service.js');
+var NfPageNotFoundComponent = require('nifi-registry/components/page-not-found/nf-registry-page-not-found.js');
+var NfRegistryExplorer = require('nifi-registry/components/explorer/nf-registry-explorer.js');
+var NfRegistryAdministration = require('nifi-registry/components/administration/nf-registry-administration.js');
+var NfRegistryUsersAdministration = require('nifi-registry/components/administration/users/nf-registry-users-administration.js');
+var NfRegistryAddUser = require('nifi-registry/components/administration/users/dialogs/add-user/nf-registry-add-user.js');
+var NfRegistryCreateNewGroup = require('nifi-registry/components/administration/users/dialogs/create-new-group/nf-registry-create-new-group.js');
+var NfRegistryEditBucketPolicy = require('nifi-registry/components/administration/workflow/dialogs/edit-bucket-policy/nf-registry-edit-bucket-policy.js');
+var NfRegistryAddPolicyToBucket = require('nifi-registry/components/administration/workflow/dialogs/add-policy-to-bucket/nf-registry-add-policy-to-bucket.js');
+var NfRegistryAddUserToGroups = require('nifi-registry/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.js');
+var NfRegistryAddUsersToGroup = require('nifi-registry/components/administration/users/dialogs/add-users-to-group/nf-registry-add-users-to-group.js');
+var NfRegistryManageUser = require('nifi-registry/components/administration/users/sidenav/manage-user/nf-registry-manage-user.js');
+var NfRegistryManageGroup = require('nifi-registry/components/administration/users/sidenav/manage-group/nf-registry-manage-group.js');
+var NfRegistryManageBucket = require('nifi-registry/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.js');
+var NfRegistryWorkflowAdministration = require('nifi-registry/components/administration/workflow/nf-registry-workflow-administration.js');
+var NfRegistryCreateBucket = require('nifi-registry/components/administration/workflow/dialogs/create-bucket/nf-registry-create-bucket.js');
+var NfRegistryGridListViewer = require('nifi-registry/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.js');
+var NfRegistryBucketGridListViewer = require('nifi-registry/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.js');
+var NfRegistryDropletGridListViewer = require('nifi-registry/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.js');
+var fdsCore = require('@fluid-design-system/core');
+var ngMoment = require('angular2-moment');
+var rxjs = require('rxjs/Rx');
+var ngCommonHttp = require('@angular/common/http');
+var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
+var NfStorage = require('nifi-registry/services/nf-storage.service.js');
+var NfLoginComponent = require('nifi-registry/components/login/nf-registry-login.js');
+var NfUserLoginComponent = require('nifi-registry/components/login/dialogs/nf-registry-user-login.js');
+
+describe('NfRegistryManageBucket Component', function () {
+    var comp;
+    var fixture;
+    var nfRegistryService;
+    var nfRegistryApi;
+
+    beforeEach(function () {
+        ngCoreTesting.TestBed.configureTestingModule({
+            imports: [
+                ngMoment.MomentModule,
+                ngCommonHttp.HttpClientModule,
+                fdsCore,
+                NfRegistryRoutes
+            ],
+            declarations: [
+                NfRegistry,
+                NfRegistryExplorer,
+                NfRegistryAdministration,
+                NfRegistryUsersAdministration,
+                NfRegistryManageUser,
+                NfRegistryManageGroup,
+                NfRegistryManageBucket,
+                NfRegistryWorkflowAdministration,
+                NfRegistryAddUser,
+                NfRegistryCreateBucket,
+                NfRegistryCreateNewGroup,
+                NfRegistryAddUserToGroups,
+                NfRegistryAddUsersToGroup,
+                NfRegistryAddPolicyToBucket,
+                NfRegistryEditBucketPolicy,
+                NfRegistryGridListViewer,
+                NfRegistryBucketGridListViewer,
+                NfRegistryDropletGridListViewer,
+                NfPageNotFoundComponent,
+                NfLoginComponent,
+                NfUserLoginComponent
+            ],
+            entryComponents: [
+                NfRegistryAddUser,
+                NfRegistryCreateBucket,
+                NfRegistryCreateNewGroup,
+                NfRegistryAddUserToGroups,
+                NfRegistryAddUsersToGroup,
+                NfRegistryAddPolicyToBucket,
+                NfRegistryEditBucketPolicy,
+                NfUserLoginComponent
+            ],
+            providers: [
+                NfRegistryService,
+                NfRegistryApi,
+                NfStorage,
+                {
+                    provide: ngCommonHttp.HTTP_INTERCEPTORS,
+                    useClass: NfRegistryTokenInterceptor,
+                    multi: true
+                },
+                {
+                    provide: ngCommon.APP_BASE_HREF,
+                    useValue: '/'
+                },
+                {
+                    provide: ngRouter.ActivatedRoute,
+                    useValue: {
+                        params: rxjs.Observable.of({bucketId: '123'})
+                    }
+                }
+            ]
+        });
+        fixture = ngCoreTesting.TestBed.createComponent(NfRegistryManageBucket);
+
+        // test instance
+        comp = fixture.componentInstance;
+
+        // from the root injector
+        nfRegistryService = ngCoreTesting.TestBed.get(NfRegistryService);
+        nfRegistryApi = ngCoreTesting.TestBed.get(NfRegistryApi);
+
+        // because the NfRegistryManageBucket component is a nested route component we need to set up the nfRegistryService service manually
+        nfRegistryService.sidenav = {
+            open: function () {
+            },
+            close: function () {
+            }
+        };
+        nfRegistryService.bucket = {
+            identifier: 999,
+            name: 'Bucket #1'
+        };
+        nfRegistryService.buckets = [nfRegistryService.bucket];
+
+        //Spy
+        spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryService, 'filterDroplets');
+    });
+
+    it('should have a defined component', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'Bucket #1'
+        }));
+        spyOn(nfRegistryApi, 'getPolicies').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([
+            {
+                identifier: 'string',
+                resource: '/buckets/123',
+                action: 'READ',
+                configurable: true,
+                users: [{
+                    identity: 'User #1'
+                }],
+                userGroups: [{
+                    identity: 'Group #1'
+                }]
+            }
+        ]));
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBucket and getPolicies calls
+        fixture.detectChanges();
+
+        //assertions
+        expect(comp).toBeDefined();
+        expect(nfRegistryService.bucket.name).toEqual('Bucket #1');
+        expect(nfRegistryApi.getPolicies).toHaveBeenCalled();
+
+        var getBucketCall = nfRegistryApi.getBucket.calls.first()
+        expect(getBucketCall.args[0]).toBe('123');
+    }));
+
+    it('should FAIL to get bucket by id and redirect to workflow perspective', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(nfRegistryApi, 'getPolicies').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBucket and getPolicies calls
+        fixture.detectChanges();
+
+        //assertions
+        var routerCall = comp.router.navigateByUrl.calls.first();
+        expect(routerCall.args[0]).toBe('/nifi-registry/administration/workflow');
+        expect(comp.router.navigateByUrl.calls.count()).toBe(1);
+    }));
+
+    it('should redirect to workflow perspective', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'Bucket #1'
+        }));
+        spyOn(nfRegistryApi, 'getPolicies').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([
+            {
+                identifier: 'string',
+                resource: '/buckets/123',
+                action: 'READ',
+                configurable: true,
+                users: [{
+                    identity: 'User #1'
+                }],
+                userGroups: [{
+                    identity: 'Group #1'
+                }]
+            }
+        ]));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBucket and getPolicies calls
+        fixture.detectChanges();
+
+        // the function to test
+        comp.closeSideNav();
+
+        //assertions
+        var routerCall = comp.router.navigateByUrl.calls.first();
+        expect(routerCall.args[0]).toBe('/nifi-registry/administration/workflow');
+        expect(comp.router.navigateByUrl.calls.count()).toBe(1);
+    }));
+
+    it('should open a modal dialog UX enabling the creation of a user policy for a specific bucket', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp, 'filterPolicies').and.callFake(function () {
+        });
+        spyOn(comp.dialog, 'open').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of({
+                        userOrGroup: {
+                            type: 'user'
+                        }
+                    });
+                }
+            }
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'Bucket #1'
+        }));
+        spyOn(nfRegistryApi, 'getPolicies').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([
+            {
+                identifier: '123',
+                resource: '/buckets/123',
+                action: 'READ',
+                configurable: true,
+                users: [{
+                    identity: 'User #1'
+                }],
+                userGroups: [{
+                    identity: 'Group #1'
+                }]
+            }
+        ]));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBucket and getPolicies calls
+        fixture.detectChanges();
+
+        //assertions
+        var getBucketCall = nfRegistryApi.getBucket.calls.first();
+        expect(getBucketCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getBucket.calls.count()).toBe(1);
+
+        // the function to test
+        comp.addPolicy();
+
+        //assertions
+        expect(nfRegistryApi.getBucket.calls.count()).toBe(2);
+        expect(comp.snackBarService.openCoaster).toHaveBeenCalled();
+        expect(comp.filterPolicies).toHaveBeenCalled();
+    }));
+
+    it('should open a modal dialog UX enabling the creation of a user group policy for a specific bucket', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp, 'filterPolicies').and.callFake(function () {
+        });
+        spyOn(comp.dialog, 'open').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of({
+                        userOrGroup: {
+                            type: 'group'
+                        }
+                    });
+                }
+            }
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'Bucket #1'
+        }));
+        spyOn(nfRegistryApi, 'getPolicies').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([
+            {
+                identifier: '123',
+                resource: '/buckets/123',
+                action: 'READ',
+                configurable: true,
+                users: [{
+                    identity: 'User #1'
+                }],
+                userGroups: [{
+                    identity: 'Group #1'
+                }]
+            }
+        ]));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBucket and getPolicies calls
+        fixture.detectChanges();
+
+        //assertions
+        var getBucketCall = nfRegistryApi.getBucket.calls.first();
+        expect(getBucketCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getBucket.calls.count()).toBe(1);
+
+        // the function to test
+        comp.addPolicy();
+
+        //assertions
+        expect(nfRegistryApi.getBucket.calls.count()).toBe(2);
+        expect(comp.snackBarService.openCoaster).toHaveBeenCalled();
+        expect(comp.filterPolicies).toHaveBeenCalled();
+    }));
+
+    it('should open a modal dialog UX enabling the edit of a user policy for a specific bucket', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp, 'filterPolicies').and.callFake(function () {
+        });
+        spyOn(comp.dialog, 'open').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of({
+                        userOrGroup: {
+                            type: 'user'
+                        }
+                    });
+                }
+            }
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'Bucket #1'
+        }));
+        spyOn(nfRegistryApi, 'getPolicies').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([
+            {
+                identifier: '123',
+                resource: '/buckets/123',
+                action: 'READ',
+                configurable: true,
+                users: [{
+                    identity: 'User #1'
+                }],
+                userGroups: [{
+                    identity: 'Group #1'
+                }]
+            }
+        ]));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBucket and getPolicies calls
+        fixture.detectChanges();
+
+        //assertions
+        var getBucketCall = nfRegistryApi.getBucket.calls.first();
+        expect(getBucketCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getBucket.calls.count()).toBe(1);
+
+        // the function to test
+        comp.editPolicy();
+
+        //assertions
+        expect(nfRegistryApi.getBucket.calls.count()).toBe(2);
+        expect(comp.snackBarService.openCoaster).toHaveBeenCalled();
+        expect(comp.filterPolicies).toHaveBeenCalled();
+    }));
+
+    it('should open a modal dialog UX enabling the edit of a user group policy for a specific bucket', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp, 'filterPolicies').and.callFake(function () {
+        });
+        spyOn(comp.dialog, 'open').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of({
+                        userOrGroup: {
+                            type: 'group'
+                        }
+                    });
+                }
+            }
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'Bucket #1'
+        }));
+        spyOn(nfRegistryApi, 'getPolicies').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([
+            {
+                identifier: '123',
+                resource: '/buckets/123',
+                action: 'READ',
+                configurable: true,
+                users: [{
+                    identity: 'User #1'
+                }],
+                userGroups: [{
+                    identity: 'Group #1'
+                }]
+            }
+        ]));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBucket and getPolicies calls
+        fixture.detectChanges();
+
+        //assertions
+        var getBucketCall = nfRegistryApi.getBucket.calls.first();
+        expect(getBucketCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getBucket.calls.count()).toBe(1);
+
+        // the function to test
+        comp.editPolicy();
+
+        //assertions
+        expect(nfRegistryApi.getBucket.calls.count()).toBe(2);
+        expect(comp.snackBarService.openCoaster).toHaveBeenCalled();
+        expect(comp.filterPolicies).toHaveBeenCalled();
+    }));
+
+    it('should remove policy from bucket', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp, 'filterPolicies').and.callFake(function () {
+        });
+        spyOn(comp.dialogService, 'openConfirm').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of(true);
+                }
+            }
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'Bucket #1'
+        }));
+        spyOn(nfRegistryApi, 'getPolicies').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([
+            {
+                identifier: '456',
+                resource: '/buckets/123',
+                action: 'READ',
+                configurable: true,
+                users: [{
+                    identity: 'User #1'
+                }],
+                userGroups: [{
+                    identity: 'Group #1'
+                }]
+            }
+        ]));
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: [{
+                identity: 'User #1'
+            }],
+            userGroups: [{
+                identity: 'Group #1'
+            }]
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBucket and getPolicies calls
+        fixture.detectChanges();
+
+        //assertions
+        var getBucketCall = nfRegistryApi.getBucket.calls.first();
+        expect(getBucketCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getBucket.calls.count()).toBe(1);
+
+        var userOrGroup = {
+            type: 'user',
+            identity: '123',
+            permissions: 'read, write, delete'
+        };
+
+        // the function to test
+        comp.removePolicyFromBucket(userOrGroup);
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(3);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(3);
+        expect(nfRegistryApi.getPolicies.calls.count()).toBe(4);
+        expect(comp.snackBarService.openCoaster.calls.count()).toBe(3);
+        expect(comp.filterPolicies).toHaveBeenCalled();
+    }));
+
+    it('should update bucket name', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp.dialogService, 'openConfirm').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of(true);
+                }
+            }
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'Bucket #1'
+        }));
+        spyOn(nfRegistryApi, 'getPolicies').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([
+            {
+                identifier: '456',
+                resource: '/buckets/123',
+                action: 'READ',
+                configurable: true,
+                users: [{
+                    identity: 'User #1'
+                }],
+                userGroups: [{
+                    identity: 'Group #1'
+                }]
+            }
+        ]));
+        spyOn(nfRegistryApi, 'updateBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'test',
+            status: 200
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBucket and getPolicies calls
+        fixture.detectChanges();
+
+        //assertions
+        var getBucketCall = nfRegistryApi.getBucket.calls.first();
+        expect(getBucketCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getBucket.calls.count()).toBe(1);
+
+        // the function to test
+        comp.updateBucketName('test');
+
+        //assertions
+        expect(comp.snackBarService.openCoaster.calls.count()).toBe(1);
+        expect(comp.nfRegistryService.bucket.name).toBe('test');
+    }));
+
+    it('should fail to update bucket name (409)', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp.dialogService, 'openConfirm').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of(true);
+                }
+            }
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'Bucket #1'
+        }));
+        spyOn(nfRegistryApi, 'getPolicies').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([
+            {
+                identifier: '456',
+                resource: '/buckets/123',
+                action: 'READ',
+                configurable: true,
+                users: [{
+                    identity: 'User #1'
+                }],
+                userGroups: [{
+                    identity: 'Group #1'
+                }]
+            }
+        ]));
+        spyOn(nfRegistryApi, 'updateBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'test',
+            status: 409
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBucket and getPolicies calls
+        fixture.detectChanges();
+
+        //assertions
+        var getBucketCall = nfRegistryApi.getBucket.calls.first();
+        expect(getBucketCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getBucket.calls.count()).toBe(1);
+
+        // the function to test
+        comp.updateBucketName('test');
+
+        //assertions
+        expect(comp.dialogService.openConfirm.calls.count()).toBe(1);
+        expect(comp.nfRegistryService.bucket.name).toBe('Bucket #1');
+    }));
+
+    it('should fail to update bucket name (400)', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp.dialogService, 'openConfirm').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of(true);
+                }
+            }
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'Bucket #1'
+        }));
+        spyOn(nfRegistryApi, 'getPolicies').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([
+            {
+                identifier: '456',
+                resource: '/buckets/123',
+                action: 'READ',
+                configurable: true,
+                users: [{
+                    identity: 'User #1'
+                }],
+                userGroups: [{
+                    identity: 'Group #1'
+                }]
+            }
+        ]));
+        spyOn(nfRegistryApi, 'updateBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'test',
+            status: 400
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBucket and getPolicies calls
+        fixture.detectChanges();
+
+        //assertions
+        var getBucketCall = nfRegistryApi.getBucket.calls.first();
+        expect(getBucketCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getBucket.calls.count()).toBe(1);
+
+        // the function to test
+        comp.updateBucketName('test');
+
+        //assertions
+        expect(comp.dialogService.openConfirm.calls.count()).toBe(1);
+        expect(comp.nfRegistryService.bucket.name).toBe('Bucket #1');
+    }));
+
+    it('should destroy the component', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryService.sidenav, 'close');
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            name: 'Bucket #1'
+        }));
+        spyOn(nfRegistryApi, 'getPolicies').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([
+            {
+                identifier: 'string',
+                resource: '/buckets/123',
+                action: 'READ',
+                configurable: true,
+                users: [],
+                userGroups: []
+            }
+        ]));
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBucket and getPolicies calls
+        fixture.detectChanges();
+        spyOn(comp.$subscription, 'unsubscribe');
+
+        // The function to test
+        comp.ngOnDestroy();
+
+        //assertions
+        expect(nfRegistryService.sidenav.close).toHaveBeenCalled();
+        expect(nfRegistryService.bucket.name).toBe('Bucket #1');
+        expect(comp.$subscription.unsubscribe).toHaveBeenCalled();
+    }));
+});

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.js b/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.js
index 7f4ae24..1772297 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.js
@@ -29,10 +29,12 @@ var nfRegistryAnimations = require('nifi-registry/nf-registry.animations.js');
  * @param nfStorage             A wrapper for the browser's local storage.
  * @param nfRegistryService     The nf-registry.service module.
  * @param ActivatedRoute        The angular activated route module.
+ * @param router                The angular router module.
  * @constructor
  */
-function NfRegistryBucketGridListViewer(nfRegistryApi, nfStorage, nfRegistryService, ActivatedRoute) {
+function NfRegistryBucketGridListViewer(nfRegistryApi, nfStorage, nfRegistryService, ActivatedRoute, router) {
     this.route = ActivatedRoute;
+    this.router = router;
     this.nfStorage = nfStorage;
     this.nfRegistryService = nfRegistryService;
     this.nfRegistryApi = nfRegistryApi;
@@ -62,12 +64,29 @@ NfRegistryBucketGridListViewer.prototype = {
                 );
             })
             .subscribe(function (response) {
-                var buckets = response[0];
-                var droplets = response[1];
-                var bucket = response[2];
-                self.nfRegistryService.bucket = bucket;
-                self.nfRegistryService.buckets = buckets;
-                self.nfRegistryService.droplets = droplets;
+                if (!response[0].status || response[0].status === 200) {
+                    var buckets = response[0];
+                    self.nfRegistryService.buckets = buckets;
+                } else if (response[0].status === 404) {
+                    self.router.navigateByUrl('/nifi-registry/explorer/grid-list');
+                }
+                if (!response[2].status || response[2].status === 200) {
+                    var bucket = response[2];
+                    self.nfRegistryService.bucket = bucket;
+                } else if (response[2].status === 404) {
+                    self.router.navigateByUrl('/nifi-registry/explorer/grid-list');
+                }
+                if (!response[1].status || response[1].status === 200) {
+                    var droplets = response[1];
+                    self.nfRegistryService.droplets = droplets;
+                } else if (response[1].status === 404) {
+                    if (!response[2].status || response[2].status === 200) {
+                        var bucket = response[2];
+                        self.router.navigateByUrl('/nifi-registry/explorer/grid-list/buckets/' + bucket);
+                    } else {
+                        self.router.navigateByUrl('/nifi-registry/explorer/grid-list');
+                    }
+                }
                 self.nfRegistryService.filterDroplets();
                 self.nfRegistryService.setBreadcrumbState('in');
                 self.nfRegistryService.inProgress = false;
@@ -97,7 +116,8 @@ NfRegistryBucketGridListViewer.parameters = [
     NfRegistryApi,
     NfStorage,
     NfRegistryService,
-    ngRouter.ActivatedRoute
+    ngRouter.ActivatedRoute,
+    ngRouter.Router
 ];
 
 module.exports = NfRegistryBucketGridListViewer;

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.spec.js b/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.spec.js
index c1140c5..700ed49 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.spec.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.spec.js
@@ -39,7 +39,6 @@ var ngMoment = require('angular2-moment');
 var rxjs = require('rxjs/Rx');
 var ngCommonHttp = require('@angular/common/http');
 var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
-var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js');
 var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 var NfLoginComponent = require('nifi-registry/components/login/nf-registry-login.js');
 var NfUserLoginComponent = require('nifi-registry/components/login/dialogs/nf-registry-user-login.js');
@@ -77,7 +76,6 @@ describe('NfRegistryBucketGridListViewer Component', function () {
             ],
             providers: [
                 NfRegistryService,
-                NfRegistryAuthService,
                 NfRegistryApi,
                 NfStorage,
                 {
@@ -111,7 +109,11 @@ describe('NfRegistryBucketGridListViewer Component', function () {
 
         //Spy
         spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
-        spyOn(nfRegistryService, 'loadCurrentUser').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryService, 'filterDroplets');
+    });
+
+    it('should have a defined component', ngCoreTesting.fakeAsync(function () {
         spyOn(nfRegistryApi, 'getBuckets').and.callFake(function () {
         }).and.returnValue(rxjs.Observable.of([{
             identifier: '2f7f9e54-dc09-4ceb-aa58-9fe581319cdc',
@@ -122,10 +124,6 @@ describe('NfRegistryBucketGridListViewer Component', function () {
             identifier: '2f7f9e54-dc09-4ceb-aa58-9fe581319cdc',
             name: 'Bucket #1'
         }));
-        spyOn(nfRegistryService, 'filterDroplets');
-    });
-
-    it('should have a defined component', ngCoreTesting.fakeAsync(function () {
         spyOn(nfRegistryApi, 'getDroplets').and.callFake(function () {
         }).and.returnValue(rxjs.Observable.of([{
             "identifier": "2e04b4fb-9513-47bb-aa74-1ae34616bfdc",
@@ -170,7 +168,45 @@ describe('NfRegistryBucketGridListViewer Component', function () {
         expect(getBucketCall.args[0]).toBe('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc');
     }));
 
+    it('should FAIL to get buckets, get bucket, and get droplets and redirect to view all buckets', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryApi, 'getBuckets').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(nfRegistryApi, 'getDroplets').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit which makes getBuckets, getBucket, and getDroplets calls
+        fixture.detectChanges();
+        // wait for async getBuckets, getBucket, and getDroplets calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBuckets, getBucket, and getDroplets calls
+        fixture.detectChanges();
+
+        //assertions
+        var routerCall = comp.router.navigateByUrl.calls.first();
+        expect(routerCall.args[0]).toBe('/nifi-registry/explorer/grid-list');
+        expect(comp.router.navigateByUrl.calls.count()).toBe(3);
+    }));
+
     it('should destroy the component', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryApi, 'getBuckets').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([{
+            identifier: '2f7f9e54-dc09-4ceb-aa58-9fe581319cdc',
+            name: 'Bucket #1'
+        }]));
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '2f7f9e54-dc09-4ceb-aa58-9fe581319cdc',
+            name: 'Bucket #1'
+        }));
         spyOn(nfRegistryApi, 'getDroplets').and.callFake(function () {
         }).and.returnValue(rxjs.Observable.of([{
             "identifier": "2e04b4fb-9513-47bb-aa74-1ae34616bfdc",

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.js b/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.js
index d85f68b..0705156 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.js
@@ -29,10 +29,12 @@ var nfRegistryAnimations = require('nifi-registry/nf-registry.animations.js');
  * @param nfStorage             A wrapper for the browser's local storage.
  * @param nfRegistryService     The nf-registry.service module.
  * @param activatedRoute        The angular activated route module.
+ * @param router                The angular router module.
  * @constructor
  */
-function NfRegistryDropletGridListViewer(nfRegistryApi, nfStorage, nfRegistryService, activatedRoute) {
+function NfRegistryDropletGridListViewer(nfRegistryApi, nfStorage, nfRegistryService, activatedRoute, router) {
     this.route = activatedRoute;
+    this.router = router;
     this.nfStorage = nfStorage;
     this.nfRegistryService = nfRegistryService;
     this.nfRegistryApi = nfRegistryApi;
@@ -60,14 +62,32 @@ NfRegistryDropletGridListViewer.prototype = {
                 );
             })
             .subscribe(function (response) {
-                var droplet = response[0];
-                var bucket = response[1];
-                var buckets = response[2];
-                var droplets = response[3];
-                self.nfRegistryService.bucket = bucket;
-                self.nfRegistryService.buckets = buckets;
-                self.nfRegistryService.droplet = droplet;
-                self.nfRegistryService.droplets = droplets;
+                if (!response[0].status || response[0].status === 200) {
+                    var droplet = response[0];
+                    self.nfRegistryService.droplet = droplet;
+                } else if (response[0].status === 404) {
+                    if (!response[1].status || response[1].status === 200) {
+                        var bucket = response[1];
+                        self.nfRegistryService.bucket = bucket;
+                        self.router.navigateByUrl('/nifi-registry/explorer/grid-list/buckets/' + bucket.identifier);
+                    } else if (response[1].status === 404) {
+                        self.router.navigateByUrl('/nifi-registry/explorer/grid-list');
+                    }
+                }
+                if (!response[1].status || response[1].status === 200) {
+                    var bucket = response[1];
+                    self.nfRegistryService.bucket = bucket;
+                } else if (response[1].status === 404) {
+                    self.router.navigateByUrl('/nifi-registry/explorer/grid-list');
+                }
+                if (!response[2].status || response[2].status === 200) {
+                    var buckets = response[2];
+                    self.nfRegistryService.buckets = buckets;
+                }
+                if (!response[3].status || response[3].status === 200) {
+                    var droplets = response[3];
+                    self.nfRegistryService.droplets = droplets;
+                }
                 self.nfRegistryService.filterDroplets();
                 self.nfRegistryService.setBreadcrumbState('in');
                 self.nfRegistryService.inProgress = false;
@@ -96,7 +116,8 @@ NfRegistryDropletGridListViewer.parameters = [
     NfRegistryApi,
     NfStorage,
     NfRegistryService,
-    ngRouter.ActivatedRoute
+    ngRouter.ActivatedRoute,
+    ngRouter.Router
 ];
 
 module.exports = NfRegistryDropletGridListViewer;

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.spec.js b/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.spec.js
index b802a4d..77488a9 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.spec.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.spec.js
@@ -39,7 +39,6 @@ var ngMoment = require('angular2-moment');
 var rxjs = require('rxjs/Rx');
 var ngCommonHttp = require('@angular/common/http');
 var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
-var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js');
 var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 var NfLoginComponent = require('nifi-registry/components/login/nf-registry-login.js');
 var NfUserLoginComponent = require('nifi-registry/components/login/dialogs/nf-registry-user-login.js');
@@ -77,7 +76,6 @@ describe('NfRegistryDropletGridListViewer Component', function () {
             ],
             providers: [
                 NfRegistryService,
-                NfRegistryAuthService,
                 NfRegistryApi,
                 NfStorage,
                 {
@@ -116,8 +114,11 @@ describe('NfRegistryDropletGridListViewer Component', function () {
 
         //Spy
         spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
-        spyOn(nfRegistryService, 'loadCurrentUser').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
-        // spyOn(ngHttpService, 'get').and.callThrough();
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryService, 'filterDroplets');
+    });
+
+    it('should have a defined component', ngCoreTesting.fakeAsync(function () {
         spyOn(nfRegistryApi, 'getDroplet').and.callFake(function () {
         }).and.returnValue(rxjs.Observable.of({
             "identifier": "2e04b4fb-9513-47bb-aa74-1ae34616bfdc",
@@ -145,10 +146,6 @@ describe('NfRegistryDropletGridListViewer Component', function () {
             identifier: '2f7f9e54-dc09-4ceb-aa58-9fe581319cdc',
             name: 'Bucket #1'
         }));
-        spyOn(nfRegistryService, 'filterDroplets');
-    });
-
-    it('should have a defined component', ngCoreTesting.fakeAsync(function () {
         spyOn(nfRegistryApi, 'getDroplets').and.callFake(function () {
         }).and.returnValue(rxjs.Observable.of([{
             "identifier": "2e04b4fb-9513-47bb-aa74-1ae34616bfdc",
@@ -199,7 +196,66 @@ describe('NfRegistryDropletGridListViewer Component', function () {
         expect(getBucketCall.args[0]).toBe('2f7f9e54-dc09-4ceb-aa58-9fe581319cdc');
     }));
 
+    it('should FAIL to get buckets, get bucket, get droplets, and get droplet and then redirect to view all buckets', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryApi, 'getBuckets').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(nfRegistryApi, 'getDroplets').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(nfRegistryApi, 'getDroplet').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit which makes getBuckets, getBucket, and getDroplets calls
+        fixture.detectChanges();
+        // wait for async getBuckets, getBucket, and getDroplets calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getBuckets, getBucket, and getDroplets calls
+        fixture.detectChanges();
+
+        //assertions
+        var routerCall = comp.router.navigateByUrl.calls.first();
+        expect(routerCall.args[0]).toBe('/nifi-registry/explorer/grid-list');
+        expect(comp.router.navigateByUrl.calls.count()).toBe(2);
+    }));
+
     it('should destroy the component', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryApi, 'getDroplet').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            "identifier": "2e04b4fb-9513-47bb-aa74-1ae34616bfdc",
+            "name": "Flow #1",
+            "description": "This is flow #1",
+            "bucketIdentifier": "2f7f9e54-dc09-4ceb-aa58-9fe581319cdc",
+            "createdTimestamp": 1505931890999,
+            "modifiedTimestamp": 1505931890999,
+            "type": "FLOW",
+            "snapshotMetadata": null,
+            "link": {
+                "params": {
+                    "rel": "self"
+                },
+                "href": "flows/2e04b4fb-9513-47bb-aa74-1ae34616bfdc"
+            }
+        }));
+        spyOn(nfRegistryApi, 'getBuckets').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of([{
+            identifier: '2f7f9e54-dc09-4ceb-aa58-9fe581319cdc',
+            name: 'Bucket #1'
+        }]));
+        spyOn(nfRegistryApi, 'getBucket').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '2f7f9e54-dc09-4ceb-aa58-9fe581319cdc',
+            name: 'Bucket #1'
+        }));
         spyOn(nfRegistryApi, 'getDroplets').and.callFake(function () {
         }).and.returnValue(rxjs.Observable.of([{
             "identifier": "2e04b4fb-9513-47bb-aa74-1ae34616bfdc",

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.html
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.html b/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.html
index d077016..8fbd6d4 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.html
+++ b/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.html
@@ -74,15 +74,15 @@ limitations under the License.
                         <div fxFlex="25" class="pad-left-sm">
                             <div>
                                 <span class="uppercase">Bucket Identifier</span>
-                                <p class="ellipsis" title="{{droplet.bucketIdentifier}}" *ngIf="droplet.bucketIdentifier">{{droplet.bucketIdentifier}}</p>
+                                <p class="ellipsis" matTooltip="{{droplet.bucketIdentifier}}" *ngIf="droplet.bucketIdentifier">{{droplet.bucketIdentifier}}</p>
                             </div>
                             <div class="pad-top-md">
                                 <span class="uppercase">{{droplet.type}} Identifier</span>
-                                <p class="ellipsis" title="{{droplet.identifier}} "*ngIf="droplet.identifier">{{droplet.identifier}}</p>
+                                <p class="ellipsis" matTooltip="{{droplet.identifier}} "*ngIf="droplet.identifier">{{droplet.identifier}}</p>
                             </div>
                             <div class="pad-top-md">
                                 <span class="uppercase">Description</span>
-                                <p class="nf-registry-droplet-description" title="{{droplet.description}}" *ngIf="droplet.description">{{droplet.description}}</p>
+                                <p class="nf-registry-droplet-description" matTooltip="{{droplet.description}}" *ngIf="droplet.description">{{droplet.description}}</p>
                                 <p *ngIf="!droplet.description">No description specified</p>
                             </div>
                         </div>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.spec.js b/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.spec.js
index 68d1988..47ddab5 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.spec.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.spec.js
@@ -39,7 +39,6 @@ var ngMoment = require('angular2-moment');
 var rxjs = require('rxjs/Rx');
 var ngCommonHttp = require('@angular/common/http');
 var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
-var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js');
 var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 var NfLoginComponent = require('nifi-registry/components/login/nf-registry-login.js');
 var NfUserLoginComponent = require('nifi-registry/components/login/dialogs/nf-registry-user-login.js');
@@ -77,7 +76,6 @@ describe('NfRegistryGridListViewer Component', function () {
             ],
             providers: [
                 NfRegistryService,
-                NfRegistryAuthService,
                 NfRegistryApi,
                 NfStorage,
                 {
@@ -111,7 +109,7 @@ describe('NfRegistryGridListViewer Component', function () {
 
         // Spy
         spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
-        spyOn(nfRegistryService, 'loadCurrentUser').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
         spyOn(nfRegistryApi, 'getBuckets').and.callFake(function () {
         }).and.returnValue(rxjs.Observable.of([{
             identifier: '2f7f9e54-dc09-4ceb-aa58-9fe581319cdc',

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/explorer/nf-registry-explorer.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/explorer/nf-registry-explorer.spec.js b/nifi-registry-web-ui/src/main/webapp/components/explorer/nf-registry-explorer.spec.js
index cd6e2eb..4cf6c5f 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/explorer/nf-registry-explorer.spec.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/explorer/nf-registry-explorer.spec.js
@@ -37,7 +37,6 @@ var fdsCore = require('@fluid-design-system/core');
 var ngMoment = require('angular2-moment');
 var ngCommonHttp = require('@angular/common/http');
 var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
-var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js');
 var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 var NfLoginComponent = require('nifi-registry/components/login/nf-registry-login.js');
 var NfUserLoginComponent = require('nifi-registry/components/login/dialogs/nf-registry-user-login.js');
@@ -74,7 +73,6 @@ describe('NfRegistryExplorer Component', function () {
             ],
             providers: [
                 NfRegistryService,
-                NfRegistryAuthService,
                 NfRegistryApi,
                 NfStorage,
                 {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/nf-registry.module.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/nf-registry.module.js b/nifi-registry-web-ui/src/main/webapp/nf-registry.module.js
index a2d9671..cafe1f6 100644
--- a/nifi-registry-web-ui/src/main/webapp/nf-registry.module.js
+++ b/nifi-registry-web-ui/src/main/webapp/nf-registry.module.js
@@ -44,7 +44,6 @@ var NfRegistryDropletGridListViewer = require('nifi-registry/components/explorer
 var fdsCore = require('@fluid-design-system/core');
 var ngCommonHttp = require('@angular/common/http');
 var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
-var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js');
 var nfRegistryAuthGuardService = require('nifi-registry/services/nf-registry.auth-guard.service.js');
 var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 
@@ -98,7 +97,6 @@ NfRegistryModule.annotations = [
         ],
         providers: [
             NfRegistryService,
-            NfRegistryAuthService,
             nfRegistryAuthGuardService.NfRegistryUsersAdministrationAuthGuard,
             nfRegistryAuthGuardService.NfRegistryWorkflowsAdministrationAuthGuard,
             nfRegistryAuthGuardService.NfRegistryLoginAuthGuard,

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/nf-registry.routes.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/nf-registry.routes.js b/nifi-registry-web-ui/src/main/webapp/nf-registry.routes.js
index 4235b0a..3fe831a 100644
--- a/nifi-registry-web-ui/src/main/webapp/nf-registry.routes.js
+++ b/nifi-registry-web-ui/src/main/webapp/nf-registry.routes.js
@@ -35,6 +35,11 @@ var NfRegistryRoutes = new ngRouter.RouterModule.forRoot([{
     component: NfRegistryExplorer,
     children: [
         {
+            path: '',
+            redirectTo: 'grid-list',
+            pathMatch: 'full'
+        },
+        {
             path: 'grid-list',
             component: NfRegistryGridListViewer,
             canActivate: [nfRegistryAuthGuardService.NfRegistryResourcesAuthGuard]

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/nf-registry.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/nf-registry.spec.js b/nifi-registry-web-ui/src/main/webapp/nf-registry.spec.js
index a5e43c7..c9d90d6 100644
--- a/nifi-registry-web-ui/src/main/webapp/nf-registry.spec.js
+++ b/nifi-registry-web-ui/src/main/webapp/nf-registry.spec.js
@@ -38,7 +38,6 @@ var ngMoment = require('angular2-moment');
 var ngHttp = require('@angular/http');
 var ngCommonHttp = require('@angular/common/http');
 var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
-var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js');
 var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 var NfLoginComponent = require('nifi-registry/components/login/nf-registry-login.js');
 var NfUserLoginComponent = require('nifi-registry/components/login/dialogs/nf-registry-user-login.js');
@@ -77,7 +76,6 @@ describe('NfRegistry Component', function () {
             ],
             providers: [
                 NfRegistryService,
-                NfRegistryAuthService,
                 NfRegistryApi,
                 NfStorage,
                 {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/services/nf-registry.api.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.api.js b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.api.js
index 04ec818..9cde0d9 100644
--- a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.api.js
+++ b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.api.js
@@ -19,7 +19,6 @@ var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 var ngCommonHttp = require('@angular/common/http');
 var fdsDialogsModule = require('@fluid-design-system/dialogs');
 var rxjs = require('rxjs/Observable');
-var ngRouter = require('@angular/router');
 var MILLIS_PER_SECOND = 1000;
 var headers = new Headers({'Content-Type': 'application/json'});
 
@@ -36,14 +35,12 @@ var config = {
  * @param nfStorage             A wrapper for the browser's local storage.
  * @param http                  The angular http module.
  * @param fdsDialogService      The FDS dialog service.
- * @param router                The angular router module.
  * @constructor
  */
-function NfRegistryApi(nfStorage, http, fdsDialogService, router) {
+function NfRegistryApi(nfStorage, http, fdsDialogService) {
     this.nfStorage = nfStorage;
     this.http = http;
     this.dialogService = fdsDialogService;
-    this.router = router;
 };
 
 NfRegistryApi.prototype = {
@@ -91,16 +88,11 @@ NfRegistryApi.prototype = {
             })
             .catch(function (error) {
                 self.dialogService.openConfirm({
-                    title: 'Error',
+                    title: 'Flow Not Found',
                     message: error.error,
                     acceptButton: 'Ok',
                     acceptButtonColor: 'fds-warn'
-                }).afterClosed().subscribe(
-                    function (accept) {
-                        if (accept) {
-                            self.router.navigateByUrl('/nifi-registry/explorer/grid-list/buckets/' + bucketId);
-                        }
-                    });
+                });
                 return rxjs.Observable.of(error);
             });
     },
@@ -125,12 +117,6 @@ NfRegistryApi.prototype = {
                 return response || [];
             })
             .catch(function (error) {
-                self.dialogService.openConfirm({
-                    title: 'Error',
-                    message: error.error,
-                    acceptButton: 'Ok',
-                    acceptButtonColor: 'fds-warn'
-                });
                 return rxjs.Observable.of(error);
             });
     },
@@ -224,16 +210,11 @@ NfRegistryApi.prototype = {
             })
             .catch(function (error) {
                 self.dialogService.openConfirm({
-                    title: 'Error',
+                    title: 'Bucket Not Found',
                     message: error.error,
                     acceptButton: 'Ok',
                     acceptButtonColor: 'fds-warn'
-                }).afterClosed().subscribe(
-                    function (accept) {
-                        if (accept) {
-                            self.router.navigateByUrl('/nifi-registry/explorer/grid-list');
-                        }
-                    });
+                });
                 return rxjs.Observable.of(error);
             });
     },
@@ -255,7 +236,7 @@ NfRegistryApi.prototype = {
             })
             .catch(function (error) {
                 self.dialogService.openConfirm({
-                    title: 'Error',
+                    title: 'Buckets Not Found',
                     message: error.error,
                     acceptButton: 'Ok',
                     acceptButtonColor: 'fds-warn'
@@ -299,12 +280,12 @@ NfRegistryApi.prototype = {
             })
             .catch(function (error) {
                 self.dialogService.openConfirm({
-                    title: 'Error',
+                    title: 'User Not Found',
                     message: error.error,
                     acceptButton: 'Ok',
                     acceptButtonColor: 'fds-warn'
                 });
-                return rxjs.Observable.throw(error.error);
+                return rxjs.Observable.of(error);
             });
     },
 
@@ -394,7 +375,7 @@ NfRegistryApi.prototype = {
             })
             .catch(function (error) {
                 self.dialogService.openConfirm({
-                    title: 'Error',
+                    title: 'Users Not Found',
                     message: error.error,
                     acceptButton: 'Ok',
                     acceptButtonColor: 'fds-warn'
@@ -439,7 +420,7 @@ NfRegistryApi.prototype = {
             })
             .catch(function (error) {
                 self.dialogService.openConfirm({
-                    title: 'Error',
+                    title: 'Groups Not Found',
                     message: error.error,
                     acceptButton: 'Ok',
                     acceptButtonColor: 'fds-warn'
@@ -462,7 +443,7 @@ NfRegistryApi.prototype = {
             })
             .catch(function (error) {
                 self.dialogService.openConfirm({
-                    title: 'Error',
+                    title: 'Group Not Found',
                     message: error.error,
                     acceptButton: 'Ok',
                     acceptButtonColor: 'fds-warn'
@@ -578,6 +559,12 @@ NfRegistryApi.prototype = {
                 return response;
             })
             .catch(function (error) {
+                self.dialogService.openConfirm({
+                    title: 'Error',
+                    message: error.error,
+                    acceptButton: 'Ok',
+                    acceptButtonColor: 'fds-warn'
+                });
                 return rxjs.Observable.of(error);
             });
     },
@@ -596,6 +583,12 @@ NfRegistryApi.prototype = {
                 return response;
             })
             .catch(function (error) {
+                self.dialogService.openConfirm({
+                    title: 'Error',
+                    message: error.error,
+                    acceptButton: 'Ok',
+                    acceptButtonColor: 'fds-warn'
+                });
                 return rxjs.Observable.of(error);
             });
     },
@@ -744,12 +737,8 @@ NfRegistryApi.prototype = {
                 return response;
             })
             .catch(function (error) {
-                // there is no anonymous access and we don't know this user - open the login page which handles login/registration/etc
-                if (error.status === 401) {
-                    self.nfStorage.removeItem('jwt');
-                    self.router.navigateByUrl('/nifi-registry/login');
-                }
                 return rxjs.Observable.of({
+                    error: error,
                     resourcePermissions: {
                         anyTopLevelResource: {
                             canRead: false,
@@ -785,8 +774,7 @@ NfRegistryApi.prototype = {
 NfRegistryApi.parameters = [
     NfStorage,
     ngCommonHttp.HttpClient,
-    fdsDialogsModule.FdsDialogService,
-    ngRouter.Router
+    fdsDialogsModule.FdsDialogService
 ];
 
 module.exports = NfRegistryApi;


[4/5] nifi-registry git commit: [NIFIREG-126] adding some polish and testing around deep links

Posted by kd...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-group/nf-registry-manage-group.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-group/nf-registry-manage-group.spec.js b/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-group/nf-registry-manage-group.spec.js
new file mode 100644
index 0000000..7c38182
--- /dev/null
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-group/nf-registry-manage-group.spec.js
@@ -0,0 +1,2403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the 'License'); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var NfRegistryRoutes = require('nifi-registry/nf-registry.routes.js');
+var ngCoreTesting = require('@angular/core/testing');
+var ngCommon = require('@angular/common');
+var ngRouter = require('@angular/router');
+var NfRegistry = require('nifi-registry/nf-registry.js');
+var NfRegistryApi = require('nifi-registry/services/nf-registry.api.js');
+var NfRegistryService = require('nifi-registry/services/nf-registry.service.js');
+var NfPageNotFoundComponent = require('nifi-registry/components/page-not-found/nf-registry-page-not-found.js');
+var NfRegistryExplorer = require('nifi-registry/components/explorer/nf-registry-explorer.js');
+var NfRegistryAdministration = require('nifi-registry/components/administration/nf-registry-administration.js');
+var NfRegistryUsersAdministration = require('nifi-registry/components/administration/users/nf-registry-users-administration.js');
+var NfRegistryAddUser = require('nifi-registry/components/administration/users/dialogs/add-user/nf-registry-add-user.js');
+var NfRegistryCreateNewGroup = require('nifi-registry/components/administration/users/dialogs/create-new-group/nf-registry-create-new-group.js');
+var NfRegistryEditBucketPolicy = require('nifi-registry/components/administration/workflow/dialogs/edit-bucket-policy/nf-registry-edit-bucket-policy.js');
+var NfRegistryAddPolicyToBucket = require('nifi-registry/components/administration/workflow/dialogs/add-policy-to-bucket/nf-registry-add-policy-to-bucket.js');
+var NfRegistryAddUserToGroups = require('nifi-registry/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.js');
+var NfRegistryAddUsersToGroup = require('nifi-registry/components/administration/users/dialogs/add-users-to-group/nf-registry-add-users-to-group.js');
+var NfRegistryManageUser = require('nifi-registry/components/administration/users/sidenav/manage-user/nf-registry-manage-user.js');
+var NfRegistryManageGroup = require('nifi-registry/components/administration/users/sidenav/manage-group/nf-registry-manage-group.js');
+var NfRegistryManageBucket = require('nifi-registry/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.js');
+var NfRegistryWorkflowAdministration = require('nifi-registry/components/administration/workflow/nf-registry-workflow-administration.js');
+var NfRegistryCreateBucket = require('nifi-registry/components/administration/workflow/dialogs/create-bucket/nf-registry-create-bucket.js');
+var NfRegistryGridListViewer = require('nifi-registry/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.js');
+var NfRegistryBucketGridListViewer = require('nifi-registry/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.js');
+var NfRegistryDropletGridListViewer = require('nifi-registry/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.js');
+var fdsCore = require('@fluid-design-system/core');
+var ngMoment = require('angular2-moment');
+var rxjs = require('rxjs/Rx');
+var ngCommonHttp = require('@angular/common/http');
+var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
+var NfStorage = require('nifi-registry/services/nf-storage.service.js');
+var NfLoginComponent = require('nifi-registry/components/login/nf-registry-login.js');
+var NfUserLoginComponent = require('nifi-registry/components/login/dialogs/nf-registry-user-login.js');
+
+describe('NfRegistryManageGroup Component', function () {
+    var comp;
+    var fixture;
+    var nfRegistryService;
+    var nfRegistryApi;
+
+    beforeEach(function () {
+        ngCoreTesting.TestBed.configureTestingModule({
+            imports: [
+                ngMoment.MomentModule,
+                ngCommonHttp.HttpClientModule,
+                fdsCore,
+                NfRegistryRoutes
+            ],
+            declarations: [
+                NfRegistry,
+                NfRegistryExplorer,
+                NfRegistryAdministration,
+                NfRegistryUsersAdministration,
+                NfRegistryManageUser,
+                NfRegistryManageGroup,
+                NfRegistryManageBucket,
+                NfRegistryWorkflowAdministration,
+                NfRegistryAddUser,
+                NfRegistryCreateBucket,
+                NfRegistryCreateNewGroup,
+                NfRegistryAddUserToGroups,
+                NfRegistryAddUsersToGroup,
+                NfRegistryAddPolicyToBucket,
+                NfRegistryEditBucketPolicy,
+                NfRegistryGridListViewer,
+                NfRegistryBucketGridListViewer,
+                NfRegistryDropletGridListViewer,
+                NfPageNotFoundComponent,
+                NfLoginComponent,
+                NfUserLoginComponent
+            ],
+            entryComponents: [
+                NfRegistryAddUser,
+                NfRegistryCreateBucket,
+                NfRegistryCreateNewGroup,
+                NfRegistryAddUserToGroups,
+                NfRegistryAddUsersToGroup,
+                NfRegistryAddPolicyToBucket,
+                NfRegistryEditBucketPolicy,
+                NfUserLoginComponent
+            ],
+            providers: [
+                NfRegistryService,
+                NfRegistryApi,
+                NfStorage,
+                {
+                    provide: ngCommonHttp.HTTP_INTERCEPTORS,
+                    useClass: NfRegistryTokenInterceptor,
+                    multi: true
+                },
+                {
+                    provide: ngCommon.APP_BASE_HREF,
+                    useValue: '/'
+                },
+                {
+                    provide: ngRouter.ActivatedRoute,
+                    useValue: {
+                        params: rxjs.Observable.of({groupId: '123'})
+                    }
+                }
+            ]
+        });
+        fixture = ngCoreTesting.TestBed.createComponent(NfRegistryManageGroup);
+
+        // test instance
+        comp = fixture.componentInstance;
+
+        // from the root injector
+        nfRegistryService = ngCoreTesting.TestBed.get(NfRegistryService);
+        nfRegistryApi = ngCoreTesting.TestBed.get(NfRegistryApi);
+
+        // because the NfRegistryManageGroup component is a nested route component we need to set up the nfRegistryService service manually
+        nfRegistryService.sidenav = {
+            open: function () {
+            },
+            close: function () {
+            }
+        };
+        nfRegistryService.group = {
+            identifier: 999,
+            identity: 'Group #1',
+            users: [{
+                identifier: '123',
+                identity: 'Group #1'
+            }],
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        };
+        nfRegistryService.groups = [nfRegistryService.group];
+
+        //Spy
+        spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+    });
+
+    it('should have a defined component', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        expect(comp).toBeDefined();
+        expect(nfRegistryService.group.identifier).toEqual('123');
+
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first()
+        expect(getUserGroupCall.args[0]).toBe('123');
+    }));
+
+    it('should FAIL to get user by id and redirect to admin users perspective', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var routerCall = comp.router.navigateByUrl.calls.first();
+        expect(routerCall.args[0]).toBe('/nifi-registry/administration/users');
+        expect(comp.router.navigateByUrl.calls.count()).toBe(1);
+    }));
+
+    it('should FAIL to get user by id and redirect to workflow perspective', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 409
+        }));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var routerCall = comp.router.navigateByUrl.calls.first();
+        expect(routerCall.args[0]).toBe('/nifi-registry/administration/workflow');
+        expect(comp.router.navigateByUrl.calls.count()).toBe(1);
+    }));
+
+    it('should redirect to users perspective', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        // the function to test
+        comp.closeSideNav();
+
+        //assertions
+        var routerCall = comp.router.navigateByUrl.calls.first();
+        expect(routerCall.args[0]).toBe('/nifi-registry/administration/users');
+        expect(comp.router.navigateByUrl.calls.count()).toBe(1);
+    }));
+
+    it('should toggle to create the manage bucket privileges for the current group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404,
+            userGroups: []
+        }));
+        spyOn(nfRegistryApi, 'postPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            userGroups: [
+                {
+                    identifier: '123',
+                    identity: 'Group #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleGroupManageBucketsPrivileges({
+            checked: true
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.postPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to update the manage bucket privileges for the current group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            userGroups: []
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            userGroups: [
+                {
+                    identifier: '123',
+                    identity: 'Group #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleGroupManageBucketsPrivileges({
+            checked: true
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to remove the manage bucket privileges for the current group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 400,
+            userGroups: [
+                {
+                    identifier: '123',
+                    identity: 'Group #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleGroupManageBucketsPrivileges({
+            checked: false
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to create the manage proxy privileges for the current group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404,
+            userGroups: []
+        }));
+        spyOn(nfRegistryApi, 'postPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            userGroups: [
+                {
+                    identifier: '123',
+                    identity: 'Group #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleGroupManageProxyPrivileges({
+            checked: true
+        }, 'write');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.postPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to update the manage proxy privileges for the current group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            userGroups: []
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            userGroups: [
+                {
+                    identifier: '123',
+                    identity: 'Group #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleGroupManageProxyPrivileges({
+            checked: true
+        }, 'write');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to remove the manage proxy privileges for the current group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 400,
+            userGroups: [
+                {
+                    identifier: '123',
+                    identity: 'Group #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleGroupManageProxyPrivileges({
+            checked: false
+        }, 'write');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to create the manage policies privileges for the current group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404,
+            userGroups: []
+        }));
+        spyOn(nfRegistryApi, 'postPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            userGroups: [
+                {
+                    identifier: '123',
+                    identity: 'Group #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleGroupManagePoliciesPrivileges({
+            checked: true
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.postPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to update the manage policies privileges for the current group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            userGroups: []
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            userGroups: [
+                {
+                    identifier: '123',
+                    identity: 'Group #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleGroupManagePoliciesPrivileges({
+            checked: true
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to remove the manage policies privileges for the current group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 400,
+            userGroups: [
+                {
+                    identifier: '123',
+                    identity: 'Group #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleGroupManagePoliciesPrivileges({
+            checked: false
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to create the manage tenants privileges for the current group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404,
+            userGroups: []
+        }));
+        spyOn(nfRegistryApi, 'postPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            userGroups: [
+                {
+                    identifier: '123',
+                    identity: 'Group #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleGroupManageTenantsPrivileges({
+            checked: true
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.postPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to update the manage tenants privileges for the current group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            userGroups: []
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            userGroups: [
+                {
+                    identifier: '123',
+                    identity: 'Group #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleGroupManageTenantsPrivileges({
+            checked: true
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to remove the manage tenants privileges for the current group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 400,
+            userGroups: [
+                {
+                    identifier: '123',
+                    identity: 'Group #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleGroupManageTenantsPrivileges({
+            checked: false
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+    }));
+
+    it('should open a modal dialog UX enabling the addition of the current user to a group(s)', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp, 'filterUsers').and.callFake(function () {
+        });
+        spyOn(comp.dialog, 'open').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of({});
+                }
+            }
+        });
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.addUsersToGroup();
+
+        //assertions
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+        expect(comp.filterUsers).toHaveBeenCalled();
+    }));
+
+    it('should remove user from group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp, 'filterUsers').and.callFake(function () {
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+        spyOn(nfRegistryApi, 'updateUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        var user = {
+            identifier: '123'
+        };
+
+        // the function to test
+        comp.removeUserFromGroup(user);
+
+        //assertions
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(2);
+        expect(nfRegistryApi.updateUserGroup.calls.count()).toBe(1);
+        expect(comp.snackBarService.openCoaster.calls.count()).toBe(1);
+        expect(comp.filterUsers).toHaveBeenCalled();
+    }));
+
+    it('should update group name', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp.dialogService, 'openConfirm').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of(true);
+                }
+            }
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+        spyOn(nfRegistryApi, 'updateUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'test',
+            status: 200
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.updateGroupName('test');
+
+        //assertions
+        expect(comp.snackBarService.openCoaster.calls.count()).toBe(1);
+        expect(comp.nfRegistryService.group.identity).toBe('test');
+    }));
+
+    it('should fail to update group name (409)', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp.dialogService, 'openConfirm').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of(true);
+                }
+            }
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    policies: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    proxy: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    }
+                }
+            }]
+        }));
+        spyOn(nfRegistryApi, 'updateUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'test',
+            status: 409
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUserGroup calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserGroupCall = nfRegistryApi.getUserGroup.calls.first();
+        expect(getUserGroupCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+
+        // the function to test
+        comp.updateGroupName('test');
+
+        //assertions
+        expect(comp.dialogService.openConfirm.calls.count()).toBe(1);
+        expect(comp.nfRegistryService.group.identity).toBe('Group #1');
+    }));
+
+    it('should destroy the component', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryService.sidenav, 'close');
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'Group #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            },
+            users: [{
+                identifier: '123',
+                identity: 'User #1',
+                resourcePermissions: {
+                    anyTopLevelResource: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    buckets: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                    },
+                    tenants: {
+                        canRead: false,
+                        canWrite: false,
+                        canDelete: false
+                

<TRUNCATED>

[3/5] nifi-registry git commit: [NIFIREG-126] adding some polish and testing around deep links

Posted by kd...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-user/nf-registry-manage-user.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-user/nf-registry-manage-user.js b/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-user/nf-registry-manage-user.js
index 9abc043..23ac198 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-user/nf-registry-manage-user.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-user/nf-registry-manage-user.js
@@ -64,17 +64,22 @@ NfRegistryManageUser.prototype = {
      */
     ngOnInit: function () {
         var self = this;
-        this.nfRegistryService.sidenav.open();
-
         // subscribe to the route params
         this.$subscription = self.route.params
             .switchMap(function (params) {
                 return self.nfRegistryApi.getUser(params['userId']);
             })
             .subscribe(function (response) {
-                self.nfRegistryService.user = response;
-                self._username = response.identity;
-                self.filterGroups();
+                if (!response.status || response.status === 200) {
+                    self.nfRegistryService.sidenav.open();
+                    self.nfRegistryService.user = response;
+                    self._username = response.identity;
+                    self.filterGroups();
+                } else if (response.status === 404) {
+                    self.router.navigateByUrl('/nifi-registry/administration/users');
+                } else if (response.status === 409) {
+                    self.router.navigateByUrl('/nifi-registry/administration/workflow');
+                }
             });
     },
 
@@ -107,7 +112,7 @@ NfRegistryManageUser.prototype = {
                     this.nfRegistryService.BUCKETS_PRIVS[resource].forEach(function (action) {
                         if (!policyAction || (action === policyAction)) {
                             self.nfRegistryApi.getPolicyActionResource(action, resource).subscribe(function (policy) {
-                                if (policy.status && policy.status === 409) {
+                                if (policy.status && policy.status === 404) {
                                     // resource does NOT exist, let's create it
                                     self.nfRegistryApi.postPolicyActionResource(action, resource, [self.nfRegistryService.user], []).subscribe(
                                         function (response) {
@@ -148,7 +153,7 @@ NfRegistryManageUser.prototype = {
                     this.nfRegistryService.BUCKETS_PRIVS[resource].forEach(function (action) {
                         if (!policyAction || (action === policyAction)) {
                             self.nfRegistryApi.getPolicyActionResource(action, resource).subscribe(function (policy) {
-                                if (policy.status && policy.status === 409) {
+                                if (policy.status && policy.status === 404) {
                                     // resource does NOT exist
                                 } else {
                                     // resource exists, let's filter out the current user and update it
@@ -187,7 +192,7 @@ NfRegistryManageUser.prototype = {
                     this.nfRegistryService.TENANTS_PRIVS[resource].forEach(function (action) {
                         if (!policyAction || (action === policyAction)) {
                             self.nfRegistryApi.getPolicyActionResource(action, resource).subscribe(function (policy) {
-                                if (policy.status && policy.status === 409) {
+                                if (policy.status && policy.status === 404) {
                                     // resource does NOT exist, let's create it
                                     self.nfRegistryApi.postPolicyActionResource(action, resource, [self.nfRegistryService.user], []).subscribe(
                                         function (response) {
@@ -228,7 +233,7 @@ NfRegistryManageUser.prototype = {
                     this.nfRegistryService.TENANTS_PRIVS[resource].forEach(function (action) {
                         if (!policyAction || (action === policyAction)) {
                             self.nfRegistryApi.getPolicyActionResource(action, resource).subscribe(function (policy) {
-                                if (policy.status && policy.status === 409) {
+                                if (policy.status && policy.status === 404) {
                                     // resource does NOT exist
                                 } else {
                                     // resource exists, let's filter out the current user and update it
@@ -267,7 +272,7 @@ NfRegistryManageUser.prototype = {
                     this.nfRegistryService.POLICIES_PRIVS[resource].forEach(function (action) {
                         if (!policyAction || (action === policyAction)) {
                             self.nfRegistryApi.getPolicyActionResource(action, resource).subscribe(function (policy) {
-                                if (policy.status && policy.status === 409) {
+                                if (policy.status && policy.status === 404) {
                                     // resource does NOT exist, let's create it
                                     self.nfRegistryApi.postPolicyActionResource(action, resource, [self.nfRegistryService.user], []).subscribe(
                                         function (response) {
@@ -308,7 +313,7 @@ NfRegistryManageUser.prototype = {
                     this.nfRegistryService.POLICIES_PRIVS[resource].forEach(function (action) {
                         if (!policyAction || (action === policyAction)) {
                             self.nfRegistryApi.getPolicyActionResource(action, resource).subscribe(function (policy) {
-                                if (policy.status && policy.status === 409) {
+                                if (policy.status && policy.status === 404) {
                                     // resource does NOT exist
                                 } else {
                                     // resource exists, let's filter out the current user and update it
@@ -347,7 +352,7 @@ NfRegistryManageUser.prototype = {
                     this.nfRegistryService.PROXY_PRIVS[resource].forEach(function (action) {
                         if (!policyAction || (action === policyAction)) {
                             self.nfRegistryApi.getPolicyActionResource(action, resource).subscribe(function (policy) {
-                                if (policy.status && policy.status === 409) {
+                                if (policy.status && policy.status === 404) {
                                     // resource does NOT exist, let's create it
                                     self.nfRegistryApi.postPolicyActionResource(action, resource, [self.nfRegistryService.user], []).subscribe(
                                         function (response) {
@@ -388,7 +393,7 @@ NfRegistryManageUser.prototype = {
                     this.nfRegistryService.PROXY_PRIVS[resource].forEach(function (action) {
                         if (!policyAction || (action === policyAction)) {
                             self.nfRegistryApi.getPolicyActionResource(action, resource).subscribe(function (policy) {
-                                if (policy.status && policy.status === 409) {
+                                if (policy.status && policy.status === 404) {
                                     // resource does NOT exist
                                 } else {
                                     // resource exists, let's filter out the current user and update it

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-user/nf-registry-manage-user.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-user/nf-registry-manage-user.spec.js b/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-user/nf-registry-manage-user.spec.js
new file mode 100644
index 0000000..d3eca21
--- /dev/null
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-user/nf-registry-manage-user.spec.js
@@ -0,0 +1,1816 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the 'License'); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var NfRegistryRoutes = require('nifi-registry/nf-registry.routes.js');
+var ngCoreTesting = require('@angular/core/testing');
+var ngCommon = require('@angular/common');
+var ngRouter = require('@angular/router');
+var NfRegistry = require('nifi-registry/nf-registry.js');
+var NfRegistryApi = require('nifi-registry/services/nf-registry.api.js');
+var NfRegistryService = require('nifi-registry/services/nf-registry.service.js');
+var NfPageNotFoundComponent = require('nifi-registry/components/page-not-found/nf-registry-page-not-found.js');
+var NfRegistryExplorer = require('nifi-registry/components/explorer/nf-registry-explorer.js');
+var NfRegistryAdministration = require('nifi-registry/components/administration/nf-registry-administration.js');
+var NfRegistryUsersAdministration = require('nifi-registry/components/administration/users/nf-registry-users-administration.js');
+var NfRegistryAddUser = require('nifi-registry/components/administration/users/dialogs/add-user/nf-registry-add-user.js');
+var NfRegistryCreateNewGroup = require('nifi-registry/components/administration/users/dialogs/create-new-group/nf-registry-create-new-group.js');
+var NfRegistryEditBucketPolicy = require('nifi-registry/components/administration/workflow/dialogs/edit-bucket-policy/nf-registry-edit-bucket-policy.js');
+var NfRegistryAddPolicyToBucket = require('nifi-registry/components/administration/workflow/dialogs/add-policy-to-bucket/nf-registry-add-policy-to-bucket.js');
+var NfRegistryAddUserToGroups = require('nifi-registry/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.js');
+var NfRegistryAddUsersToGroup = require('nifi-registry/components/administration/users/dialogs/add-users-to-group/nf-registry-add-users-to-group.js');
+var NfRegistryManageUser = require('nifi-registry/components/administration/users/sidenav/manage-user/nf-registry-manage-user.js');
+var NfRegistryManageGroup = require('nifi-registry/components/administration/users/sidenav/manage-group/nf-registry-manage-group.js');
+var NfRegistryManageBucket = require('nifi-registry/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.js');
+var NfRegistryWorkflowAdministration = require('nifi-registry/components/administration/workflow/nf-registry-workflow-administration.js');
+var NfRegistryCreateBucket = require('nifi-registry/components/administration/workflow/dialogs/create-bucket/nf-registry-create-bucket.js');
+var NfRegistryGridListViewer = require('nifi-registry/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.js');
+var NfRegistryBucketGridListViewer = require('nifi-registry/components/explorer/grid-list/registry/nf-registry-bucket-grid-list-viewer.js');
+var NfRegistryDropletGridListViewer = require('nifi-registry/components/explorer/grid-list/registry/nf-registry-droplet-grid-list-viewer.js');
+var fdsCore = require('@fluid-design-system/core');
+var ngMoment = require('angular2-moment');
+var rxjs = require('rxjs/Rx');
+var ngCommonHttp = require('@angular/common/http');
+var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
+var NfStorage = require('nifi-registry/services/nf-storage.service.js');
+var NfLoginComponent = require('nifi-registry/components/login/nf-registry-login.js');
+var NfUserLoginComponent = require('nifi-registry/components/login/dialogs/nf-registry-user-login.js');
+
+describe('NfRegistryManageUser Component', function () {
+    var comp;
+    var fixture;
+    var nfRegistryService;
+    var nfRegistryApi;
+
+    beforeEach(function () {
+        ngCoreTesting.TestBed.configureTestingModule({
+            imports: [
+                ngMoment.MomentModule,
+                ngCommonHttp.HttpClientModule,
+                fdsCore,
+                NfRegistryRoutes
+            ],
+            declarations: [
+                NfRegistry,
+                NfRegistryExplorer,
+                NfRegistryAdministration,
+                NfRegistryUsersAdministration,
+                NfRegistryManageUser,
+                NfRegistryManageGroup,
+                NfRegistryManageBucket,
+                NfRegistryWorkflowAdministration,
+                NfRegistryAddUser,
+                NfRegistryCreateBucket,
+                NfRegistryCreateNewGroup,
+                NfRegistryAddUserToGroups,
+                NfRegistryAddUsersToGroup,
+                NfRegistryAddPolicyToBucket,
+                NfRegistryEditBucketPolicy,
+                NfRegistryGridListViewer,
+                NfRegistryBucketGridListViewer,
+                NfRegistryDropletGridListViewer,
+                NfPageNotFoundComponent,
+                NfLoginComponent,
+                NfUserLoginComponent
+            ],
+            entryComponents: [
+                NfRegistryAddUser,
+                NfRegistryCreateBucket,
+                NfRegistryCreateNewGroup,
+                NfRegistryAddUserToGroups,
+                NfRegistryAddUsersToGroup,
+                NfRegistryAddPolicyToBucket,
+                NfRegistryEditBucketPolicy,
+                NfUserLoginComponent
+            ],
+            providers: [
+                NfRegistryService,
+                NfRegistryApi,
+                NfStorage,
+                {
+                    provide: ngCommonHttp.HTTP_INTERCEPTORS,
+                    useClass: NfRegistryTokenInterceptor,
+                    multi: true
+                },
+                {
+                    provide: ngCommon.APP_BASE_HREF,
+                    useValue: '/'
+                },
+                {
+                    provide: ngRouter.ActivatedRoute,
+                    useValue: {
+                        params: rxjs.Observable.of({userId: '123'})
+                    }
+                }
+            ]
+        });
+        fixture = ngCoreTesting.TestBed.createComponent(NfRegistryManageUser);
+
+        // test instance
+        comp = fixture.componentInstance;
+
+        // from the root injector
+        nfRegistryService = ngCoreTesting.TestBed.get(NfRegistryService);
+        nfRegistryApi = ngCoreTesting.TestBed.get(NfRegistryApi);
+
+        // because the NfRegistryManageUser component is a nested route component we need to set up the nfRegistryService service manually
+        nfRegistryService.sidenav = {
+            open: function () {
+            },
+            close: function () {
+            }
+        };
+        nfRegistryService.user = {
+            identifier: 999,
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        };
+        nfRegistryService.users = [nfRegistryService.user];
+
+        //Spy
+        spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+    });
+
+    it('should have a defined component', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        expect(comp).toBeDefined();
+        expect(nfRegistryService.user.identifier).toEqual('123');
+
+        var getUserCall = nfRegistryApi.getUser.calls.first()
+        expect(getUserCall.args[0]).toBe('123');
+    }));
+
+    it('should FAIL to get user by id and redirect to admin users perspective', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var routerCall = comp.router.navigateByUrl.calls.first();
+        expect(routerCall.args[0]).toBe('/nifi-registry/administration/users');
+        expect(comp.router.navigateByUrl.calls.count()).toBe(1);
+    }));
+
+    it('should FAIL to get user by id and redirect to workflow perspective', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 409
+        }));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var routerCall = comp.router.navigateByUrl.calls.first();
+        expect(routerCall.args[0]).toBe('/nifi-registry/administration/workflow');
+        expect(comp.router.navigateByUrl.calls.count()).toBe(1);
+    }));
+
+    it('should redirect to users perspective', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        // the function to test
+        comp.closeSideNav();
+
+        //assertions
+        var routerCall = comp.router.navigateByUrl.calls.first();
+        expect(routerCall.args[0]).toBe('/nifi-registry/administration/users');
+        expect(comp.router.navigateByUrl.calls.count()).toBe(1);
+    }));
+
+    it('should toggle to create the manage bucket privileges for the current user', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(nfRegistryApi, 'postPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: [
+                {
+                    identifier: '123',
+                    identity: 'User #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleUserManageBucketsPrivileges({
+            checked: true
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.postPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to update the manage bucket privileges for the current user', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: []
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: [
+                {
+                    identifier: '123',
+                    identity: 'User #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleUserManageBucketsPrivileges({
+            checked: true
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to remove the manage bucket privileges for the current user', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 400,
+            users: [
+                {
+                    identifier: '123',
+                    identity: 'User #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleUserManageBucketsPrivileges({
+            checked: false
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to create the manage proxy privileges for the current user', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(nfRegistryApi, 'postPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: [
+                {
+                    identifier: '123',
+                    identity: 'User #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleUserManageProxyPrivileges({
+            checked: true
+        }, 'write');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.postPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to update the manage proxy privileges for the current user', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: []
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: [
+                {
+                    identifier: '123',
+                    identity: 'User #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleUserManageProxyPrivileges({
+            checked: true
+        }, 'write');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to remove the manage proxy privileges for the current user', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 400,
+            users: [
+                {
+                    identifier: '123',
+                    identity: 'User #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleUserManageProxyPrivileges({
+            checked: false
+        }, 'write');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to create the manage policies privileges for the current user', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(nfRegistryApi, 'postPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: [
+                {
+                    identifier: '123',
+                    identity: 'User #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleUserManagePoliciesPrivileges({
+            checked: true
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.postPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to update the manage policies privileges for the current user', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: []
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: [
+                {
+                    identifier: '123',
+                    identity: 'User #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleUserManagePoliciesPrivileges({
+            checked: true
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to remove the manage policies privileges for the current user', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 400,
+            users: [
+                {
+                    identifier: '123',
+                    identity: 'User #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleUserManagePoliciesPrivileges({
+            checked: false
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to create the manage tenants privileges for the current user', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 404
+        }));
+        spyOn(nfRegistryApi, 'postPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: [
+                {
+                    identifier: '123',
+                    identity: 'User #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleUserManageTenantsPrivileges({
+            checked: true
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.postPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to update the manage tenants privileges for the current user', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: []
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: [
+                {
+                    identifier: '123',
+                    identity: 'User #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleUserManageTenantsPrivileges({
+            checked: true
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+    }));
+
+    it('should toggle to remove the manage tenants privileges for the current user', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(nfRegistryApi, 'getPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            status: 400,
+            users: [
+                {
+                    identifier: '123',
+                    identity: 'User #1',
+                    resourcePermissions: {
+                        anyTopLevelResource: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        buckets: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        tenants: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        policies: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        },
+                        proxy: {
+                            canRead: false,
+                            canWrite: false,
+                            canDelete: false
+                        }
+                    }
+                }
+            ]
+        }));
+        spyOn(nfRegistryApi, 'putPolicyActionResource').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.toggleUserManageTenantsPrivileges({
+            checked: false
+        }, 'read');
+
+        //assertions
+        expect(nfRegistryApi.getPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.putPolicyActionResource.calls.count()).toBe(1);
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+    }));
+
+    it('should open a modal dialog UX enabling the addition of the current user to a group(s)', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp, 'filterGroups').and.callFake(function () {
+        });
+        spyOn(comp.dialog, 'open').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of({});
+                }
+            }
+        });
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.addUserToGroups();
+
+        //assertions
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+        expect(comp.filterGroups).toHaveBeenCalled();
+    }));
+
+    it('should remove user from group', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp, 'filterGroups').and.callFake(function () {
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            users: [{
+                identity: 'User #1'
+            }],
+            userGroups: [{
+                identity: 'Group #1'
+            }]
+        }));
+        spyOn(nfRegistryApi, 'updateUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({}));
+        spyOn(comp.router, 'navigateByUrl').and.callFake(function () {
+        });
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        var group = {
+            identifier: '123'
+        };
+
+        // the function to test
+        comp.removeUserFromGroup(group);
+
+        //assertions
+        expect(nfRegistryApi.getUser.calls.count()).toBe(2);
+        expect(nfRegistryApi.getUserGroup.calls.count()).toBe(1);
+        expect(nfRegistryApi.updateUserGroup.calls.count()).toBe(1);
+        expect(comp.snackBarService.openCoaster.calls.count()).toBe(1);
+        expect(comp.filterGroups).toHaveBeenCalled();
+    }));
+
+    it('should update user name', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp.dialogService, 'openConfirm').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of(true);
+                }
+            }
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        spyOn(nfRegistryApi, 'updateUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'test',
+            status: 200
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.updateUserName('test');
+
+        //assertions
+        expect(comp.snackBarService.openCoaster.calls.count()).toBe(1);
+        expect(comp.nfRegistryService.user.identity).toBe('test');
+    }));
+
+    it('should fail to update user name (409)', ngCoreTesting.fakeAsync(function () {
+        // Spy
+        spyOn(comp.dialogService, 'openConfirm').and.callFake(function () {
+            return {
+                afterClosed: function () {
+                    return rxjs.Observable.of(true);
+                }
+            }
+        });
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        spyOn(nfRegistryApi, 'updateUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'test',
+            status: 409
+        }));
+
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+
+        //assertions
+        var getUserCall = nfRegistryApi.getUser.calls.first();
+        expect(getUserCall.args[0]).toBe('123');
+        expect(nfRegistryApi.getUser.calls.count()).toBe(1);
+
+        // the function to test
+        comp.updateUserName('test');
+
+        //assertions
+        expect(comp.dialogService.openConfirm.calls.count()).toBe(1);
+        expect(comp.nfRegistryService.user.identity).toBe('User #1');
+    }));
+
+    it('should destroy the component', ngCoreTesting.fakeAsync(function () {
+        spyOn(nfRegistryService.sidenav, 'close');
+        spyOn(nfRegistryApi, 'getUser').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({
+            identifier: '123',
+            identity: 'User #1',
+            resourcePermissions: {
+                anyTopLevelResource: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                buckets: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                tenants: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                policies: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                },
+                proxy: {
+                    canRead: false,
+                    canWrite: false,
+                    canDelete: false
+                }
+            }
+        }));
+        // 1st change detection triggers ngOnInit
+        fixture.detectChanges();
+        // wait for async calls
+        ngCoreTesting.tick();
+        // 2nd change detection completes after the getUser calls
+        fixture.detectChanges();
+        spyOn(comp.$subscription, 'unsubscribe');
+
+        // The function to test
+        comp.ngOnDestroy();
+
+        //assertions
+        expect(nfRegistryService.sidenav.close).toHaveBeenCalled();
+        expect(nfRegistryService.user.identity).toBe('User #1');
+        expect(comp.$subscription.unsubscribe).toHaveBeenCalled();
+    }));
+});

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/nf-registry-workflow-administration.html
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/nf-registry-workflow-administration.html b/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/nf-registry-workflow-administration.html
index fd7453c..4b9744c 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/nf-registry-workflow-administration.html
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/nf-registry-workflow-administration.html
@@ -23,13 +23,15 @@ limitations under the License.
                       [items]="nfRegistryService.autoCompleteBuckets"
                       (add)="nfRegistryService.bucketsSearchAdd($event)"
                       (remove)="nfRegistryService.bucketsSearchRemove($event)"></td-chips>
-            <button class="push-top-sm push-right-sm"
-                    color="fds-secondary"
-                    mat-raised-button
-                    [disabled]="!nfRegistryService.currentUser.resourcePermissions.buckets.canWrite"
-                    (click)="createBucket()">
-                New Bucket
-            </button>
+            <div matTooltip="{{(!nfRegistryService.currentUser.resourcePermissions.buckets.canWrite) ? 'You do not have permission. Please contact your system administrator.': ''}}">
+                <button class="push-top-sm push-right-sm"
+                        color="fds-secondary"
+                        mat-raised-button
+                        [disabled]="!nfRegistryService.currentUser.resourcePermissions.buckets.canWrite"
+                        (click)="createBucket()">
+                    New Bucket
+                </button>
+            </div>
             <button class="push-top-sm" [disabled]="nfRegistryService.isMultiBucketActionsDisabled" color="fds-primary" mat-raised-button [matMenuTriggerFor]="bucketActionMenu">
                 Actions<i class="fa fa-caret-down" aria-hidden="true"></i>
             </button>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/nf-registry-workflow-administration.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/nf-registry-workflow-administration.spec.js b/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/nf-registry-workflow-administration.spec.js
index dcc73e8..0b881c0 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/nf-registry-workflow-administration.spec.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/nf-registry-workflow-administration.spec.js
@@ -42,7 +42,6 @@ var ngMoment = require('angular2-moment');
 var rxjs = require('rxjs/Rx');
 var ngCommonHttp = require('@angular/common/http');
 var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
-var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js');
 var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 var NfLoginComponent = require('nifi-registry/components/login/nf-registry-login.js');
 var NfUserLoginComponent = require('nifi-registry/components/login/dialogs/nf-registry-user-login.js');
@@ -87,7 +86,6 @@ describe('NfRegistryWorkflowAdministration Component', function () {
             ],
             providers: [
                 NfRegistryService,
-                NfRegistryAuthService,
                 NfRegistryApi,
                 NfStorage,
                 {
@@ -120,7 +118,7 @@ describe('NfRegistryWorkflowAdministration Component', function () {
 
         // Spy
         spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
-        spyOn(nfRegistryService, 'loadCurrentUser').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
         spyOn(nfRegistryApi, 'getBuckets').and.callFake(function () {
         }).and.returnValue(rxjs.Observable.of([{name: 'Bucket #1'}]));
         spyOn(nfRegistryService, 'filterBuckets');

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.html
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.html b/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.html
index 9f48951..86e0fac 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.html
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.html
@@ -44,7 +44,7 @@ limitations under the License.
             <div flex fxLayout="row" fxLayoutAlign="space-between center">
                 <span class="md-card-title">Policies ({{userIdentitiesWithPolicies.length + groupIdentitiesWithPolicies.length}})</span>
                 <button color="fds-secondary"
-                        [disabled]="nfRegistryService.currentUser.anonymous || !nfRegistryService.currentUser.resourcePermissions.policies.canWrite"
+                        [disabled]="nfRegistryService.currentUser.anonymous || !nfRegistryService.currentUser.resourcePermissions.policies.canWrite || !nfRegistryService.currentUser.resourcePermissions.tenants.canRead"
                         mat-raised-button
                         (click)="addPolicy()">
                     New Policy

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.js b/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.js
index 8f485df..c0b1b00 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/workflow/sidenav/manage-bucket/nf-registry-manage-bucket.js
@@ -70,7 +70,6 @@ NfRegistryManageBucket.prototype = {
      */
     ngOnInit: function () {
         var self = this;
-        this.nfRegistryService.sidenav.open();
         this.$subscription = this.route.params
             .switchMap(function (params) {
                 return new rxjs.Observable.forkJoin(
@@ -79,30 +78,36 @@ NfRegistryManageBucket.prototype = {
                 );
             })
             .subscribe(function (response) {
-                self.nfRegistryService.bucket = response[0];
-                self._bucketname = response[0].name;
-                if (!self.nfRegistryService.currentUser.anonymous) {
-                    if (!response[1].error) {
-                        var policies = response[1];
-                        policies.forEach(function (policy) {
-                            if (policy.resource.indexOf("/buckets/" + self.nfRegistryService.bucket.identifier) >= 0) {
-                                self.bucketPolicies.push(policy);
-                                policy.users.forEach(function (user) {
-                                    var userActionsForBucket = self.userPerms[user.identity] || [];
-                                    userActionsForBucket.push(policy.action);
-                                    self.userPerms[user.identity] = userActionsForBucket;
+                if (!response[0].status || response[0].status === 200) {
+                    self.nfRegistryService.sidenav.open();
+                    var bucket = response[0];
+                    self.nfRegistryService.bucket = bucket;
+                    self._bucketname = response[0].name;
+                    if (!self.nfRegistryService.currentUser.anonymous) {
+                        if (!response[1].status || response[1].status === 200) {
+                            var policies = response[1];
+                            policies.forEach(function (policy) {
+                                if (policy.resource.indexOf("/buckets/" + self.nfRegistryService.bucket.identifier) >= 0) {
+                                    self.bucketPolicies.push(policy);
+                                    policy.users.forEach(function (user) {
+                                        var userActionsForBucket = self.userPerms[user.identity] || [];
+                                        userActionsForBucket.push(policy.action);
+                                        self.userPerms[user.identity] = userActionsForBucket;
 
-                                });
-                                policy.userGroups.forEach(function (group) {
-                                    var groupActionsForBucket = self.groupPerms[group.identity] || [];
-                                    groupActionsForBucket.push(policy.action);
-                                    self.groupPerms[group.identity] = groupActionsForBucket;
+                                    });
+                                    policy.userGroups.forEach(function (group) {
+                                        var groupActionsForBucket = self.groupPerms[group.identity] || [];
+                                        groupActionsForBucket.push(policy.action);
+                                        self.groupPerms[group.identity] = groupActionsForBucket;
 
-                                });
-                            }
-                        });
-                        self.filterPolicies();
+                                    });
+                                }
+                            });
+                            self.filterPolicies();
+                        }
                     }
+                } else if (response[0].status === 404) {
+                    self.router.navigateByUrl('/nifi-registry/administration/workflow');
                 }
             });
     },
@@ -112,7 +117,6 @@ NfRegistryManageBucket.prototype = {
      */
     ngOnDestroy: function () {
         this.nfRegistryService.sidenav.close();
-        this.nfRegistryService.bucket = {};
         this.$subscription.unsubscribe();
     },
 
@@ -281,9 +285,9 @@ NfRegistryManageBucket.prototype = {
     },
 
     /**
-     * Remove user from group.
+     * Remove policy from bucket.
      *
-     * @param group
+     * @param userOrGroup       The user or group object
      */
     removePolicyFromBucket: function (userOrGroup) {
         var self = this;


[5/5] nifi-registry git commit: [NIFIREG-126] adding some polish and testing around deep links

Posted by kd...@apache.org.
[NIFIREG-126] adding some polish and testing around deep links

This closes #99.

Signed-off-by: Kevin Doran <kd...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/nifi-registry/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi-registry/commit/1bb1e2b6
Tree: http://git-wip-us.apache.org/repos/asf/nifi-registry/tree/1bb1e2b6
Diff: http://git-wip-us.apache.org/repos/asf/nifi-registry/diff/1bb1e2b6

Branch: refs/heads/master
Commit: 1bb1e2b654c17784a1dec36b53239c7d9ed48f3b
Parents: ed86f1a
Author: Scott Aslan <sc...@gmail.com>
Authored: Fri Feb 9 10:19:26 2018 -0500
Committer: Kevin Doran <kd...@apache.org>
Committed: Fri Feb 9 14:25:26 2018 -0500

----------------------------------------------------------------------
 .travis.yml                                     |    2 +-
 .../nifi/registry/service/RegistryService.java  |   92 +-
 .../registry/web/api/AccessPolicyResource.java  |    8 +-
 .../registry/web/api/BucketFlowResource.java    |    8 +-
 .../nifi/registry/web/api/TenantResource.java   |   24 +-
 .../web/api/UnsecuredNiFiRegistryClientIT.java  |    2 +-
 .../src/main/frontend/karma.conf.js             |    8 +-
 .../platform/core/common/styles/_buttons.scss   |    5 +
 .../core/common/styles/_checkboxes.scss         |    4 +
 .../platform/core/common/styles/_menus.scss     |    1 +
 .../nf-registry-administration.spec.js          |    2 -
 .../users/nf-registry-users-administration.html |   12 +-
 .../users/nf-registry-users-administration.js   |   20 +-
 .../nf-registry-users-adminstration.spec.js     |    4 +-
 .../manage-group/nf-registry-manage-group.js    |   17 +-
 .../nf-registry-manage-group.spec.js            | 2403 ++++++++++++++++++
 .../manage-user/nf-registry-manage-user.js      |   31 +-
 .../manage-user/nf-registry-manage-user.spec.js | 1816 +++++++++++++
 .../nf-registry-workflow-administration.html    |   16 +-
 .../nf-registry-workflow-administration.spec.js |    4 +-
 .../nf-registry-manage-bucket.html              |    2 +-
 .../manage-bucket/nf-registry-manage-bucket.js  |   54 +-
 .../nf-registry-manage-bucket.spec.js           |  766 ++++++
 .../nf-registry-bucket-grid-list-viewer.js      |   36 +-
 .../nf-registry-bucket-grid-list-viewer.spec.js |   50 +-
 .../nf-registry-droplet-grid-list-viewer.js     |   41 +-
 ...nf-registry-droplet-grid-list-viewer.spec.js |   72 +-
 .../registry/nf-registry-grid-list-viewer.html  |    6 +-
 .../nf-registry-grid-list-viewer.spec.js        |    4 +-
 .../explorer/nf-registry-explorer.spec.js       |    2 -
 .../src/main/webapp/nf-registry.module.js       |    2 -
 .../src/main/webapp/nf-registry.routes.js       |    5 +
 .../src/main/webapp/nf-registry.spec.js         |    2 -
 .../src/main/webapp/services/nf-registry.api.js |   62 +-
 .../webapp/services/nf-registry.api.spec.js     |  453 +++-
 .../services/nf-registry.auth-guard.service.js  |  237 +-
 .../nf-registry.auth-guard.service.spec.js      |  629 +++++
 .../webapp/services/nf-registry.auth.service.js |   46 -
 .../main/webapp/services/nf-registry.service.js |   25 -
 .../webapp/services/nf-registry.service.spec.js |    4 +-
 .../services/nf-registry.token.interceptor.js   |   14 +-
 .../src/main/webapp/systemjs.builder.config.js  |    1 -
 42 files changed, 6594 insertions(+), 398 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index 8b2bc35..d416986 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -55,5 +55,5 @@ install: true
 
 #build commands
 script:
-    - mvn -T 2C clean install -Pintegration-tests,contrib-check
+    - mvn -T 2C clean install -Pintegration-tests,contrib-check,jsUnitTests
 

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
index fad517f..802121e 100644
--- a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
+++ b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/RegistryService.java
@@ -149,7 +149,9 @@ public class RegistryService {
         try {
             final BucketEntity bucket = metadataService.getBucketById(bucketIdentifier);
             if (bucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + bucketIdentifier);
+                LOGGER.warn("The specified bucket id [{}] does not exist.", bucketIdentifier);
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             return DataModelMapper.map(bucket);
@@ -196,7 +198,9 @@ public class RegistryService {
             // ensure a bucket with the given id exists
             final BucketEntity existingBucketById = metadataService.getBucketById(bucket.getIdentifier());
             if (existingBucketById == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + bucket.getIdentifier());
+                LOGGER.warn("The specified bucket id [{}] does not exist.", bucket.getIdentifier());
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             // ensure a different bucket with the same name does not exist
@@ -239,7 +243,9 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + bucketIdentifier);
+                LOGGER.warn("The specified bucket id [{}] does not exist.", bucketIdentifier);
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             // for each flow in the bucket, delete all snapshots from the flow persistence provider
@@ -267,7 +273,9 @@ public class RegistryService {
         try {
             final BucketEntity bucket = metadataService.getBucketById(bucketIdentifier);
             if (bucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + bucketIdentifier);
+                LOGGER.warn("The specified bucket id [{}] does not exist.", bucketIdentifier);
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             final List<BucketItem> bucketItems = new ArrayList<>();
@@ -336,7 +344,9 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + bucketIdentifier);
+                LOGGER.warn("The specified bucket id [{}] does not exist.", bucketIdentifier);
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             // ensure another flow with the same name doesn't exist
@@ -371,12 +381,16 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + bucketIdentifier);
+                LOGGER.warn("The specified bucket id [{}] does not exist.", bucketIdentifier);
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             final FlowEntity existingFlow = metadataService.getFlowByIdWithSnapshotCounts(flowIdentifier);
             if (existingFlow == null) {
-                throw new ResourceNotFoundException("Versioned flow does not exist for identifier " + flowIdentifier);
+                LOGGER.warn("The specified flow id [{}] does not exist.", flowIdentifier);
+
+                throw new ResourceNotFoundException("The specified flow ID does not exist in this bucket.");
             }
 
             if (!existingBucket.getId().equals(existingFlow.getBucketId())) {
@@ -398,7 +412,9 @@ public class RegistryService {
         try {
             final BucketEntity existingBucket = metadataService.getBucketById(bucketId);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + bucketId);
+                LOGGER.warn("The specified bucket id [{}] does not exist.", bucketId);
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             // return non-verbose set of flows for the given bucket
@@ -431,12 +447,16 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(versionedFlow.getBucketIdentifier());
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + versionedFlow.getBucketIdentifier());
+                LOGGER.warn("The specified bucket id [{}] does not exist.", versionedFlow.getBucketIdentifier());
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             final FlowEntity existingFlow = metadataService.getFlowByIdWithSnapshotCounts(versionedFlow.getIdentifier());
             if (existingFlow == null) {
-                throw new ResourceNotFoundException("Versioned flow does not exist for identifier " + versionedFlow.getIdentifier());
+                LOGGER.warn("The specified flow id [{}] does not exist.", versionedFlow.getIdentifier());
+
+                throw new ResourceNotFoundException("The specified flow ID does not exist in this bucket.");
             }
 
             if (!existingBucket.getId().equals(existingFlow.getBucketId())) {
@@ -486,13 +506,17 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + bucketIdentifier);
+                LOGGER.warn("The specified bucket id [{}] does not exist.", bucketIdentifier);
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             // ensure the flow exists
             final FlowEntity existingFlow = metadataService.getFlowById(flowIdentifier);
             if (existingFlow == null) {
-                throw new ResourceNotFoundException("Versioned flow does not exist for identifier " + flowIdentifier);
+                LOGGER.warn("The specified flow id [{}] does not exist.", flowIdentifier);
+
+                throw new ResourceNotFoundException("The specified flow ID does not exist in this bucket.");
             }
 
             if (!existingBucket.getId().equals(existingFlow.getBucketId())) {
@@ -536,13 +560,17 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(snapshotMetadata.getBucketIdentifier());
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + snapshotMetadata.getBucketIdentifier());
+                LOGGER.warn("The specified bucket id [{}] does not exist.", snapshotMetadata.getBucketIdentifier());
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             // ensure the flow exists, we need to use "with counts" here so we can return this is a part of the response
             final FlowEntity existingFlow = metadataService.getFlowByIdWithSnapshotCounts(snapshotMetadata.getFlowIdentifier());
             if (existingFlow == null) {
-                throw new ResourceNotFoundException("Versioned flow does not exist for identifier " + snapshotMetadata.getFlowIdentifier());
+                LOGGER.warn("The specified flow id [{}] does not exist.", snapshotMetadata.getFlowIdentifier());
+
+                throw new ResourceNotFoundException("The specified flow ID does not exist in this bucket.");
             }
 
             if (!existingBucket.getId().equals(existingFlow.getBucketId())) {
@@ -614,13 +642,17 @@ public class RegistryService {
         try {
             final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + bucketIdentifier);
+                LOGGER.warn("The specified bucket id [{}] does not exist.", bucketIdentifier);
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             // we need to populate the version count here so we have to do this retrieval instead of snapshotEntity.getFlow()
             final FlowEntity flowEntityWithCount = metadataService.getFlowByIdWithSnapshotCounts(flowIdentifier);
             if (flowEntityWithCount == null) {
-                throw new ResourceNotFoundException("Versioned flow does not exist with identifier " + flowIdentifier);
+                LOGGER.warn("The specified flow id [{}] does not exist.", flowIdentifier);
+
+                throw new ResourceNotFoundException("The specified flow ID does not exist in this bucket.");
             }
 
             if (!existingBucket.getId().equals(flowEntityWithCount.getBucketId())) {
@@ -630,7 +662,9 @@ public class RegistryService {
             // ensure the snapshot exists
             final FlowSnapshotEntity snapshotEntity = metadataService.getFlowSnapshot(flowIdentifier, version);
             if (snapshotEntity == null) {
-                throw new ResourceNotFoundException("Versioned flow snapshot does not exist for flow " + flowIdentifier + " and version " + version);
+                LOGGER.warn("The specified flow snapshot id [{}] does not exist for version [{}].", flowIdentifier, version);
+
+                throw new ResourceNotFoundException("The specified versioned flow snapshot does not exist for this flow.");
             }
 
             // get the serialized bytes of the snapshot
@@ -683,13 +717,17 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + bucketIdentifier);
+                LOGGER.warn("The specified bucket id [{}] does not exist.", bucketIdentifier);
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             // ensure the flow exists
             final FlowEntity existingFlow = metadataService.getFlowById(flowIdentifier);
             if (existingFlow == null) {
-                throw new ResourceNotFoundException("Versioned flow does not exist for identifier " + flowIdentifier);
+                LOGGER.warn("The specified flow id [{}] does not exist.", flowIdentifier);
+
+                throw new ResourceNotFoundException("The specified flow ID does not exist in this bucket.");
             }
 
             if (!existingBucket.getId().equals(existingFlow.getBucketId())) {
@@ -724,13 +762,17 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + bucketIdentifier);
+                LOGGER.warn("The specified bucket id [{}] does not exist.", bucketIdentifier);
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             // ensure the flow exists
             final FlowEntity existingFlow = metadataService.getFlowById(flowIdentifier);
             if (existingFlow == null) {
-                throw new ResourceNotFoundException("Versioned flow does not exist for identifier " + flowIdentifier);
+                LOGGER.warn("The specified flow id [{}] does not exist.", flowIdentifier);
+
+                throw new ResourceNotFoundException("The specified flow ID does not exist in this bucket.");
             }
 
             if (!existingBucket.getId().equals(existingFlow.getBucketId())) {
@@ -763,13 +805,17 @@ public class RegistryService {
             // ensure the bucket exists
             final BucketEntity existingBucket = metadataService.getBucketById(bucketIdentifier);
             if (existingBucket == null) {
-                throw new ResourceNotFoundException("Bucket does not exist for identifier " + bucketIdentifier);
+                LOGGER.warn("The specified bucket id [{}] does not exist.", bucketIdentifier);
+
+                throw new ResourceNotFoundException("The specified bucket ID does not exist in this registry.");
             }
 
             // ensure the flow exists
             final FlowEntity existingFlow = metadataService.getFlowById(flowIdentifier);
             if (existingFlow == null) {
-                throw new ResourceNotFoundException("Versioned flow does not exist for identifier " + flowIdentifier);
+                LOGGER.warn("The specified flow id [{}] does not exist.", flowIdentifier);
+
+                throw new ResourceNotFoundException("The specified flow ID does not exist in this bucket.");
             }
 
             if (!existingBucket.getId().equals(existingFlow.getBucketId())) {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java
index f918d4c..68bc493 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessPolicyResource.java
@@ -174,7 +174,9 @@ public class AccessPolicyResource extends AuthorizableApplicationResource {
 
         final AccessPolicy accessPolicy = authorizationService.getAccessPolicy(identifier);
         if (accessPolicy == null) {
-            throw new ResourceNotFoundException("No access policy found with ID + " + identifier);
+            logger.warn("The specified access policy id [{}] does not exist.", identifier);
+
+            throw new ResourceNotFoundException("The specified policy does not exist in this registry.");
         }
 
         return generateOkResponse(accessPolicy).build();
@@ -309,7 +311,9 @@ public class AccessPolicyResource extends AuthorizableApplicationResource {
         authorizeAccess(RequestAction.DELETE);
         AccessPolicy deletedPolicy = authorizationService.deleteAccessPolicy(identifier);
         if (deletedPolicy == null) {
-            throw new ResourceNotFoundException("No access policy found with ID + " + identifier);
+            logger.warn("The specified access policy id [{}] does not exist.", identifier);
+
+            throw new ResourceNotFoundException("The specified policy does not exist in this registry.");
         }
         return generateOkResponse(deletedPolicy).build();
     }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
index dbe6407..e645a40 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketFlowResource.java
@@ -333,7 +333,9 @@ public class BucketFlowResource extends AuthorizableApplicationResource {
 
         final VersionedFlowSnapshotMetadata latest = registryService.getLatestFlowSnapshotMetadata(bucketId, flowId);
         if (latest == null) {
-            throw new ResourceNotFoundException("No flow versions found for flow with id " + flowId);
+            logger.warn("The specified flow id [{}] does not exist.", flowId);
+
+            throw new ResourceNotFoundException("The specified flow ID does not exist in this bucket.");
         }
 
         final VersionedFlowSnapshot lastSnapshot = registryService.getFlowSnapshot(bucketId, flowId, latest.getVersion());
@@ -367,7 +369,9 @@ public class BucketFlowResource extends AuthorizableApplicationResource {
 
         final VersionedFlowSnapshotMetadata latest = registryService.getLatestFlowSnapshotMetadata(bucketId, flowId);
         if (latest == null) {
-            throw new ResourceNotFoundException("No flow versions found for flow with id " + flowId);
+            logger.warn("The specified flow id [{}] does not exist.", flowId);
+
+            throw new ResourceNotFoundException("The specified flow ID does not exist in this bucket.");
         }
 
         linkService.populateSnapshotLinks(latest);

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/TenantResource.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/TenantResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/TenantResource.java
index 07db72b..1d838c4 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/TenantResource.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/TenantResource.java
@@ -182,7 +182,9 @@ public class TenantResource extends AuthorizableApplicationResource {
 
         final User user = authorizationService.getUser(identifier);
         if (user == null) {
-            throw new ResourceNotFoundException("No user found with identifier " + identifier);
+            logger.warn("The specified user id [{}] does not exist.", identifier);
+
+            throw new ResourceNotFoundException("The specified user ID does not exist in this registry.");
         }
         return generateOkResponse(user).build();
     }
@@ -230,7 +232,9 @@ public class TenantResource extends AuthorizableApplicationResource {
 
         final User updatedUser = authorizationService.updateUser(requestUser);
         if (updatedUser == null) {
-            throw new ResourceNotFoundException("No user found with identifier " + identifier);
+            logger.warn("The specified user id [{}] does not exist.", identifier);
+
+            throw new ResourceNotFoundException("The specified user ID does not exist in this registry.");
         }
 
         return generateOkResponse(updatedUser).build();
@@ -268,7 +272,9 @@ public class TenantResource extends AuthorizableApplicationResource {
 
         final User user = authorizationService.deleteUser(identifier);
         if (user == null) {
-            throw new ResourceNotFoundException("No user found with identifier " + identifier);
+            logger.warn("The specified user id [{}] does not exist.", identifier);
+
+            throw new ResourceNotFoundException("The specified user ID does not exist in this registry.");
         }
         return generateOkResponse(user).build();
     }
@@ -382,7 +388,9 @@ public class TenantResource extends AuthorizableApplicationResource {
 
         final UserGroup userGroup = authorizationService.getUserGroup(identifier);
         if (userGroup == null) {
-            throw new ResourceNotFoundException("No group found with identifier " + identifier);
+            logger.warn("The specified user group id [{}] does not exist.", identifier);
+
+            throw new ResourceNotFoundException("The specified user group ID does not exist in this registry.");
         }
 
         return generateOkResponse(userGroup).build();
@@ -432,7 +440,9 @@ public class TenantResource extends AuthorizableApplicationResource {
 
         UserGroup updatedUserGroup = authorizationService.updateUserGroup(requestUserGroup);
         if (updatedUserGroup == null) {
-            throw new ResourceNotFoundException("No group found with identifier " + identifier);
+            logger.warn("The specified user group id [{}] does not exist.", identifier);
+
+            throw new ResourceNotFoundException("The specified user group ID does not exist in this registry.");
         }
 
         return generateOkResponse(updatedUserGroup).build();
@@ -470,7 +480,9 @@ public class TenantResource extends AuthorizableApplicationResource {
 
         final UserGroup userGroup = authorizationService.deleteUserGroup(identifier);
         if (userGroup == null) {
-            throw new ResourceNotFoundException("No group found with identifier " + identifier);
+            logger.warn("The specified user group id [{}] does not exist.", identifier);
+
+            throw new ResourceNotFoundException("The specified user group ID does not exist in this registry.");
         }
 
         return generateOkResponse(userGroup).build();

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java
index c733f26..d093943 100644
--- a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java
+++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/UnsecuredNiFiRegistryClientIT.java
@@ -243,7 +243,7 @@ public class UnsecuredNiFiRegistryClientIT extends UnsecuredITBase {
             snapshotClient.getLatestMetadata(snapshotFlow.getBucketIdentifier(), "DOES-NOT-EXIST");
             Assert.fail("Should have thrown exception");
         } catch (NiFiRegistryException nfe) {
-            Assert.assertEquals("Error retrieving latest snapshot metadata: Versioned flow does not exist for identifier DOES-NOT-EXIST", nfe.getMessage());
+            Assert.assertEquals("Error retrieving latest snapshot metadata: The specified flow ID does not exist in this bucket.", nfe.getMessage());
         }
 
         // ---------------------- TEST ITEMS --------------------------//

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/frontend/karma.conf.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/frontend/karma.conf.js b/nifi-registry-web-ui/src/main/frontend/karma.conf.js
index 8a63bfd..27a521d 100644
--- a/nifi-registry-web-ui/src/main/frontend/karma.conf.js
+++ b/nifi-registry-web-ui/src/main/frontend/karma.conf.js
@@ -28,8 +28,8 @@ module.exports = function (config) {
         frameworks: ['jasmine'],
         customLaunchers: {
             Chrome_travis_ci: {
-                base: 'Chrome',
-                flags: []
+                base: 'ChromeHeadless',
+                flags: ['--no-sandbox']
             }
         },
         plugins: [
@@ -142,7 +142,7 @@ module.exports = function (config) {
         preprocessors: {
             'webapp/**/!(*spec|*mock|*stub|*config|*extras|*fds-demo).js': 'coverage'
         },
-        reporters: ['kjhtml', 'coverage'],
+        reporters: ['kjhtml', 'spec', 'coverage'],
         coverageReporter: {
             type: 'html',
             dir: 'coverage/'
@@ -155,7 +155,7 @@ module.exports = function (config) {
         logLevel: config.LOG_INFO,
         autoWatch: true,
         browsers: ['Chrome'],
-        singleRun: true
+        singleRun: false
     });
 
     if (process.env.TRAVIS) {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/platform/core/common/styles/_buttons.scss
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/platform/core/common/styles/_buttons.scss b/nifi-registry-web-ui/src/main/platform/core/common/styles/_buttons.scss
index c8d4802..8b316ea 100644
--- a/nifi-registry-web-ui/src/main/platform/core/common/styles/_buttons.scss
+++ b/nifi-registry-web-ui/src/main/platform/core/common/styles/_buttons.scss
@@ -75,6 +75,11 @@ body[fds] .mat-raised-button.cdk-focused:focus {
 
 body[fds] .mat-raised-button[disabled] {
   opacity: .6;
+  cursor: not-allowed;
+}
+
+body[fds] .mat-button-toggle-disabled .mat-button-toggle-label-content {
+  cursor: not-allowed;
 }
 
 body[fds] .mat-button-focus-overlay {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/platform/core/common/styles/_checkboxes.scss
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/platform/core/common/styles/_checkboxes.scss b/nifi-registry-web-ui/src/main/platform/core/common/styles/_checkboxes.scss
index 353ec0a..0268fde 100644
--- a/nifi-registry-web-ui/src/main/platform/core/common/styles/_checkboxes.scss
+++ b/nifi-registry-web-ui/src/main/platform/core/common/styles/_checkboxes.scss
@@ -79,3 +79,7 @@ body[fds] .mat-pseudo-checkbox-checked, body[fds] .mat-pseudo-checkbox-indetermi
   height: 10px;
   width: 10px;
 }
+
+body[fds] .mat-checkbox-disabled {
+  cursor: not-allowed;
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/platform/core/common/styles/_menus.scss
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/platform/core/common/styles/_menus.scss b/nifi-registry-web-ui/src/main/platform/core/common/styles/_menus.scss
index 5a0c6a9..fdd9194 100644
--- a/nifi-registry-web-ui/src/main/platform/core/common/styles/_menus.scss
+++ b/nifi-registry-web-ui/src/main/platform/core/common/styles/_menus.scss
@@ -38,6 +38,7 @@ body[fds] .regular-button-menu .mat-menu-item:hover {
 body[fds] .mat-menu-item[disabled] {
   color: rgba(0, 0, 0, 0.38);
   background-color: #ffffff;
+  cursor: not-allowed;
 }
 
 body[fds] .mat-menu-item .mat-icon {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.spec.js b/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.spec.js
index 7d1165e..90b4965 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.spec.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.spec.js
@@ -20,7 +20,6 @@ var ngCoreTesting = require('@angular/core/testing');
 var ngCommon = require('@angular/common');
 var ngCommonHttp = require('@angular/common/http');
 var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
-var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js');
 var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 var ngPlatformBrowser = require('@angular/platform-browser');
 var NfRegistry = require('nifi-registry/nf-registry.js');
@@ -79,7 +78,6 @@ describe('NfRegistryAdministration Component', function () {
             ],
             providers: [
                 NfRegistryService,
-                NfRegistryAuthService,
                 NfRegistryApi,
                 NfStorage,
                 {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-administration.html
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-administration.html b/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-administration.html
index 501a8a7..7a31b0a 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-administration.html
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-administration.html
@@ -23,9 +23,11 @@ limitations under the License.
                       [items]="nfRegistryService.autoCompleteUsersAndGroups"
                       (add)="nfRegistryService.usersSearchAdd($event)"
                       (remove)="nfRegistryService.usersSearchRemove($event)"></td-chips>
-            <button class="push-top-sm push-right-sm" color="fds-secondary" mat-raised-button (click)="addUser()">
-                Add User
-            </button>
+            <div matTooltip="{{(!nfRegistryService.currentUser.resourcePermissions.tenants.canWrite) ? 'You do not have permission. Please contact your system administrator.': ''}}">
+                <button class="push-top-sm push-right-sm" color="fds-secondary" mat-raised-button (click)="addUser()" [disabled]="!nfRegistryService.currentUser.resourcePermissions.tenants.canWrite">
+                    Add User
+                </button>
+            </div>
             <button class="push-top-sm" color="fds-primary"
                     mat-raised-button [matMenuTriggerFor]="userActionMenu">
                 Actions<i class="fa fa-caret-down" aria-hidden="true"></i>
@@ -39,8 +41,8 @@ limitations under the License.
                     <span>Delete</span>
                 </button>
             </div>
-            <div matTooltip="{{(nfRegistryService.getSelectedGroups().length > 0) ? 'Only users can be added when creating a new group. Please deselect any groups to enable.': ''}}">
-                <button mat-menu-item [disabled]="(nfRegistryService.getSelectedGroups().length > 0)"
+            <div matTooltip="{{(nfRegistryService.getSelectedGroups().length > 0) ? 'Only users can be added when creating a new group. Please deselect any groups to enable.': (!nfRegistryService.currentUser.resourcePermissions.tenants.canWrite) ? 'You do not have permission. Please contact your system administrator.': ''}}">
+                <button mat-menu-item [disabled]="(nfRegistryService.getSelectedGroups().length > 0) || !nfRegistryService.currentUser.resourcePermissions.tenants.canWrite"
                     (click)="createNewGroup()">
                     <span>Create new group</span>
                 </button>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-administration.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-administration.js b/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-administration.js
index 89ce645..77f9906 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-administration.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-administration.js
@@ -65,10 +65,22 @@ NfRegistryUsersAdministration.prototype = {
                 );
             })
             .subscribe(function (response) {
-                var users = response[0];
-                var groups = response[1];
-                self.nfRegistryService.users = users;
-                self.nfRegistryService.groups = groups;
+                if (!response[0].status || response[0].status === 200) {
+                    var users = response[0];
+                    self.nfRegistryService.users = users;
+                } else if (response[0].status === 404) {
+                    self.router.navigateByUrl('/nifi-registry/administration/users');
+                } else if (response[0].status === 409) {
+                    self.router.navigateByUrl('/nifi-registry/administration/workflow');
+                }
+                if (!response[1].status || response[1].status === 200) {
+                    var groups = response[1];
+                    self.nfRegistryService.groups = groups;
+                } else if (response[1].status === 404) {
+                    self.router.navigateByUrl('/nifi-registry/administration/users');
+                } else if (response[1].status === 409) {
+                    self.router.navigateByUrl('/nifi-registry/administration/workflow');
+                }
                 self.nfRegistryService.filterUsersAndGroups();
                 self.nfRegistryService.inProgress = false;
             });

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-adminstration.spec.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-adminstration.spec.js b/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-adminstration.spec.js
index c99700c..f0bb42e 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-adminstration.spec.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/users/nf-registry-users-adminstration.spec.js
@@ -42,7 +42,6 @@ var ngMoment = require('angular2-moment');
 var rxjs = require('rxjs/Rx');
 var ngCommonHttp = require('@angular/common/http');
 var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js');
-var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js');
 var NfStorage = require('nifi-registry/services/nf-storage.service.js');
 var NfLoginComponent = require('nifi-registry/components/login/nf-registry-login.js');
 var NfUserLoginComponent = require('nifi-registry/components/login/dialogs/nf-registry-user-login.js');
@@ -87,7 +86,6 @@ describe('NfRegistryUsersAdministration Component', function () {
             ],
             providers: [
                 NfRegistryService,
-                NfRegistryAuthService,
                 NfRegistryApi,
                 NfStorage,
                 {
@@ -120,7 +118,7 @@ describe('NfRegistryUsersAdministration Component', function () {
 
         // Spy
         spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
-        spyOn(nfRegistryService, 'loadCurrentUser').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
+        spyOn(nfRegistryApi, 'loadCurrentUser').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({}));
         spyOn(nfRegistryApi, 'getUsers').and.callFake(function () {
         }).and.returnValue(rxjs.Observable.of([{
             "identifier": "2e04b4fb-9513-47bb-aa74-1ae34616bfdc",

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/1bb1e2b6/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-group/nf-registry-manage-group.js
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-group/nf-registry-manage-group.js b/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-group/nf-registry-manage-group.js
index 9aaa684..4afff3e 100644
--- a/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-group/nf-registry-manage-group.js
+++ b/nifi-registry-web-ui/src/main/webapp/components/administration/users/sidenav/manage-group/nf-registry-manage-group.js
@@ -63,17 +63,22 @@ NfRegistryManageGroup.prototype = {
      */
     ngOnInit: function () {
         var self = this;
-        this.nfRegistryService.sidenav.open();
-
         // subscribe to the route params
         this.$subscription = self.route.params
             .switchMap(function (params) {
                 return self.nfRegistryApi.getUserGroup(params['groupId']);
             })
             .subscribe(function (response) {
-                self.nfRegistryService.group = response;
-                self._groupname = response.identity;
-                self.filterUsers();
+                if (!response.status || response.status === 200) {
+                    self.nfRegistryService.sidenav.open();
+                    self.nfRegistryService.group = response;
+                    self._groupname = response.identity;
+                    self.filterUsers();
+                } else if (response.status === 404) {
+                    self.router.navigateByUrl('/nifi-registry/administration/users');
+                } else if (response.status === 409) {
+                    self.router.navigateByUrl('/nifi-registry/administration/workflow');
+                }
             });
     },
 
@@ -542,7 +547,7 @@ NfRegistryManageGroup.prototype = {
                     color: '#1EB475',
                     duration: 3000
                 });
-            } else if (response.status === 404) {
+            } else if (response.status === 409) {
                 self._groupname = self.nfRegistryService.group.identity;
                 self.dialogService.openConfirm({
                     title: 'Error',