NIFIREG-30 - Add login component, auth guard to login, tenants, buckets, admin, 
and explorer routes. Also added route for login component.

NIFIREG-20 - Improve page load times.

NIFIREG-15 - Add loading screen.

This closes #58.

Signed-off-by: Bryan Bende <bbe...@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/580f7754
Tree: http://git-wip-us.apache.org/repos/asf/nifi-registry/tree/580f7754
Diff: http://git-wip-us.apache.org/repos/asf/nifi-registry/diff/580f7754

Branch: refs/heads/master
Commit: 580f77549bef6fb582749c13fa99cb344482bdb4
Parents: 287cc41
Author: Scott Aslan <scottyas...@gmail.com>
Authored: Thu Dec 14 16:25:32 2017 -0500
Committer: Bryan Bende <bbe...@apache.org>
Committed: Fri Dec 15 15:12:06 2017 -0500

----------------------------------------------------------------------
 .../src/main/locale/messages.es.xlf             |  44 +-
 .../core/common/styles/_globalVars.scss         |   4 +-
 .../core/common/styles/_helperClasses.scss      |   5 +
 .../platform/core/common/styles/_inputs.scss    |   2 +-
 .../platform/core/common/styles/_stepper.scss   |  20 +
 .../core/common/styles/fluid-design-system.scss |   1 +
 .../src/main/webapp/WEB-INF/web.xml             |  10 +
 .../nf-registry-administration.html             |  22 +-
 .../nf-registry-administration.js               |  35 +-
 .../nf-registry-administration.spec.js          |  16 +-
 .../nf-registry-user-group-permissions.html     |  28 -
 .../nf-registry-user-group-permissions.js       |  70 ---
 .../users/details/nf-registry-user-details.html |  28 -
 .../users/details/nf-registry-user-details.js   |  69 ---
 ...nf-registry-add-selected-users-to-group.html |  75 ---
 .../nf-registry-add-selected-users-to-group.js  | 237 --------
 ...registry-add-selected-users-to-group.spec.js | 169 ------
 .../nf-registry-add-user-to-groups.html         |  80 +++
 .../nf-registry-add-user-to-groups.js           | 235 ++++++++
 .../nf-registry-add-user-to-groups.spec.js      | 172 ++++++
 .../dialogs/add-user/nf-registry-add-user.js    |   2 +-
 .../nf-registry-add-users-to-group.html         |  80 +++
 .../nf-registry-add-users-to-group.js           | 234 ++++++++
 .../nf-registry-add-users-to-group.spec.js      | 170 ++++++
 .../users/nf-registry-users-administration.html |  24 +-
 .../users/nf-registry-users-administration.js   |  73 +--
 .../nf-registry-users-adminstration.spec.js     |  27 +-
 .../nf-registry-user-permissions.html           |  28 -
 .../permissions/nf-registry-user-permissions.js |  69 ---
 .../manage-group/nf-registry-manage-group.html  | 154 +++++
 .../manage-group/nf-registry-manage-group.js    | 577 +++++++++++++++++++
 .../manage-user/nf-registry-manage-user.html    | 158 +++++
 .../manage-user/nf-registry-manage-user.js      | 577 +++++++++++++++++++
 .../nf-registry-bucket-permissions.html         |  88 ++-
 .../nf-registry-workflow-administration.html    |  10 +-
 .../nf-registry-workflow-administration.js      |  33 +-
 .../nf-registry-workflow-administration.spec.js |  16 +-
 .../nf-registry-bucket-grid-list-viewer.js      |  42 +-
 .../nf-registry-bucket-grid-list-viewer.spec.js |  17 +-
 .../nf-registry-droplet-grid-list-viewer.js     |  49 +-
 ...nf-registry-droplet-grid-list-viewer.spec.js |  17 +-
 .../registry/nf-registry-grid-list-viewer.html  |   9 +-
 .../registry/nf-registry-grid-list-viewer.js    |  32 +-
 .../nf-registry-grid-list-viewer.spec.js        |  16 +-
 .../explorer/nf-registry-explorer.spec.js       |  16 +-
 .../login/dialogs/nf-registry-user-login.html   |  45 ++
 .../login/dialogs/nf-registry-user-login.js     |  69 +++
 .../components/login/nf-registry-login.html     |  19 +
 .../components/login/nf-registry-login.js       |  64 ++
 .../nf-registry-page-not-found.html             |  19 +
 .../nf-registry-page-not-found.js               |  45 +-
 .../src/main/webapp/nf-registry.html            |  14 +-
 .../src/main/webapp/nf-registry.js              |   3 +-
 .../src/main/webapp/nf-registry.module.js       |  31 +-
 .../src/main/webapp/nf-registry.routes.js       |  46 +-
 .../src/main/webapp/nf-registry.spec.js         |  16 +-
 .../src/main/webapp/services/nf-registry.api.js | 197 ++++++-
 .../webapp/services/nf-registry.api.spec.js     |  21 +-
 .../services/nf-registry.auth-guard.service.js  | 257 +++++++++
 .../webapp/services/nf-registry.auth.service.js |   2 +-
 .../main/webapp/services/nf-registry.service.js | 267 +++++++--
 .../webapp/services/nf-registry.service.spec.js |  30 +-
 .../src/main/webapp/systemjs.builder.config.js  |  11 +-
 .../main/webapp/theming/_structureElements.scss |  26 +-
 64 files changed, 3854 insertions(+), 1168 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/locale/messages.es.xlf
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/locale/messages.es.xlf 
b/nifi-registry-web-ui/src/main/locale/messages.es.xlf
index 9a093c9..9bee8cd 100644
--- a/nifi-registry-web-ui/src/main/locale/messages.es.xlf
+++ b/nifi-registry-web-ui/src/main/locale/messages.es.xlf
@@ -35,46 +35,76 @@
         <note priority="1" from="description">A description of the type of 
administration options available.</note>
         <note priority="1" from="meaning">Workflow administration tab</note>
        </trans-unit>
+      <trans-unit id="nf-admin-user-management-sidenav-membership-tab-title" 
datatype="html">
+         <source>Membership</source>
+         <target state="new">afiliación</target>
+        <note priority="1" from="description">View the groups to which this 
user belongs.</note>
+        <note priority="1" from="meaning">Group membership tab, user 
management sidenav</note>
+       </trans-unit>
+      <trans-unit id="nf-admin-group-management-sidenav-membership-tab-title" 
datatype="html">
+         <source>Membership</source>
+         <target state="new">afiliación</target>
+        <note priority="1" from="description">View the users that belong to 
this group.</note>
+        <note priority="1" from="meaning">User membership tab, group 
management sidenav</note>
+       </trans-unit>
+      <trans-unit id="nf-admin-user-management-sidenav-policies-tab-title" 
datatype="html">
+         <source>Policies</source>
+         <target state="new">Políticas</target>
+        <note priority="1" from="description">View the policies grated this 
user.</note>
+        <note priority="1" from="meaning">User policy tab, user management 
sidenav</note>
+       </trans-unit>
       <trans-unit id="nf-admin-workflow-create-bucket-button" datatype="html">
          <source>Create</source>
          <target state="new">Crear</target>
-        <note priority="1" from="description">A button for creating a new 
bucket in the registry.@@nf-admin-workflow-create-bucket-button.</note>
+        <note priority="1" from="description">A button for creating a new 
bucket in the registry.</note>
         <note priority="1" from="meaning">Create new bucket button</note>
        </trans-unit>
       <trans-unit id="nf-admin-workflow-add-user-button" datatype="html">
          <source>Add</source>
          <target state="new">añadir</target>
-        <note priority="1" from="description">A button for adding a new user 
in the registry.@@nf-admin-workflow-add-user-button.</note>
+        <note priority="1" from="description">A button for adding a new user 
in the registry.</note>
         <note priority="1" from="meaning">Add new user button</note>
        </trans-unit>
       <trans-unit id="nf-admin-workflow-cancel-add-user-button" 
datatype="html">
          <source>Cancel</source>
          <target state="new">Cancelar</target>
-        <note priority="1" from="description">A button for cancelling the 
creation of a new user in the 
registry.@@nf-admin-workflow-add-user-button.</note>
+        <note priority="1" from="description">A button for cancelling the 
creation of a new user in the registry.</note>
         <note priority="1" from="meaning">Cancel creation of new user</note>
        </trans-unit>
