You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dlab.apache.org by dg...@apache.org on 2020/02/18 10:30:48 UTC

[incubator-dlab] 01/01: [DLAB-384]: Grouped roles on frontend

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

dgnatyshyn pushed a commit to branch DLAB-384
in repository https://gitbox.apache.org/repos/asf/incubator-dlab.git

commit ab3d3a81f07654d56d92a3861fe0ebc69e7ed095
Author: Dmytro Gnatyshyn <di...@ukr.net>
AuthorDate: Tue Feb 18 12:29:42 2020 +0200

    [DLAB-384]: Grouped roles on frontend
---
 .../app/administration/roles/roles.component.html  |  45 +--
 .../app/administration/roles/roles.component.scss  |   5 +-
 .../app/administration/roles/roles.component.ts    |  25 +-
 .../webapp/src/app/shared/form-controls/index.ts   |   5 +-
 .../multi-level-select-dropdown.component.html     |  70 +++++
 .../multi-level-select-dropdown.component.scss     | 319 +++++++++++++++++++++
 .../multi-level-select-dropdown.component.ts       | 101 +++++++
 .../src/app/shared/navbar/navbar.component.ts      |   4 +-
 8 files changed, 540 insertions(+), 34 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.html
index af111c2..5015d7a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.html
@@ -112,27 +112,30 @@
         <th mat-header-cell *matHeaderCellDef class="roles"> Roles </th>
         <td mat-cell *matCellDef="let element" class="roles">
           <div class="inner-step mat-reset">
-            <div class="selector-wrapper-edit">
-              <mat-form-field class="select">
-                <mat-select multiple [compareWith]="compareObjects" name="selected_roles" disableOptionCentering
-                  [(value)]="element.selected_roles" placeholder="Select roles" class="roles-select" panelClass="select-role">
-                  <mat-option class="multiple-select" disabled>
-                    <a class="select ani" (click)="selectAllOptions(element, rolesList, 'selected_roles')">
-                      <i class="material-icons">playlist_add_check</i>&nbsp;All
-                    </a>
-                    <a class="deselect ani" (click)="selectAllOptions(element, null, 'selected_roles')">
-                      <i class="material-icons">clear</i>&nbsp;None
-                    </a>
-                  </mat-option>
-                  <mat-option *ngFor="let role of rolesList" [value]="role">
-                    {{ role }}
-                  </mat-option>
-                </mat-select>
-                <button class="caret">
-                  <i class="material-icons">keyboard_arrow_down</i>
-                </button>
-              </mat-form-field>
-            </div>
+<!--            <div class="selector-wrapper-edit">-->
+<!--              <mat-form-field class="select">-->
+<!--                <mat-select multiple [compareWith]="compareObjects" name="selected_roles" disableOptionCentering-->
+<!--                  [(value)]="element.selected_roles" placeholder="Select roles" class="roles-select" panelClass="select-role">-->
+<!--                  <mat-option class="multiple-select" disabled>-->
+<!--                    <a class="select ani" (click)="selectAllOptions(element, rolesList, 'selected_roles')">-->
+<!--                      <i class="material-icons">playlist_add_check</i>&nbsp;All-->
+<!--                    </a>-->
+<!--                    <a class="deselect ani" (click)="selectAllOptions(element, null, 'selected_roles')">-->
+<!--                      <i class="material-icons">clear</i>&nbsp;None-->
+<!--                    </a>-->
+<!--                  </mat-option>-->
+<!--                  <mat-option *ngFor="let role of rolesList" [value]="role">-->
+<!--                    {{ role }}-->
+<!--                  </mat-option>-->
+<!--                </mat-select>-->
+<!--                <button class="caret">-->
+<!--                  <i class="material-icons">keyboard_arrow_down</i>-->
+<!--                </button>-->
+<!--              </mat-form-field>-->
+              <multi-level-select-dropdown  (selectionChange)="onUpdate($event)" [type]="element.group" [items]="rolesList" [model]="rolesList"></multi-level-select-dropdown>
+<!--                                            [model]="element.selected_roles"-->
+
+<!--            </div>-->
           </div>
         </td>
       </ng-container>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.scss