+      <trans-unit id="nf-clear-user-login-button" datatype="html">
+         <source>Clear</source>
+         <target state="new">Claro</target>
+        <note priority="1" from="description">A button for clearing the login 
form.</note>
+        <note priority="1" from="meaning">Clear log in form</note>
+       </trans-unit>
+      <trans-unit id="nf-user-login-button" datatype="html">
+         <source>Log In</source>
+         <target state="new">Iniciar sesión</target>
+        <note priority="1" from="description">A button for attempting to 
authenticate with the registry.</note>
+        <note priority="1" from="meaning">Log in form</note>
+       </trans-unit>
       <trans-unit id="nf-admin-workflow-create-new-group-button" 
datatype="html">
          <source>Create</source>
          <target state="new">Crear</target>
-        <note priority="1" from="description">A button for creating a new 
group in the registry.@@nf-admin-workflow-create-new-group-button.</note>
+        <note priority="1" from="description">A button for creating a new 
group in the registry.</note>
         <note priority="1" from="meaning">Create new group button</note>
        </trans-unit>
       <trans-unit id="nf-admin-workflow-cancel-create-new-group-button" 
datatype="html">
          <source>Cancel</source>
          <target state="new">Cancelar</target>
-        <note priority="1" from="description">A button for cancelling the 
creation of a new group in the 
registry.@@nf-admin-workflow-cancel-create-new-group-button.</note>
+        <note priority="1" from="description">A button for cancelling the 
creation of a new group in the registry.</note>
         <note priority="1" from="meaning">Cancel creation of new group</note>
        </trans-unit>
       <trans-unit id="nf-admin-workflow-add-selected-users-to-group-button" 
datatype="html">
          <source>Add</source>
          <target state="new">añadir</target>
-        <note priority="1" from="description">A button for adding users to an 
existing group in the 
registry.@@nf-admin-workflow-create-new-group-button.</note>
+        <note priority="1" from="description">A button for adding users to an 
existing group in the registry.</note>
         <note priority="1" from="meaning">Add selected users to group 
button</note>
        </trans-unit>
       <trans-unit 
id="nf-admin-workflow-cancel-add-selected-users-to-group-button" 
datatype="html">
          <source>Cancel</source>
          <target state="new">Cancelar</target>
-        <note priority="1" from="description">A button for cancelling the 
addition of selected users to a group in the 
registry.@@nf-admin-workflow-cancel-create-new-group-button.</note>
+        <note priority="1" from="description">A button for cancelling the 
addition of selected users to a group in the registry.</note>
         <note priority="1" from="meaning">Cancel addition of selected users to 
group</note>
        </trans-unit>
     </body>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/platform/core/common/styles/_globalVars.scss
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/platform/core/common/styles/_globalVars.scss 
b/nifi-registry-web-ui/src/main/platform/core/common/styles/_globalVars.scss
index f43f214..77c6ee2 100644
--- a/nifi-registry-web-ui/src/main/platform/core/common/styles/_globalVars.scss
+++ b/nifi-registry-web-ui/src/main/platform/core/common/styles/_globalVars.scss
@@ -35,11 +35,13 @@ $grey2: #666666;
 $grey3: #999999;
 $grey4: #CCCCCC;
 $grey5: #EEEEEE;
-$grey6: #F5F5F5; // or #FAFAFA
+$grey6: #F8F9F9; // or #FAFAFA
 $grey7: #DDDDDD;
 $grey8: #CFD3D7;
 $grey9: #b2b8c1;
 $grey10: #dbdee2;
+$grey11: #2C3E44;
+$grey12: #EEEFF0;
 $blue1: #1491C1;
 $blue2: #E7f6Fc;
 $blue3: #A7DFF2;

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/platform/core/common/styles/_helperClasses.scss
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/platform/core/common/styles/_helperClasses.scss 
b/nifi-registry-web-ui/src/main/platform/core/common/styles/_helperClasses.scss
index 6b00b46..1298358 100644
--- 
a/nifi-registry-web-ui/src/main/platform/core/common/styles/_helperClasses.scss
+++ 
b/nifi-registry-web-ui/src/main/platform/core/common/styles/_helperClasses.scss
@@ -28,6 +28,11 @@
   padding-bottom: 10px;
 }
 
+.help-icon {
+  font-size: 12px;
+  color: $blue1;
+}
+
 .details-header {
   height: 92px;
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/platform/core/common/styles/_inputs.scss
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/platform/core/common/styles/_inputs.scss 
b/nifi-registry-web-ui/src/main/platform/core/common/styles/_inputs.scss
index 4ab225a..392f5cb 100644
--- a/nifi-registry-web-ui/src/main/platform/core/common/styles/_inputs.scss
+++ b/nifi-registry-web-ui/src/main/platform/core/common/styles/_inputs.scss
@@ -32,7 +32,7 @@ body[fds] input.mat-input-element, body[fds] 
textarea.mat-input-element {
   border: 1px solid $grey8;
   height: 32px;
   padding: 0px 10px;
-  width: calc(100% - 22px);
+  width: calc(100% - 26px);
 }
 
 body[fds] textarea.mat-input-element {

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/platform/core/common/styles/_stepper.scss
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/platform/core/common/styles/_stepper.scss 
b/nifi-registry-web-ui/src/main/platform/core/common/styles/_stepper.scss
new file mode 100644
index 0000000..fda0b87
--- /dev/null
+++ b/nifi-registry-web-ui/src/main/platform/core/common/styles/_stepper.scss
@@ -0,0 +1,20 @@
+/*
+* 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.
+*/
+
+.td-step-header span {
+  display: none;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/platform/core/common/styles/fluid-design-system.scss
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/platform/core/common/styles/fluid-design-system.scss
 
b/nifi-registry-web-ui/src/main/platform/core/common/styles/fluid-design-system.scss
index 1ee9b70..7075f92 100644
--- 
a/nifi-registry-web-ui/src/main/platform/core/common/styles/fluid-design-system.scss
+++ 
b/nifi-registry-web-ui/src/main/platform/core/common/styles/fluid-design-system.scss
@@ -31,6 +31,7 @@
 @import 'panels';
 @import 'links';
 @import 'sideNav';
+@import 'stepper';
 @import 'tooltips';
 @import 'expansionPanels';
 @import 'menus';

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-web-ui/src/main/webapp/WEB-INF/web.xml 
b/nifi-registry-web-ui/src/main/webapp/WEB-INF/web.xml
index da27a62..c020795 100644
--- a/nifi-registry-web-ui/src/main/webapp/WEB-INF/web.xml
+++ b/nifi-registry-web-ui/src/main/webapp/WEB-INF/web.xml
@@ -26,6 +26,16 @@
         <url-pattern>/fluid-design-system</url-pattern>
     </servlet-mapping>
 
+    <!-- servlet to map to login page -->
+    <servlet>
+        <servlet-name>Login</servlet-name>
+        <jsp-file>/WEB-INF/pages/index.jsp</jsp-file>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>Login</servlet-name>
+        <url-pattern>/login/*</url-pattern>
+    </servlet-mapping>
+
     <!-- servlet to map to administration page -->
     <servlet>
         <servlet-name>Administration</servlet-name>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.html
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.html
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.html
index 604af59..23f40a0 100644
--- 
a/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.html
+++ 
b/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.html
@@ -17,16 +17,22 @@ limitations under the License.
 
 <div id="nifi-registry-administration-perspective">
     <mat-button-toggle-group name="nifi-registry-administration-perspective" 
fxLayout="row"
-                            fxLayoutAlign="space-between center" 
class="tab-toggle-group">
-        <mat-button-toggle [checked]="nfRegistryService.adminPerspective === 
'workflow'" value="workflow"
-                           class="uppercase"
-                           routerLink="/nifi-registry/administration/workflow"
-                           i18n="Workflow administration tab|A description of 
the type of administration options available.@@nf-admin-workflow-tab-title">
+                             fxLayoutAlign="space-between center" 
class="tab-toggle-group">
+        <mat-button-toggle
+                
[disabled]="!nfRegistryService.currentUser.resourcePermissions.buckets.canRead"
+                [matTooltip]="'Manage NiFi Registry buckets.'"
+                [checked]="nfRegistryService.adminPerspective === 'workflow'" 
value="workflow"
+                class="uppercase"
+                (change)="navigateToAdminPerspective($event)"
+                i18n="Workflow administration tab|A description of the type of 
administration options available.@@nf-admin-workflow-tab-title">
             Buckets
         </mat-button-toggle>
-        <mat-button-toggle [checked]="nfRegistryService.adminPerspective === 
'users'" value="users" class="uppercase"
-                          routerLink="/nifi-registry/administration/users"
-                          i18n="Users administration tab|A description of the 
type of administration options available.@@nf-admin-users-tab-title">
+        <mat-button-toggle
+                [disabled]="nfRegistryService.currentUser.anonymous || 
!nfRegistryService.currentUser.resourcePermissions.tenants.canRead"
+                [matTooltip]="getUserTooltip()"
+                [checked]="nfRegistryService.adminPerspective === 'users'" 
value="users" class="uppercase"
+                (change)="navigateToAdminPerspective($event)"
+                i18n="Users administration tab|A description of the type of 
administration options available.@@nf-admin-users-tab-title">
             Users
         </mat-button-toggle>
     </mat-button-toggle-group>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.js
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.js
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.js
index 3a8376e..beba08d 100644
--- 
a/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.js
+++ 
b/nifi-registry-web-ui/src/main/webapp/components/administration/nf-registry-administration.js
@@ -23,11 +23,11 @@ var ngRouter = require('@angular/router');
  * NfRegistryAdministration constructor.
  *
  * @param nfRegistryService     The nf-registry.service module.
- * @param ActivatedRoute        The angular activated route module.
+ * @param router                The angular router module.
  * @constructor
  */
-function NfRegistryAdministration(nfRegistryService, ActivatedRoute) {
-    this.route = ActivatedRoute;
+function NfRegistryAdministration(nfRegistryService, router) {
+    this.router = router;
     this.nfRegistryService = nfRegistryService;
 };
 
@@ -49,6 +49,33 @@ NfRegistryAdministration.prototype = {
     ngOnDestroy: function () {
         this.nfRegistryService.perspective = '';
         this.nfRegistryService.setBreadcrumbState('out');
+    },
+
+    /**
+     * Navigates to admin perspective.
+     *
+     * @param $event
+     */
+    navigateToAdminPerspective: function($event) {
+        this.router.navigateByUrl('nifi-registry/administration/' + 
$event.value);
+    },
+
+    /**
+     * Generate the user tab tooltip.
+     *
+     * @returns {*}
+     */
+    getUserTooltip: function() {
+        if(this.nfRegistryService.currentUser.anonymous) {
+            return 'Please configure NiFi Registry security to enable.';
+        }
+        else {
+            
if(!this.nfRegistryService.currentUser.resourcePermissions.tenants.canRead) {
+                return 'You do not have permission. Please contact your System 
Administrator.'
+            } else {
+                return 'Manage NiFi Registry users and groups.'
+            }
+        }
     }
 };
 
@@ -64,7 +91,7 @@ NfRegistryAdministration.annotations = [
 
 NfRegistryAdministration.parameters = [
     NfRegistryService,
-    ngRouter.ActivatedRoute
+    ngRouter.Router
 ];
 
 module.exports = NfRegistryAdministration;

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/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 4cc7cf8..258ae06 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
@@ -32,9 +32,8 @@ var NfRegistryExplorer = 
require('nifi-registry/components/explorer/nf-registry-
 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 NfRegistryUserDetails = 
require('nifi-registry/components/administration/users/details/nf-registry-user-details.js');
-var NfRegistryUserPermissions = 
require('nifi-registry/components/administration/users/permissions/nf-registry-user-permissions.js');
-var NfRegistryUserGroupPermissions = 
require('nifi-registry/components/administration/user-group/permissions/nf-registry-user-group-permissions.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 NfRegistryBucketPermissions = 
require('nifi-registry/components/administration/workflow/buckets/permissions/nf-registry-bucket-permissions.js');
 var NfRegistryWorkflowAdministration = 
require('nifi-registry/components/administration/workflow/nf-registry-workflow-administration.js');
 var NfRegistryGridListViewer = 
require('nifi-registry/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.js');
@@ -43,6 +42,8 @@ var NfRegistryDropletGridListViewer = 
require('nifi-registry/components/explorer
 var fdsCore = require('@fluid-design-system/core');
 var ngMoment = require('angular2-moment');
 var rxjs = require('rxjs/Rx');
+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('NfRegistryAdministration Component', function () {
     var comp;
@@ -66,16 +67,17 @@ describe('NfRegistryAdministration Component', function () {
                 NfRegistryExplorer,
                 NfRegistryAdministration,
                 NfRegistryUsersAdministration,
-                NfRegistryUserDetails,
-                NfRegistryUserPermissions,
-                NfRegistryUserGroupPermissions,
+                NfRegistryManageUser,
+                NfRegistryManageGroup,
                 NfRegistryBucketPermissions,
                 NfRegistryAddUser,
                 NfRegistryWorkflowAdministration,
                 NfRegistryGridListViewer,
                 NfRegistryBucketGridListViewer,
                 NfRegistryDropletGridListViewer,
-                NfPageNotFoundComponent
+                NfPageNotFoundComponent,
+                NfLoginComponent,
+                NfUserLoginComponent
             ],
             providers: [
                 NfRegistryService,

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/user-group/permissions/nf-registry-user-group-permissions.html
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/user-group/permissions/nf-registry-user-group-permissions.html
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/user-group/permissions/nf-registry-user-group-permissions.html
deleted file mode 100644
index f67161c..0000000
--- 
a/nifi-registry-web-ui/src/main/webapp/components/administration/user-group/permissions/nf-registry-user-group-permissions.html
+++ /dev/null
@@ -1,28 +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.
--->
-
-<div fxFill>
-    <div fxLayout="row" fxLayoutAlign="space-between center" class="pad-top-sm 
pad-bottom-md pad-left-md pad-right-md">
-        <span class="md-card-title"><i class="fa fa-users push-right-sm" 
aria-hidden="true"></i>{{nfRegistryService.group.identity}}</span>
-        <button mat-icon-button (click)="closeSideNav()">
-            <mat-icon color="primary">close</mat-icon>
-        </button>
-    </div>
-    <button id="nf-registry-user-group-permissions-side-nav-container" 
class="push-right-md" mat-raised-button color="fds-primary"
-            (click)="closeSideNav()">Close
-    </button>
-</div>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/user-group/permissions/nf-registry-user-group-permissions.js
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/user-group/permissions/nf-registry-user-group-permissions.js
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/user-group/permissions/nf-registry-user-group-permissions.js
deleted file mode 100644
index fe20949..0000000
--- 
a/nifi-registry-web-ui/src/main/webapp/components/administration/user-group/permissions/nf-registry-user-group-permissions.js
+++ /dev/null
@@ -1,70 +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 ngCore = require('@angular/core');
-var NfRegistryService = 
require('nifi-registry/services/nf-registry.service.js');
-var ngRouter = require('@angular/router');
-
-/**
- * NfRegistryUserGroupsPermissions constructor.
- *
- * @param nfRegistryService     The nf-registry.service module.
- * @param Router                The angular router module.
- * @constructor
- */
-function NfRegistryUserGroupsPermissions(nfRegistryService, Router) {
-    this.nfRegistryService = nfRegistryService;
-    this.router = Router;
-};
-
-NfRegistryUserGroupsPermissions.prototype = {
-    constructor: NfRegistryUserGroupsPermissions,
-
-    /**
-     * Initialize the component.
-     */
-    ngOnInit: function () {
-        this.nfRegistryService.sidenav.open();
-    },
-
-    /**
-     * Destroy the component.
-     */
-    ngOnDestroy: function () {
-        this.nfRegistryService.group = {};
-        this.nfRegistryService.sidenav.close();
-    },
-
-    /**
-     * Navigate to administer users for current registry.
-     */
-    closeSideNav: function () {
-        this.router.navigateByUrl('/nifi-registry/administration/users');
-    }
-};
-
-NfRegistryUserGroupsPermissions.annotations = [
-    new ngCore.Component({
-        template: require('./nf-registry-user-group-permissions.html!text')
-    })
-];
-
-NfRegistryUserGroupsPermissions.parameters = [
-    NfRegistryService,
-    ngRouter.Router
-];
-
-module.exports = NfRegistryUserGroupsPermissions;

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/users/details/nf-registry-user-details.html
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/details/nf-registry-user-details.html
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/details/nf-registry-user-details.html
deleted file mode 100644
index 0329093..0000000
--- 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/details/nf-registry-user-details.html
+++ /dev/null
@@ -1,28 +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.
--->
-
-<div fxFill>
-    <div fxLayout="row" fxLayoutAlign="space-between center" class="pad-top-md 
pad-bottom-md pad-left-sm pad-right-sm">
-        <span class="md-card-title">User Details</span>
-        <button mat-icon-button (click)="closeSideNav()">
-            <mat-icon color="primary">close</mat-icon>
-        </button>
-    </div>
-    <button id="nf-registry-user-details-side-nav-container" mat-raised-button 
color="fds-primary"
-            (click)="closeSideNav()">Close
-    </button>
-</div>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/users/details/nf-registry-user-details.js
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/details/nf-registry-user-details.js
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/details/nf-registry-user-details.js
deleted file mode 100644
index ba676b3..0000000
--- 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/details/nf-registry-user-details.js
+++ /dev/null
@@ -1,69 +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 ngCore = require('@angular/core');
-var NfRegistryService = 
require('nifi-registry/services/nf-registry.service.js');
-var ngRouter = require('@angular/router');
-
-/**
- * NfRegistryUserDetails constructor.
- *
- * @param nfRegistryService     The nf-registry.service module.
- * @param Router                The angular router module.
- * @constructor
- */
-function NfRegistryUserDetails(nfRegistryService, Router) {
-    this.nfRegistryService = nfRegistryService;
-    this.router = Router;
-};
-
-NfRegistryUserDetails.prototype = {
-    constructor: NfRegistryUserDetails,
-
-    /**
-     * Initialize the component.
-     */
-    ngOnInit: function () {
-        this.nfRegistryService.sidenav.open();
-    },
-
-    /**
-     * Destroy the component.
-     */
-    ngOnDestroy: function () {
-        this.nfRegistryService.sidenav.close();
-    },
-
-    /**
-     * Navigate to administer users for current registry.
-     */
-    closeSideNav: function () {
-        this.router.navigateByUrl('/nifi-registry/administration/users');
-    }
-};
-
-NfRegistryUserDetails.annotations = [
-    new ngCore.Component({
-        template: require('./nf-registry-user-details.html!text')
-    })
-];
-
-NfRegistryUserDetails.parameters = [
-    NfRegistryService,
-    ngRouter.Router
-];
-
-module.exports = NfRegistryUserDetails;

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.html
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.html
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.html
deleted file mode 100644
index e76e898..0000000
--- 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.html
+++ /dev/null
@@ -1,75 +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.
--->
-
-<div id="nifi-registry-admin-add-selected-users-to-group-dialog">
-    <div class="pad-bottom-md" fxLayout="row" fxLayoutAlign="space-between 
center">
-        <span class="md-card-title">Add to group</span>
-        <button mat-icon-button (click)="cancel()">
-            <mat-icon color="primary">close</mat-icon>
-        </button>
-    </div>
-    <div class="pad-bottom-md">
-        <div 
id="nifi-registry-users-administration-list-container-column-header" 
class="td-data-table">
-            <div class="td-data-table-column" (click)="sortUserGroups(column)"
-                 *ngFor="let column of userGroupsColumns"
-                 fxFlex="{{column.width}}">
-                {{column.label}}
-                <i *ngIf="column.active && column.sortable && column.sortOrder 
=== 'ASC'" class="fa fa-caret-up"
-                   aria-hidden="true"></i>
-                <i *ngIf="column.active && column.sortable && column.sortOrder 
=== 'DESC'" class="fa fa-caret-down"
-                   aria-hidden="true"></i>
-            </div>
-            <div class="td-data-table-column">
-                <mat-checkbox [(ngModel)]="allGroupsSelected"
-                              (checked)="allGroupsSelected"
-                              
(change)="toggleUserGroupsSelectAll()"></mat-checkbox>
-            </div>
-        </div>
-        <div id="nifi-registry-add-selected-users-to-group-list-container">
-            <div [ngClass]="{'selected' : row.checked}" *ngFor="let row of 
filteredUserGroups"
-                 (click)="row.checked = 
!row.checked;determineAllUserGroupsSelectedState()">
-                <div *ngFor="let column of userGroupsColumns" fxLayout="row"
-                     fxLayoutAlign="space-between center" 
class="td-data-table-row">
-                    <div *ngIf="row.users && row.users.length > 0" 
class="td-data-table-cell" fxFlex="{{column.width}}">
-                        <div>
-                            <i class="fa fa-users push-right-sm" 
aria-hidden="true"></i>{{column.format ?
-                            column.format(row[column.name]) : 
row[column.name]}}
-                        </div>
-                    </div>
-                    <div class="td-data-table-cell">
-                        <mat-checkbox [(ngModel)]="row.checked" 
[checked]="row.checked"
-                                      
(change)="determineAllUserGroupsSelectedState()"
-                                      (click)="row.checked = 
!row.checked;determineAllUserGroupsSelectedState()">
-                        </mat-checkbox>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-    <div fxLayout="row">
-        <span fxFlex></span>
-        <button (click)="cancel()" color="fds-regular" mat-raised-button
-                i18n="Cancel addition of selected users to group|A button for 
cancelling the addition of selected users to a group in the 
registry.@@nf-admin-workflow-cancel-add-selected-users-to-group-button">
-            Cancel
-        </button>
-        <button [disabled]="isAddSelectedUsersToSelectedGroupsDisabled" 
class="push-left-sm" (click)="addSelectedUsersToSelectedGroups()"
-                color="fds-primary" mat-raised-button
-                i18n="Add selected users to group button|A button for adding 
users to an existing group in the 
registry.@@nf-admin-workflow-add-selected-users-to-group-button">
-            Add
-        </button>
-    </div>
-</div>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.js
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.js
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.js
deleted file mode 100644
index e66630a..0000000
--- 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.js
+++ /dev/null
@@ -1,237 +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 covalentCore = require('@covalent/core');
-var NfRegistryApi = require('nifi-registry/services/nf-registry.api.js');
-var ngCore = require('@angular/core');
-var fdsSnackBarsModule = require('@fluid-design-system/snackbars');
-var NfRegistryService = 
require('nifi-registry/services/nf-registry.service.js');
-var ngMaterial = require('@angular/material');
-var $ = require('jquery');
-
-/**
- * NfRegistryAddSelectedToGroup constructor.
- *
- * @param nfRegistryApi         The api service.
- * @param tdDataTableService    The covalent data table service module.
- * @param nfRegistryService     The nf-registry.service module.
- * @param matDialogRef          The angular material dialog ref.
- * @param fdsSnackBarService    The FDS snack bar service module.
- * @constructor
- */
-function NfRegistryAddSelectedToGroup(nfRegistryApi, tdDataTableService, 
nfRegistryService, matDialogRef, fdsSnackBarService) {
-    this.dataTableService = tdDataTableService;
-    this.snackBarService = fdsSnackBarService;
-    this.nfRegistryService = nfRegistryService;
-    this.nfRegistryApi = nfRegistryApi;
-    this.dialogRef = matDialogRef;
-    this.filteredUserGroups = [];
-    //make an independent copy of the groups for sorting and selecting within 
the scope of this component
-    this.groups = $.extend(true, [], this.nfRegistryService.groups);
-    this.selectedGroups = [];
-    this.allGroupsSelected = false;
-    this.isAddSelectedUsersToSelectedGroupsDisabled = true;
-    this.userGroupsSearchTerms = [];
-    this.userGroupsColumns = [
-        {
-            name: 'identity',
-            label: 'Display Name',
-            sortable: true,
-            tooltip: 'User name.',
-            width: 100
-        }
-    ];
-};
-
-NfRegistryAddSelectedToGroup.prototype = {
-    constructor: NfRegistryAddSelectedToGroup,
-
-    /**
-     * Initialize the component.
-     */
-    ngOnInit: function () {
-        this.filterGroups();
-    },
-
-    /**
-     * Filter groups.
-     *
-     * @param {string} [sortBy]       The column name to sort 
`userGroupsColumns` by.
-     * @param {string} [sortOrder]    The order. Either 'ASC' or 'DES'
-     */
-    filterGroups: function (sortBy, sortOrder) {
-        // if `sortOrder` is `undefined` then use 'ASC'
-        if (sortOrder === undefined) {
-            sortOrder = 'ASC'
-        }
-        // if `sortBy` is `undefined` then find the first sortable column in 
`dropletColumns`
-        if (sortBy === undefined) {
-            var arrayLength = this.userGroupsColumns.length;
-            for (var i = 0; i < arrayLength; i++) {
-                if (this.userGroupsColumns[i].sortable === true) {
-                    sortBy = this.userGroupsColumns[i].name;
-                    //only one column can be actively sorted so we reset all 
to inactive
-                    this.userGroupsColumns.forEach(function (c) {
-                        c.active = false;
-                    });
-                    //and set this column as the actively sorted column
-                    this.userGroupsColumns[i].active = true;
-                    this.userGroupsColumns[i].sortOrder = sortOrder;
-                    break;
-                }
-            }
-        }
-
-        var newUserGroupsData = this.groups;
-
-        for (var i = 0; i < this.userGroupsSearchTerms.length; i++) {
-            newUserGroupsData = 
this.nfRegistryService.filterData(newUserGroupsData, 
this.userGroupsSearchTerms[i], true);
-        }
-
-        newUserGroupsData = this.dataTableService.sortData(newUserGroupsData, 
sortBy, sortOrder);
-        this.filteredUserGroups = newUserGroupsData;
-    },
-
-    /**
-     * Sort `filteredUserGroups` by `column`.
-     *
-     * @param column    The column to sort by.
-     */
-    sortUserGroups: function (column) {
-        if (column.sortable) {
-            var sortBy = column.name;
-            var sortOrder = column.sortOrder = (column.sortOrder === 'ASC') ? 
'DESC' : 'ASC';
-            this.filterGroups(sortBy, sortOrder);
-        }
-    },
-
-    /**
-     * Checks the `allGroupsSelected` property state and either selects
-     * or deselects each of the `filteredUserGroups`.
-     */
-    toggleUserGroupsSelectAll: function () {
-        if (this.allGroupsSelected) {
-            this.selectAllUserGroups();
-        } else {
-            this.deselectAllUserGroups();
-        }
-    },
-
-    /**
-     * Sets the `checked` property of each of the `filteredUserGroups` to true
-     * and sets the `isAddSelectedUsersToSelectedGroupsDisabled` and the 
`allGroupsSelected`
-     * properties accordingly.
-     */
-    selectAllUserGroups: function () {
-        this.filteredUserGroups.forEach(function (c) {
-            c.checked = true;
-        });
-        this.isAddSelectedUsersToSelectedGroupsDisabled = false;
-        this.allGroupsSelected = true;
-    },
-
-    /**
-     * Sets the `checked` property of each group to false
-     * and sets the `isAddSelectedUsersToSelectedGroupsDisabled` and the 
`allGroupsSelected`
-     * properties accordingly.
-     */
-    deselectAllUserGroups: function () {
-        this.filteredUserGroups.forEach(function (c) {
-            c.checked = false;
-        });
-        this.isAddSelectedUsersToSelectedGroupsDisabled = true;
-        this.allGroupsSelected = false;
-    },
-
-    /**
-     * Checks of each of the `filteredUserGroups`'s checked property state
-     * and sets the `allBucketsSelected` and 
`isAddSelectedUsersToSelectedGroupsDisabled`
-     * property accordingly.
-     */
-    determineAllUserGroupsSelectedState: function () {
-        var selected = 0;
-        var allSelected = true;
-        this.filteredUserGroups.forEach(function (c) {
-            if (c.checked) {
-                selected++;
-            }
-            if (c.checked === undefined || c.checked === false) {
-                allSelected = false;
-            }
-        });
-
-        if (selected > 0) {
-            this.isAddSelectedUsersToSelectedGroupsDisabled = false;
-        } else {
-            this.isAddSelectedUsersToSelectedGroupsDisabled = true;
-        }
-
-        this.allGroupsSelected = allSelected;
-    },
-
-    /**
-     * Adds the selected users to each of the selected groups.
-     */
-    addSelectedUsersToSelectedGroups: function () {
-        var self = this;
-        var selectedUsers = 
this.nfRegistryService.filteredUsers.filter(function (filteredUser) {
-            return filteredUser.checked;
-        });
-        var groupIds = this.filteredUserGroups.filter(function 
(filteredUserGroup) {
-            return filteredUserGroup.checked;
-        });
-        groupIds.forEach(function (groupId) {
-            
self.nfRegistryApi.getUserGroup(groupId.identifier).subscribe(function (group) {
-                self.nfRegistryApi.updateUserGroup(groupId.identifier, 
groupId.identity, selectedUsers.concat(group.users)).subscribe(function (group) 
{
-                    self.dialogRef.close();
-                    var snackBarRef = self.snackBarService.openCoaster({
-                        title: 'Success',
-                        message: 'Selected users have been added to the ' + 
group.identity + ' group.',
-                        verticalPosition: 'bottom',
-                        horizontalPosition: 'right',
-                        icon: 'fa fa-check-circle-o',
-                        color: '#1EB475',
-                        duration: 3000
-                    });
-                });
-            });
-        });
-    },
-
-    /**
-     * Cancel adding selected users to groups and close the dialog.
-     */
-    cancel: function () {
-        this.dialogRef.close();
-    }
-};
-
-NfRegistryAddSelectedToGroup.annotations = [
-    new ngCore.Component({
-        template: 
require('./nf-registry-add-selected-users-to-group.html!text')
-    })
-];
-
-NfRegistryAddSelectedToGroup.parameters = [
-    NfRegistryApi,
-    covalentCore.TdDataTableService,
-    NfRegistryService,
-    ngMaterial.MatDialogRef,
-    fdsSnackBarsModule.FdsSnackBarService
-];
-
-module.exports = NfRegistryAddSelectedToGroup;

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.spec.js
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.spec.js
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.spec.js
deleted file mode 100644
index c47d255..0000000
--- 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.spec.js
+++ /dev/null
@@ -1,169 +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 NfRegistryApi = require('nifi-registry/services/nf-registry.api.js');
-var NfRegistryService = 
require('nifi-registry/services/nf-registry.service.js');
-var NfRegistryAddSelectedToGroup = 
require('nifi-registry/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.js');
-var rxjs = require('rxjs/Rx');
-var covalentCore = require('@covalent/core');
-var fdsSnackBarsModule = require('@fluid-design-system/snackbars');
-
-describe('NfRegistryAddSelectedToGroup Component isolated unit tests', 
function () {
-    var comp;
-    var nfRegistryService;
-    var nfRegistryApi;
-    var snackBarService;
-    var dataTableService;
-
-    beforeEach(function () {
-        nfRegistryService = new NfRegistryService();
-        // setup the nfRegistryService
-        nfRegistryService.groups = [{identifier: 1, identity: 'Group 1'}];
-        nfRegistryService.filteredUsers = [{identifier: 2, identity: 'User 
1'}];
-
-        nfRegistryApi = new NfRegistryApi();
-        snackBarService = new fdsSnackBarsModule.FdsSnackBarService();
-        dataTableService = new covalentCore.TdDataTableService();
-        comp = new NfRegistryAddSelectedToGroup(nfRegistryApi, 
dataTableService, nfRegistryService, {
-            close: function () {
-            }
-        }, snackBarService);
-
-        // Spy
-        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
-        }).and.returnValue(rxjs.Observable.of({identifier: 1, identity: 'Group 
1'}));
-        spyOn(nfRegistryApi, 'updateUserGroup').and.callFake(function () {
-        }).and.returnValue(rxjs.Observable.of({identifier: 1, identity: 'Group 
1'}));
-        spyOn(comp.dialogRef, 'close');
-        spyOn(comp.snackBarService, 'openCoaster');
-        spyOn(comp, 'filterGroups').and.callThrough();
-
-        // initialize the component
-        comp.ngOnInit();
-
-        //assertions
-        expect(comp.filterGroups).toHaveBeenCalled();
-        expect(comp.filteredUserGroups[0].identity).toEqual('Group 1');
-        expect(comp.filteredUserGroups.length).toBe(1);
-        expect(comp).toBeDefined();
-    });
-
-    it('should make a call to the api to add selected users to selected 
groups', function () {
-        // select a group
-        comp.filteredUserGroups[0].checked = true;
-
-        // the function to test
-        comp.addSelectedUsersToSelectedGroups();
-
-        //assertions
-        expect(comp.dialogRef.close).toHaveBeenCalled();
-        expect(comp.snackBarService.openCoaster).toHaveBeenCalled();
-    });
-
-    it('should determine all user groups are selected', function () {
-        // select a group
-        comp.filteredUserGroups[0].checked = true;
-
-        // the function to test
-        comp.determineAllUserGroupsSelectedState();
-
-        //assertions
-        expect(comp.allGroupsSelected).toBe(true);
-        expect(comp.isAddSelectedUsersToSelectedGroupsDisabled).toBe(false);
-    });
-
-    it('should determine all user groups are not selected', function () {
-        // the function to test
-        comp.determineAllUserGroupsSelectedState();
-
-        //assertions
-        expect(comp.allGroupsSelected).toBe(false);
-        expect(comp.isAddSelectedUsersToSelectedGroupsDisabled).toBe(true);
-    });
-
-    it('should select all groups.', function () {
-        // The function to test
-        comp.selectAllUserGroups();
-
-        //assertions
-        expect(comp.filteredUserGroups[0].checked).toBe(true);
-        expect(comp.isAddSelectedUsersToSelectedGroupsDisabled).toBe(false);
-        expect(comp.allGroupsSelected).toBe(true);
-    });
-
-    it('should deselect all groups.', function () {
-        // select a group
-        comp.filteredUserGroups[0].checked = true;
-
-        // The function to test
-        comp.deselectAllUserGroups();
-
-        //assertions
-        expect(comp.filteredUserGroups[0].checked).toBe(false);
-        expect(comp.isAddSelectedUsersToSelectedGroupsDisabled).toBe(true);
-        expect(comp.allGroupsSelected).toBe(false);
-    });
-
-    it('should toggle all groups `checked` properties to true.', function () {
-        //Spy
-        spyOn(comp, 'selectAllUserGroups').and.callFake(function () {
-        });
-
-        comp.allGroupsSelected = true;
-
-        // The function to test
-        comp.toggleUserGroupsSelectAll();
-
-        //assertions
-        expect(comp.selectAllUserGroups).toHaveBeenCalled();
-    });
-
-    it('should toggle all groups `checked` properties to false.', function () {
-        //Spy
-        spyOn(comp, 'deselectAllUserGroups').and.callFake(function () {
-        });
-
-        comp.allGroupsSelected = false;
-
-        // The function to test
-        comp.toggleUserGroupsSelectAll();
-
-        //assertions
-        expect(comp.deselectAllUserGroups).toHaveBeenCalled();
-    });
-
-    it('should sort `groups` by `column`', function () {
-        // object to be updated by the test
-        var column = {name: 'name', label: 'Group Name', sortable: true};
-
-        // The function to test
-        comp.sortUserGroups(column);
-
-        //assertions
-        var filterGroupsCall = comp.filterGroups.calls.mostRecent();
-        expect(filterGroupsCall.args[0]).toBe('name');
-        expect(filterGroupsCall.args[1]).toBe('ASC');
-    });
-
-    it('should cancel the creation of a new user', function () {
-        // the function to test
-        comp.cancel();
-
-        //assertions
-        expect(comp.dialogRef.close).toHaveBeenCalled();
-    });
-});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.html
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.html
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.html
new file mode 100644
index 0000000..c3103e3
--- /dev/null
+++ 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.html
@@ -0,0 +1,80 @@
+<!--
+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.
+-->
+
+<div id="nifi-registry-admin-add-selected-users-to-group-dialog">
+    <div class="pad-bottom-md" fxLayout="row" fxLayoutAlign="space-between 
center">
+        <span class="md-card-title">Add user to groups</span>
+        <button mat-icon-button (click)="cancel()">
+            <mat-icon color="primary">close</mat-icon>
+        </button>
+    </div>
+    <div *ngIf="filteredUserGroups.length > 0" class="pad-bottom-md">
+        <div 
id="nifi-registry-users-administration-list-container-column-header" 
class="td-data-table">
+            <div class="td-data-table-column" (click)="sortUsers(column)"
+                 *ngFor="let column of nfRegistryService.userGroupsColumns"
+                 fxFlex="{{column.width}}">
+                {{column.label}}
+                <i *ngIf="column.active && column.sortable && column.sortOrder 
=== 'ASC'" class="fa fa-caret-up"
+                   aria-hidden="true"></i>
+                <i *ngIf="column.active && column.sortable && column.sortOrder 
=== 'DESC'" class="fa fa-caret-down"
+                   aria-hidden="true"></i>
+            </div>
+            <div class="td-data-table-column">
+                <mat-checkbox [(ngModel)]="allGroupsSelected"
+                              (checked)="allGroupsSelected"
+                              
(change)="toggleUserGroupsSelectAll()"></mat-checkbox>
+            </div>
+        </div>
+        <div id="nifi-registry-add-selected-users-to-group-list-container">
+            <div [ngClass]="{'selected' : row.checked}" *ngFor="let row of 
filteredUserGroups"
+                 (click)="row.checked = 
!row.checked;determineAllUserGroupsSelectedState()">
+                <div *ngFor="let column of 
nfRegistryService.userGroupsColumns" fxLayout="row"
+                     fxLayoutAlign="space-between center" 
class="td-data-table-row">
+                    <div class="td-data-table-cell" fxFlex="{{column.width}}">
+                        <div>
+                            <i class="fa fa-users push-right-sm" 
aria-hidden="true"></i>{{column.format ?
+                            column.format(row[column.name]) : 
row[column.name]}}
+                        </div>
+                    </div>
+                    <div class="td-data-table-cell">
+                        <mat-checkbox [(ngModel)]="row.checked"
+                                      [checked]="row.checked"
+                                      
(change)="determineAllUserGroupsSelectedState()"
+                                      (click)="row.checked = 
!row.checked;determineAllUserGroupsSelectedState()">
+                        </mat-checkbox>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="mat-padding push-bottom-md" *ngIf="filteredUserGroups.length 
=== 0" layout="row"
+         layout-align="center center">
+        <h3>User belongs to all groups.</h3>
+    </div>
+    <div fxLayout="row">
+        <span fxFlex></span>
+        <button (click)="cancel()" color="fds-regular" mat-raised-button
+                i18n="Cancel addition of selected users to group|A button for 
cancelling the addition of selected users to a group in the 
registry.@@nf-admin-workflow-cancel-add-selected-users-to-group-button">
+            Cancel
+        </button>
+        <button [disabled]="isAddToSelectedGroupsDisabled" 
class="push-left-sm" (click)="addToSelectedGroups()"
+                color="fds-primary" mat-raised-button
+                i18n="Add selected users to group button|A button for adding 
users to an existing group in the 
registry.@@nf-admin-workflow-add-selected-users-to-group-button">
+            Add
+        </button>
+    </div>
+</div>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.js
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.js
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.js
new file mode 100644
index 0000000..7cb0f62
--- /dev/null
+++ 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.js
@@ -0,0 +1,235 @@
+/*
+ * 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 covalentCore = require('@covalent/core');
+var NfRegistryApi = require('nifi-registry/services/nf-registry.api.js');
+var ngCore = require('@angular/core');
+var fdsSnackBarsModule = require('@fluid-design-system/snackbars');
+var NfRegistryService = 
require('nifi-registry/services/nf-registry.service.js');
+var ngMaterial = require('@angular/material');
+var $ = require('jquery');
+
+/**
+ * NfRegistryAddUserToGroups constructor.
+ *
+ * @param nfRegistryApi         The api service.
+ * @param tdDataTableService    The covalent data table service module.
+ * @param nfRegistryService     The nf-registry.service module.
+ * @param matDialogRef          The angular material dialog ref.
+ * @param fdsSnackBarService    The FDS snack bar service module.
+ * @param data                  The data passed into this component.
+ * @constructor
+ */
+function NfRegistryAddUserToGroups(nfRegistryApi, tdDataTableService, 
nfRegistryService, matDialogRef, fdsSnackBarService, data) {
+    this.dataTableService = tdDataTableService;
+    this.snackBarService = fdsSnackBarService;
+    this.nfRegistryService = nfRegistryService;
+    this.nfRegistryApi = nfRegistryApi;
+    this.dialogRef = matDialogRef;
+    this.data = data;
+    //make an independent copy of the groups for sorting and selecting within 
the scope of this component
+    this.groups = $.extend(true, [], this.nfRegistryService.groups);
+    this.filteredUserGroups = [];
+    this.isAddToSelectedGroupsDisabled = true;
+    this.userGroupsSearchTerms = [];
+    this.allGroupsSelected = false;
+};
+
+NfRegistryAddUserToGroups.prototype = {
+    constructor: NfRegistryAddUserToGroups,
+
+    /**
+     * Initialize the component.
+     */
+    ngOnInit: function () {
+        var self = this;
+
+        this.data.user.userGroups.forEach(function (userGroup) {
+            self.groups = self.groups.filter(function (group) {
+                return (group.identifier !== userGroup.identifier) ? true : 
false
+            });
+        });
+
+        this.filterGroups();
+        this.determineAllUserGroupsSelectedState();
+    },
+
+    /**
+     * Filter groups.
+     *
+     * @param {string} [sortBy]       The column name to sort 
`userGroupsColumns` by.
+     * @param {string} [sortOrder]    The order. Either 'ASC' or 'DES'
+     */
+    filterGroups: function (sortBy, sortOrder) {
+        // if `sortOrder` is `undefined` then use 'ASC'
+        if (sortOrder === undefined) {
+            sortOrder = 'ASC'
+        }
+        // if `sortBy` is `undefined` then find the first sortable column in 
`dropletColumns`
+        if (sortBy === undefined) {
+            var arrayLength = this.nfRegistryService.userGroupsColumns.length;
+            for (var i = 0; i < arrayLength; i++) {
+                if (this.nfRegistryService.userGroupsColumns[i].sortable === 
true) {
+                    sortBy = this.nfRegistryService.userGroupsColumns[i].name;
+                    //only one column can be actively sorted so we reset all 
to inactive
+                    this.nfRegistryService.userGroupsColumns.forEach(function 
(c) {
+                        c.active = false;
+                    });
+                    //and set this column as the actively sorted column
+                    this.nfRegistryService.userGroupsColumns[i].active = true;
+                    this.nfRegistryService.userGroupsColumns[i].sortOrder = 
sortOrder;
+                    break;
+                }
+            }
+        }
+
+        var newUserGroupsData = this.groups;
+
+        for (var i = 0; i < this.userGroupsSearchTerms.length; i++) {
+            newUserGroupsData = 
this.nfRegistryService.filterData(newUserGroupsData, 
this.userGroupsSearchTerms[i], true);
+        }
+
+        newUserGroupsData = this.dataTableService.sortData(newUserGroupsData, 
sortBy, sortOrder);
+        this.filteredUserGroups = newUserGroupsData;
+    },
+
+    /**
+     * Sort `filteredUserGroups` by `column`.
+     *
+     * @param column    The column to sort by.
+     */
+    sortUserGroups: function (column) {
+        if (column.sortable) {
+            var sortBy = column.name;
+            var sortOrder = column.sortOrder = (column.sortOrder === 'ASC') ? 
'DESC' : 'ASC';
+            this.filterGroups(sortBy, sortOrder);
+        }
+    },
+
+    /**
+     * Checks the `allGroupsSelected` property state and either selects
+     * or deselects each of the `filteredUserGroups`.
+     */
+    toggleUserGroupsSelectAll: function () {
+        if (this.allGroupsSelected) {
+            this.selectAllUserGroups();
+        } else {
+            this.deselectAllUserGroups();
+        }
+    },
+
+    /**
+     * Sets the `checked` property of each of the `filteredUserGroups` to true
+     * and sets the `isAddToSelectedGroupsDisabled` and the `allGroupsSelected`
+     * properties accordingly.
+     */
+    selectAllUserGroups: function () {
+        this.filteredUserGroups.forEach(function (c) {
+            c.checked = true;
+        });
+        this.isAddToSelectedGroupsDisabled = false;
+        this.allGroupsSelected = true;
+    },
+
+    /**
+     * Sets the `checked` property of each group to false
+     * and sets the `isAddToSelectedGroupsDisabled` and the `allGroupsSelected`
+     * properties accordingly.
+     */
+    deselectAllUserGroups: function () {
+        this.filteredUserGroups.forEach(function (c) {
+            c.checked = false;
+        });
+        this.isAddToSelectedGroupsDisabled = true;
+        this.allGroupsSelected = false;
+    },
+
+    /**
+     * Checks of each of the `filteredUserGroups`'s checked property state
+     * and sets the `allBucketsSelected` and `isAddToSelectedGroupsDisabled`
+     * property accordingly.
+     */
+    determineAllUserGroupsSelectedState: function () {
+        var selected = 0;
+        var allSelected = true;
+        this.filteredUserGroups.forEach(function (c) {
+            if (c.checked) {
+                selected++;
+            }
+            if (c.checked === undefined || c.checked === false) {
+                allSelected = false;
+            }
+        });
+
+        if (selected > 0) {
+            this.isAddToSelectedGroupsDisabled = false;
+        } else {
+            this.isAddToSelectedGroupsDisabled = true;
+        }
+
+        this.allGroupsSelected = allSelected;
+    },
+
+    /**
+     * Adds users to each of the selected groups.
+     */
+    addToSelectedGroups: function () {
+        var self = this;
+        var selectedGroups = this.filteredUserGroups.filter(function 
(filteredUserGroup) {
+            return filteredUserGroup.checked;
+        });
+        selectedGroups.forEach(function (selectedGroup) {
+            selectedGroup.users.push(self.data.user);
+            self.nfRegistryApi.updateUserGroup(selectedGroup.identifier, 
selectedGroup.identity, selectedGroup.users).subscribe(function (group) {
+                self.dialogRef.close();
+                var snackBarRef = self.snackBarService.openCoaster({
+                    title: 'Success',
+                    message: 'User has been added to the ' + group.identity + 
' group.',
+                    verticalPosition: 'bottom',
+                    horizontalPosition: 'right',
+                    icon: 'fa fa-check-circle-o',
+                    color: '#1EB475',
+                    duration: 3000
+                });
+            });
+        });
+    },
+
+    /**
+     * Cancel adding selected users to groups and close the dialog.
+     */
+    cancel: function () {
+        this.dialogRef.close();
+    }
+};
+
+NfRegistryAddUserToGroups.annotations = [
+    new ngCore.Component({
+        template: require('./nf-registry-add-user-to-groups.html!text')
+    })
+];
+
+NfRegistryAddUserToGroups.parameters = [
+    NfRegistryApi,
+    covalentCore.TdDataTableService,
+    NfRegistryService,
+    ngMaterial.MatDialogRef,
+    fdsSnackBarsModule.FdsSnackBarService,
+    ngMaterial.MAT_DIALOG_DATA
+];
+
+module.exports = NfRegistryAddUserToGroups;

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.spec.js
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.spec.js
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.spec.js
new file mode 100644
index 0000000..018a9c1
--- /dev/null
+++ 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.spec.js
@@ -0,0 +1,172 @@
+/*
+ * 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 NfRegistryApi = require('nifi-registry/services/nf-registry.api.js');
+var NfRegistryService = 
require('nifi-registry/services/nf-registry.service.js');
+var NfRegistryAddUserToGroups = 
require('nifi-registry/components/administration/users/dialogs/add-user-to-groups/nf-registry-add-user-to-groups.js');
+var rxjs = require('rxjs/Rx');
+var covalentCore = require('@covalent/core');
+var fdsSnackBarsModule = require('@fluid-design-system/snackbars');
+
+describe('NfRegistryAddUserToGroups Component isolated unit tests', function 
() {
+    var comp;
+    var nfRegistryService;
+    var nfRegistryApi;
+    var snackBarService;
+    var dataTableService;
+
+    beforeEach(function () {
+        nfRegistryService = new NfRegistryService();
+        // setup the nfRegistryService
+        nfRegistryService.user = {identifier: 3, identity: 'User 3', 
userGroups: []};
+        nfRegistryService.groups = [{identifier: 1, identity: 'Group 1', 
checked: true, users: []}];
+
+        nfRegistryApi = new NfRegistryApi();
+        snackBarService = new fdsSnackBarsModule.FdsSnackBarService();
+        dataTableService = new covalentCore.TdDataTableService();
+        comp = new NfRegistryAddUserToGroups(nfRegistryApi, dataTableService, 
nfRegistryService, {
+            close: function () {
+            }
+        }, snackBarService, {user: nfRegistryService.user});
+
+        // Spy
+        spyOn(nfRegistryApi, 'getUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({identifier: 1, identity: 'Group 
1'}));
+        spyOn(nfRegistryApi, 'updateUserGroup').and.callFake(function () {
+        }).and.returnValue(rxjs.Observable.of({identifier: 1, identity: 'Group 
1'}));
+        spyOn(comp.dialogRef, 'close');
+        spyOn(comp.snackBarService, 'openCoaster');
+        spyOn(comp, 'filterGroups').and.callThrough();
+
+        // initialize the component
+        comp.ngOnInit();
+
+        //assertions
+        expect(comp.filterGroups).toHaveBeenCalled();
+        expect(comp.filteredUserGroups[0].identity).toEqual('Group 1');
+        expect(comp.filteredUserGroups.length).toBe(1);
+        expect(comp).toBeDefined();
+    });
+
+    it('should make a call to the api to add user to selected groups', 
function () {
+        // select a group
+        comp.filteredUserGroups[0].checked = true;
+
+        // the function to test
+        comp.addToSelectedGroups();
+
+        //assertions
+        expect(comp.dialogRef.close).toHaveBeenCalled();
+        expect(comp.snackBarService.openCoaster).toHaveBeenCalled();
+    });
+
+    it('should determine if all groups are selected', function () {
+        // select a group
+        comp.filteredUserGroups[0].checked = true;
+
+        // the function to test
+        comp.determineAllUserGroupsSelectedState();
+
+        //assertions
+        expect(comp.allGroupsSelected).toBe(true);
+        expect(comp.isAddToSelectedGroupsDisabled).toBe(false);
+    });
+
+    it('should determine if all groups are not selected', function () {
+        // select a group
+        comp.filteredUserGroups[0].checked = false;
+
+        // the function to test
+        comp.determineAllUserGroupsSelectedState();
+
+        //assertions
+        expect(comp.allGroupsSelected).toBe(false);
+        expect(comp.isAddToSelectedGroupsDisabled).toBe(true);
+    });
+
+    it('should select all groups.', function () {
+        // The function to test
+        comp.selectAllUserGroups();
+
+        //assertions
+        expect(comp.filteredUserGroups[0].checked).toBe(true);
+        expect(comp.isAddToSelectedGroupsDisabled).toBe(false);
+        expect(comp.allGroupsSelected).toBe(true);
+    });
+
+    it('should deselect all groups.', function () {
+        // select a group
+        comp.filteredUserGroups[0].checked = true;
+
+        // The function to test
+        comp.deselectAllUserGroups();
+
+        //assertions
+        expect(comp.filteredUserGroups[0].checked).toBe(false);
+        expect(comp.isAddToSelectedGroupsDisabled).toBe(true);
+        expect(comp.allGroupsSelected).toBe(false);
+    });
+
+    it('should toggle all groups `checked` properties to true.', function () {
+        //Spy
+        spyOn(comp, 'selectAllUserGroups').and.callFake(function () {
+        });
+
+        comp.allGroupsSelected = true;
+
+        // The function to test
+        comp.toggleUserGroupsSelectAll();
+
+        //assertions
+        expect(comp.selectAllUserGroups).toHaveBeenCalled();
+    });
+
+    it('should toggle all groups `checked` properties to false.', function () {
+        //Spy
+        spyOn(comp, 'deselectAllUserGroups').and.callFake(function () {
+        });
+
+        comp.allGroupsSelected = false;
+
+        // The function to test
+        comp.toggleUserGroupsSelectAll();
+
+        //assertions
+        expect(comp.deselectAllUserGroups).toHaveBeenCalled();
+    });
+
+    it('should sort `groups` by `column`', function () {
+        // object to be updated by the test
+        var column = {name: 'name', label: 'Group Name', sortable: true};
+
+        // The function to test
+        comp.sortUserGroups(column);
+
+        //assertions
+        var filterGroupsCall = comp.filterGroups.calls.mostRecent();
+        expect(filterGroupsCall.args[0]).toBe('name');
+        expect(filterGroupsCall.args[1]).toBe('ASC');
+    });
+
+    it('should cancel the addition of the user to any group', function () {
+        // the function to test
+        comp.cancel();
+
+        //assertions
+        expect(comp.dialogRef.close).toHaveBeenCalled();
+    });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user/nf-registry-add-user.js
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user/nf-registry-add-user.js
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user/nf-registry-add-user.js
index 0dc7a81..2a31e33 100644
--- 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user/nf-registry-add-user.js
+++ 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-user/nf-registry-add-user.js
@@ -45,7 +45,7 @@ NfRegistryAddUser.prototype = {
      */
     addUser: function (addUserInput) {
         var self = this;
-        this.nfRegistryApi.addUser(null, 
addUserInput.value).subscribe(function (user) {
+        this.nfRegistryApi.addUser(addUserInput.value).subscribe(function 
(user) {
             self.nfRegistryService.users.push(user);
             self.nfRegistryService.allUsersAndGroupsSelected = false;
             self.nfRegistryService.filterUsersAndGroups();

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/580f7754/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-users-to-group/nf-registry-add-users-to-group.html
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-users-to-group/nf-registry-add-users-to-group.html
 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-users-to-group/nf-registry-add-users-to-group.html
new file mode 100644
index 0000000..3bab6c4
--- /dev/null
+++ 
b/nifi-registry-web-ui/src/main/webapp/components/administration/users/dialogs/add-users-to-group/nf-registry-add-users-to-group.html
@@ -0,0 +1,80 @@
+<!--
+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.
+-->
+
+<div id="nifi-registry-admin-add-selected-users-to-group-dialog">
+    <div class="pad-bottom-md" fxLayout="row" fxLayoutAlign="space-between 
center">
+        <span class="md-card-title">Add users to group</span>
+        <button mat-icon-button (click)="cancel()">
+            <mat-icon color="primary">close</mat-icon>
+        </button>
+    </div>
+    <div *ngIf="filteredUsers.length > 0" class="pad-bottom-md">
+        <div 
id="nifi-registry-users-administration-list-container-column-header" 
class="td-data-table">
+            <div class="td-data-table-column" (click)="sortUsers(column)"
+                 *ngFor="let column of nfRegistryService.userGroupsColumns"
+                 fxFlex="{{column.width}}">
+                {{column.label}}
+                <i *ngIf="column.active && column.sortable && column.sortOrder 
=== 'ASC'" class="fa fa-caret-up"
+                   aria-hidden="true"></i>
+                <i *ngIf="column.active && column.sortable && column.sortOrder 
=== 'DESC'" class="fa fa-caret-down"
+                   aria-hidden="true"></i>
+            </div>
+            <div class="td-data-table-column">
+                <mat-checkbox [(ngModel)]="allUsersSelected"
+                              (checked)="allUsersSelected"
+                              (change)="toggleUsersSelectAll()"></mat-checkbox>
+            </div>
+        </div>
+        <div id="nifi-registry-add-selected-users-to-group-list-container">
+            <div [ngClass]="{'selected' : row.checked}" *ngFor="let row of 
filteredUsers"
+                 (click)="row.checked = 
!row.checked;determineAllUsersSelectedState()">
+                <div *ngFor="let column of 
nfRegistryService.userGroupsColumns" fxLayout="row"
+                     fxLayoutAlign="space-between center" 
class="td-data-table-row">
+                    <div class="td-data-table-cell" fxFlex="{{column.width}}">
+                        <div>
+                            {{column.format ?
+                            column.format(row[column.name]) : 
row[column.name]}}
+                        </div>
+                    </div>
+                    <div class="td-data-table-cell">
+                        <mat-checkbox [(ngModel)]="row.checked"
+                                      [checked]="row.checked"
+                                      
(change)="determineAllUsersSelectedState()"
+                                      (click)="row.checked = 
!row.checked;determineAllUsersSelectedState()">
+                        </mat-checkbox>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="mat-padding push-bottom-md" *ngIf="filteredUsers.length === 0" 
layout="row"
+         layout-align="center center">
+        <h3>All users belong to this group.</h3>
+    </div>
+    <div fxLayout="row">
+        <span fxFlex></span>
+        <button (click)="cancel()" color="fds-regular" mat-raised-button
+                i18n="Cancel addition of selected users to group|A button for 
cancelling the addition of selected users to a group in the 
registry.@@nf-admin-workflow-cancel-add-selected-users-to-group-button">
+            Cancel
+        </button>
+        <button [disabled]="isAddSelectedUsersToGroupDisabled" 
class="push-left-sm" (click)="addSelectedUsersToGroup()"
+                color="fds-primary" mat-raised-button
+                i18n="Add selected users to group button|A button for adding 
users to an existing group in the 
registry.@@nf-admin-workflow-add-selected-users-to-group-button">
+            Add
+        </button>
+    </div>
+</div>

Reply via email to