index dd14655..254d8dd 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.scss
@@ -137,7 +137,6 @@
 }
 
 .roles {
-  // width: 30%;
 
   .selector-wrapper-edit {
     position: relative;
@@ -343,11 +342,11 @@ table {
   }
 
   .roles {
-    width: 30%;
+    width: 35%;
   }
 
   .users {
-    width: 40%;
+    width: 35%;
   }
 
   .actions {
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts
index cf2f086..88c9fda 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts
@@ -25,7 +25,7 @@ import { ToastrService } from 'ngx-toastr';
 import { RolesGroupsService, HealthStatusService } from '../../core/services';
 import { CheckUtils } from '../../core/util';
 import { DICTIONARY } from '../../../dictionary/global.dictionary';
-import {ProgressBarService} from "../../core/services/progress-bar.service";
+import {ProgressBarService} from '../../core/services/progress-bar.service';
 
 @Component({
   selector: 'dlab-roles',
@@ -37,7 +37,7 @@ export class RolesComponent implements OnInit {
 
   public groupsData: Array<any> = [];
   public roles: Array<any> = [];
-  public rolesList: Array<string> = [];
+  public rolesList: Array<any> = [];
   public setupGroup: string = '';
   public setupUser: string = '';
   public manageUser: string = '';
@@ -65,18 +65,27 @@ export class RolesComponent implements OnInit {
   }
 
   openManageRolesDialog() {
-    setTimeout(() => {this.progressBarService.startProgressBar()} , 0);
+    setTimeout(() => {this.progressBarService.startProgressBar(); } , 0);
     this.rolesService.getGroupsData().subscribe(groups => {
       this.rolesService.getRolesData().subscribe(
         (roles: any) => {
           this.roles = roles;
-          this.rolesList = roles.map(role => role.description);
+          this.rolesList = roles.map((role, index) => {
+            if (index < 10) {
+              return {role: role.description, label: 'templetes'};
+            } else if (index > 9 && index < 20) {
+              return {role: role.description, label: 'Inctance shapes'};
+            } else {
+              return {role: role.description, label: 'Resource'};
+            }
+          });
+
           this.updateGroupData(groups);
 
           this.stepperView = false;
         },
         error => this.toastr.error(error.message, 'Oops!'));
-        this.progressBarService.stopProgressBar()
+        this.progressBarService.stopProgressBar();
       },
       error => {
       this.toastr.error(error.message, 'Oops!');
@@ -172,7 +181,7 @@ export class RolesComponent implements OnInit {
   }
 
   public updateGroupData(groups) {
-    this.groupsData = groups.map(v=>v).sort((a,b) => (a.group > b.group) ? 1 : ((b.group > a.group) ? -1 : 0));
+    this.groupsData = groups.map(v => v).sort((a, b) => (a.group > b.group) ? 1 : ((b.group > a.group) ? -1 : 0));
     this.groupsData.forEach(item => {
       item.selected_roles = item.roles.map(role => role.description);
     });
@@ -219,6 +228,10 @@ export class RolesComponent implements OnInit {
     this.healthStatusService.getEnvironmentHealthStatus()
       .subscribe((result: any) => this.healthStatus = result);
   }
+
+  public onUpdate($event): void {
+    this.groupsData.filter(group => group.group === $event.type)[0].selected_roles = $event.model;
+  }
 }
 
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/index.ts b/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/index.ts
index bac0dd6..4ea5a14 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/index.ts
@@ -25,6 +25,7 @@ import { MultiSelectDropdownComponent } from './multi-select-dropdown/multi-sele
 import { DirectivesModule } from '../../core/directives';
 import { KeysPipeModule, UnderscorelessPipeModule } from '../../core/pipes';
 import { BubbleModule } from '..';
+import {MultiLevelSelectDropdownComponent} from './multi-level-select-dropdown/multi-level-select-dropdown.component';
 
 export * from './multi-select-dropdown/multi-select-dropdown.component';
 export * from './dropdown-list/dropdown-list.component';
@@ -37,7 +38,7 @@ export * from './dropdown-list/dropdown-list.component';
     UnderscorelessPipeModule,
     BubbleModule
   ],
-  declarations: [DropdownListComponent, MultiSelectDropdownComponent],
-  exports: [DropdownListComponent, MultiSelectDropdownComponent]
+  declarations: [DropdownListComponent, MultiSelectDropdownComponent, MultiLevelSelectDropdownComponent],
+  exports: [DropdownListComponent, MultiSelectDropdownComponent, MultiLevelSelectDropdownComponent]
 })
 export class FormControlsModule {}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.html
new file mode 100644
index 0000000..1cc1c11
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.html
@@ -0,0 +1,70 @@
+<!--
+  ~ 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 class="dropdown-multiselect btn-group" ngClass="{{type || ''}}">
+  <button type="button" #list (click)="multiactions.toggle($event, list)">
+    <span class="ellipsis" *ngIf="model.length === 0">Select roles</span>
+    <span class="selected-items ellipsis" *ngIf="model.length !== 0">
+      {{selectedRolesList()}}
+    </span>
+    <span class="caret-btn"><i class="material-icons">keyboard_arrow_down</i></span>
+  </button>
+
+  <bubble-up #multiactions position="bottom" [keep-open]="true" class="mt-5">
+    <ul class="list-menu" id="scrolling">
+      <li class="filter-actions">
+        <a class="select_all" (click)="selectAllOptions($event)">
+          <i class="material-icons">playlist_add_check</i>&nbsp;All
+        </a>
+        <a class="deselect_all" (click)="deselectAllOptions($event)">
+          <i class="material-icons">clear</i>&nbsp;None
+        </a>
+      </li>
+
+        <ng-template  ngFor let-item [ngForOf]="items" let-i="index">
+          <li class="role-label" role="presentation" *ngIf="i === 0 || model && item.label !== items[i - 1].label" (click)="toggleItemsForLable(item.label, $event)">
+            <a href="#" class="list-item" role="menuitem">
+              <span class="arrow" [ngClass]="{'rotate-arrow': isOpenCategory[item.label], 'arrow-checked': selectedAllInCattegory(item.label) || selectedSomeInCattegory(item.label)}"></span>
+              <span class="empty-checkbox" [ngClass]="{'checked': selectedAllInCattegory(item.label) || selectedSomeInCattegory(item.label)}" (click)="toggleselectedCategory($event, model, item.label);$event.stopPropagation()" >
+                <span class="checked-checkbox" *ngIf="selectedAllInCattegory(item.label)"></span>
+                <span class="line-checkbox" *ngIf="selectedSomeInCattegory(item.label)"></span>
+              </span>
+              {{item.label}}
+            </a>
+          </li>
+
+          <li class="role-item" role="presentation" *ngIf="model && isOpenCategory[item.label]" >
+            <a href="#" class="list-item" role="menuitem" (click)="toggleSelectedOptions($event, model, item)">
+              <span class="empty-checkbox" [ngClass]="{'checked': checkInModel(item.role)}">
+                <span class="checked-checkbox" *ngIf="checkInModel(item.role)"></span>
+              </span>
+              {{item.role}}
+            </a>
+          </li>
+        </ng-template>
+
+      <li *ngIf="items?.length == 0">
+        <a role="menuitem" class="list-item">
+          <span class="material-icons">visibility_off</span>
+          No {{type}}
+        </a>
+      </li>
+    </ul>
+  </bubble-up>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.scss b/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.scss
new file mode 100644
index 0000000..1726f47
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.scss
@@ -0,0 +1,319 @@
+/*!
+ * 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.
+ */
+
+.dropdown-list,
+.dropdown-multiselect {
+  width: 100%;
+  position: relative;
+}
+
+.dropdown-list button,
+.dropdown-multiselect button {
+  height: 38px;
+  width: 100%;
+  background: #fff;
+  padding-left: 15px;
+  font-size: 14px;
+  // height: 34px;
+  text-align: left;
+  white-space: nowrap;
+  cursor: pointer;
+  border-radius: 0;
+  border: none;
+  outline: none;
+  box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12);
+}
+
+.dropdown-list {
+  button {
+    line-height: 38px;
+
+    span {
+      color: #4a5c89;
+
+      em {
+        font-size: 13px;
+        color: #35afd5;
+        margin-right: 0px;
+        font-style: normal;
+      }
+    }
+  }
+}
+
+.dropdown-list button:active,
+.dropdown-list button:focus,
+.dropdown-multiselect button:active,
+.dropdown-multiselect button:focus {
+  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, .2), 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12);
+}
+
+.dropdown-multiselect {
+  button {
+    span {
+      color: #999;
+      font-weight: 300;
+      display: inline-block;
+      max-width: 80%;
+    }
+
+    .selected-items {
+      color: #4a5c89;
+      max-width: 500px;
+    }
+  }
+}
+
+.selected-items strong {
+  font-weight: 300;
+}
+
+.dropdown-list,
+.dropdown-multiselect {
+  .caret-btn {
+    position: absolute;
+    top: 0;
+    right: 0;
+    width: 40px;
+    height: 100%;
+    text-align: center;
+    padding: 7px;
+    -webkit-appearance: none;
+    -moz-appearance: none;
+    border-left: 1px solid #ececec;
+    background: #fff;
+    color: #36afd5 !important;
+  }
+
+  .list-menu {
+    width: 100%;
+    max-height: 450px;
+    left: 0;
+    padding: 0;
+    margin: 0;
+    overflow-y: auto;
+    overflow-x: hidden;
+
+    li {
+      padding: 0;
+      margin: 0;
+    }
+    .role-item{
+      padding-left: 30px;
+    }
+
+
+  }
+
+  &.statuses {
+    .list-menu {
+      .list-item {
+        text-transform: capitalize;
+      }
+    }
+  }
+
+  &.resources {
+    .list-menu {
+      .list-item {
+        text-transform: capitalize;
+      }
+    }
+  }
+}
+
+.dropdown-list .list-menu a,
+.dropdown-multiselect .list-menu li a {
+  display: block;
+  padding: 10px;
+  padding-left: 15px;
+  position: relative;
+  font-weight: 300;
+  cursor: pointer;
+  color: #4a5c89;
+  text-decoration: none;
+}
+
+.dropdown-multiselect .list-menu li a {
+  padding-left: 45px;
+  transition: all .45s ease-in-out;
+}
+
+.dropdown-list .list-menu a:hover,
+.dropdown-multiselect .list-menu a:hover {
+  background: #f7f7f7;
+  color: #35afd5;
+}
+
+.dropdown-multiselect .list-menu .filter-actions {
+  display: flex;
+  cursor: pointer;
+  border-bottom: 1px solid #ececec;
+}
+
+.dropdown-multiselect .list-menu .filter-actions a {
+  width: 50%;
+  color: #35afd5;
+  display: block;
+  padding: 0;
+  line-height: 40px !important;
+  text-align: center;
+}
+
+.dropdown-list {
+
+  .list-menu,
+  .title {
+    span {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      font-weight: 300;
+    }
+  }
+}
+
+.dropdown-list .list-menu li span.caption {
+  display: block;
+  padding: 10px 15px;
+  cursor: default;
+}
+
+.dropdown-list .list-menu li i,
+.dropdown-list .list-menu li strong {
+  display: inline-block;
+  width: 30px;
+  text-align: center;
+  vertical-align: middle;
+  color: #35afd5;
+  line-height: 26px;
+}
+
+.dropdown-list .list-menu li i {
+  vertical-align: sub;
+  font-size: 18px;
+}
+
+.dropdown-list .list-menu a {
+  padding: 12px;
+  padding-left: 15px;
+  position: relative;
+  font-weight: 300;
+  cursor: pointer;
+
+  em {
+    font-size: 13px;
+    color: #35afd5;
+    margin-right: 0px;
+    font-style: normal;
+  }
+}
+
+.dropdown-list .list-menu a.empty {
+  height: 36px;
+}
+
+.dropdown-multiselect .list-menu .filter-actions i {
+  vertical-align: sub;
+  color: #35afd5;
+  font-size: 18px;
+  line-height: 26px;
+  transition: all .45s ease-in-out;
+}
+
+.dropdown-multiselect .list-menu .select_all:hover,
+.dropdown-multiselect .list-menu .select_all:hover i {
+  color: #4eaf3e !important;
+  background: #f9fafb;
+}
+
+.dropdown-multiselect .list-menu .deselect_all:hover,
+.dropdown-multiselect .list-menu .deselect_all:hover i {
+  color: #f1696e !important;
+  background: #f9fafb;
+}
+
+.dropdown-multiselect .list-menu a {
+  span {
+    position: absolute;
+    top: 10px;
+    left: 25px;
+    color: #35afd5;
+
+    &.checked-checkbox {
+      top: 0px;
+      left: 4px;
+      width: 5px;
+      height: 10px;
+      border-bottom: 2px solid white;
+      border-right: 2px solid white;
+      position: absolute;
+      transform: rotate(45deg);
+    }
+
+    &.line-checkbox {
+      top: 0px;
+      left: 2px;
+      width: 8px;
+      height: 7px;
+      border-bottom: 2px solid white;
+    }
+
+    &.arrow{
+      width: 16px;
+      height: 14px;
+      border: 8px solid transparent;
+      border-left: 8px solid lightgrey;
+      left: 10px;
+      top: 12px;
+      border-radius: 3px;
+
+      &.rotate-arrow{
+        transform: rotate(90deg);
+        transition: .1s ease-in-out;
+        top: 15px;
+        left: 6px;
+      }
+
+      &.arrow-checked{
+        border-left: 8px solid #35afd5;
+      }
+    }
+  }
+
+
+}
+
+.dropdown-multiselect.btn-group.open .dropdown-toggle {
+  box-shadow: none;
+}
+
+.empty-checkbox {
+  width: 16px;
+  height: 16px;
+  border-radius: 2px;
+  border: 2px solid lightgrey;
+  margin-top: 2px;
+  position: relative;
+  &.checked {
+    border-color: #35afd5;
+    background-color: #35afd5;
+  }
+}
+
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.ts
new file mode 100644
index 0000000..dc70999
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.ts
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+import { Input, Output, Component, EventEmitter } from '@angular/core';
+
+@Component({
+  selector: 'multi-level-select-dropdown',
+  templateUrl: 'multi-level-select-dropdown.component.html',
+  styleUrls: ['multi-level-select-dropdown.component.scss']
+})
+
+export class MultiLevelSelectDropdownComponent {
+  isOpen: boolean = false;
+
+  @Input() items: Array<any>;
+  @Input() model: Array<any>;
+  @Input() type: string;
+  @Output() selectionChange: EventEmitter<{}> = new EventEmitter();
+
+  public isOpenCategory = {
+  };
+
+  toggleSelectedOptions($event, model, value) {
+    $event.preventDefault();
+    const currRole = this.model.filter(v => v.role === value.role).length;
+    currRole ? this.model = model.filter(v => v.role !== value.role) : model.push(value);
+
+    this.onUpdate($event);
+
+    $event.preventDefault();
+  }
+
+  toggleselectedCategory($event, model, value) {
+    $event.preventDefault();
+    const categoryItems = this.items.filter(role => role.label === value);
+    this.selectedAllInCattegory(value) ? this.model = this.model.filter(role => role.label !== value) : categoryItems.forEach(role => {
+      if (!model.includes(role)) {model.push(role); }
+    });
+    this.onUpdate($event);
+  }
+
+  selectAllOptions($event) {
+    $event.preventDefault();
+    this.model = [];
+    this.items.forEach((item) => { this.model.push(item); });
+
+    this.onUpdate($event);
+    $event.preventDefault();
+  }
+
+  deselectAllOptions($event) {
+    this.model = [];
+    this.onUpdate($event);
+    $event.preventDefault();
+  }
+
+  onUpdate($event): void {
+    this.selectionChange.emit({ model: this.model.map(v => v.role), type: this.type, $event });
+  }
+
+  public toggleItemsForLable(label, $event) {
+    this.isOpenCategory[label] = !this.isOpenCategory[label];
+    $event.preventDefault();
+  }
+
+  public selectedAllInCattegory(category) {
+    const selected = this.model.filter(role => role.label === category);
+    const categoryItems = this.items.filter(role => role.label === category);
+    return selected.length === categoryItems.length;
+  }
+
+  public selectedSomeInCattegory(category) {
+    const selected = this.model.filter(role => role.label === category);
+    const categoryItems = this.items.filter(role => role.label === category);
+    return selected.length && selected.length !== categoryItems.length;
+  }
+
+  public checkInModel(item) {
+    return this.model.filter(v => v.role === item).length;
+  }
+
+  public selectedRolesList() {
+    return this.model.map(role => role.role).join(',');
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts
index 78ddd3c..952dfd0 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts
@@ -38,8 +38,8 @@ import {
   animateChild,
   state
 } from '@angular/animations';
-import {skip} from "rxjs/operators";
-import {ProgressBarService} from "../../core/services/progress-bar.service";
+import {skip} from 'rxjs/operators';
+import {ProgressBarService} from '../../core/services/progress-bar.service';
 
 @Component({
   selector: 'dlab-navbar',


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@dlab.apache.org
For additional commands, e-mail: commits-help@dlab.apache.org