You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dlab.apache.org by an...@apache.org on 2019/03/01 11:09:54 UTC

[incubator-dlab] branch DLAB-375 created (now 6e29cd2)

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

ankovalyshyn pushed a change to branch DLAB-375
in repository https://gitbox.apache.org/repos/asf/incubator-dlab.git.


      at 6e29cd2  [DLAB-375]: moved modal dialogs; admin preferences

This branch includes the following new commits:

     new 66e0eaa  [DLAB-375]: active manage env link
     new b879b8c  [DLAB-375]: added isAdmin property to manage views
     new 6e29cd2  [DLAB-375]: moved modal dialogs; admin preferences

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



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


[incubator-dlab] 03/03: [DLAB-375]: moved modal dialogs; admin preferences

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 6e29cd251509ad495c2d0ce81200dab7f3ede50b
Author: Andriana Kovalyshyn <An...@epam.com>
AuthorDate: Fri Mar 1 13:09:41 2019 +0200

    [DLAB-375]: moved modal dialogs; admin preferences
---
 .../backup-dilog/backup-dilog.component.html       |  81 ++++++
 .../backup-dilog/backup-dilog.component.scss       |  25 ++
 .../backup-dilog/backup-dilog.component.ts         |  74 ++++++
 .../manage-environment-dilog.component.html        |  72 ++++++
 .../manage-environment-dilog.component.scss        |  86 +++++++
 .../manage-environment-dilog.component.ts          | 126 +++++++++
 .../group-name-validarion.directive.ts             |  36 +++
 .../manage-roles-groups.component.html             | 154 +++++++++++
 .../manage-roles-groups.component.scss             | 282 +++++++++++++++++++++
 .../manage-roles-groups.component.ts               | 189 ++++++++++++++
 .../ssn-monitor/ssn-monitor.component.html         | 116 +++++++++
 .../ssn-monitor/ssn-monitor.component.scss         |  49 ++++
 .../ssn-monitor/ssn-monitor.component.ts           |  58 +++++
 13 files changed, 1348 insertions(+)

diff --git a/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.html b/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.html
new file mode 100644
index 0000000..862b8d0
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.html
@@ -0,0 +1,81 @@
+<!--
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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.
+
+-->
+
+<modal-dialog #bindDialog modalClass="backup-dialog modal-sm">
+  <modal-header>
+    <h4 class="modal-title">Backup options</h4>
+  </modal-header>
+  <modal-content>
+    <div class="content-box" *ngIf="backupOptions">
+      <div class="hold-block">
+        <mat-slide-toggle
+          labelPosition="before"
+          [checked]="backupOptions.configFiles[0] === 'all'"
+          (change)="onHoldChanged($event, 'configFiles')">
+          <span class="hold-label">Configuration files</span>
+        </mat-slide-toggle>
+      </div>
+      <div class="hold-block">
+        <mat-slide-toggle
+          labelPosition="before"
+          [checked]="backupOptions.keys[0] === 'all'"
+          (change)="onHoldChanged($event, 'keys')">
+          <span class="hold-label">User keys</span>
+        </mat-slide-toggle>
+      </div>
+      <div class="hold-block">
+        <mat-slide-toggle
+          labelPosition="before"
+          [checked]="backupOptions.databaseBackup"
+          (change)="onHoldChanged($event, 'databaseBackup')">
+          <span class="hold-label">Database</span>
+        </mat-slide-toggle>
+      </div>
+      <div class="hold-block">
+        <mat-slide-toggle
+          labelPosition="before"
+          [checked]="backupOptions.certificates[0] === 'all'"
+          (change)="onHoldChanged($event, 'certificates')">
+          <span class="hold-label">SSL Certificates</span>
+        </mat-slide-toggle>
+      </div>
+      <div class="hold-block">
+        <mat-slide-toggle
+          labelPosition="before"
+          [checked]="backupOptions.jars[0] === 'all'"
+          (change)="onHoldChanged($event, 'jars')">
+          <span class="hold-label">JAR files</span>
+        </mat-slide-toggle>
+      </div>
+      <div class="hold-block">
+        <mat-slide-toggle
+          labelPosition="before"
+          [checked]="backupOptions.logsBackup"
+          (change)="onHoldChanged($event, 'logsBackup')">
+          <span class="hold-label">Log files</span>
+        </mat-slide-toggle>
+      </div>
+      <div class="text-center m-top-30 m-bott-10">
+        <button mat-raised-button type="button" class="butt" (click)="bindDialog.close(); backupOptions.setDegault()">
+          Cancel
+        </button>
+        <button mat-raised-button type="button" (click)="applyOptions()" class="butt butt-success" [disabled]="!valid">Apply</button>
+      </div>
+    </div>
+  </modal-content>
+</modal-dialog>
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.scss b/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.scss
new file mode 100644
index 0000000..6d36f82
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.scss
@@ -0,0 +1,25 @@
+/***************************************************************************
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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.
+
+****************************************************************************/
+
+.hold-block {
+  padding: 5px 10px;
+  transition: all 0.4s ease-out;
+  &:hover {
+    color: #35afd5;
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.ts b/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.ts
new file mode 100644
index 0000000..4d0e9e9
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.ts
@@ -0,0 +1,74 @@
+/***************************************************************************
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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 { Component, OnInit, ViewChild, Output, EventEmitter } from '@angular/core';
+import { DICTIONARY } from '../../../dictionary/global.dictionary';
+
+import { BackupOptionsModel } from '../management.model';
+
+@Component({
+  selector: 'dlab-backup-dilog',
+  templateUrl: './backup-dilog.component.html',
+  styleUrls: ['./backup-dilog.component.scss']
+})
+export class BackupDilogComponent implements OnInit {
+  readonly DICTIONARY = DICTIONARY;
+  public backupOptions: BackupOptionsModel = new BackupOptionsModel([], [], [], [], false, false);
+  public valid: boolean = true;
+
+  @ViewChild('bindDialog') bindDialog;
+  @Output() backupOpts: EventEmitter<{}> = new EventEmitter();
+
+  ngOnInit() {
+    this.backupOptions.setDegault();
+    this.bindDialog.onClosing = () => this.backupOptions.setDegault();
+  }
+
+  public open(param): void {
+    this.valid = true;
+    this.bindDialog.open(param);
+  }
+
+  public onHoldChanged($event, key): void {
+    this.backupOptions[key] instanceof Array
+      ? (this.backupOptions[key][0] = $event.checked ? 'all' : 'skip')
+      : (this.backupOptions[key] = !this.backupOptions[key]);
+
+    this.checkValidity();
+  }
+
+  public applyOptions(): void {
+    this.backupOpts.emit(this.backupOptions);
+    this.backupOptions.setDegault();
+    this.bindDialog.close();
+  }
+
+  private checkValidity(): void {
+    const items = [];
+
+    Object.keys(this.backupOptions).forEach(el => {
+      if (this.backupOptions[el] instanceof Array) {
+        if (this.backupOptions[el][0] && this.backupOptions[el][0] !== 'skip') items.push(this.backupOptions[el][0]);
+      } else {
+        if (this.backupOptions[el]) items.push(this.backupOptions[el]) ;
+      }
+    });
+
+    this.valid = items.length > 0;
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.html b/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.html
new file mode 100644
index 0000000..200dd61
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.html
@@ -0,0 +1,72 @@
+<!--
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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.
+
+-->
+
+<modal-dialog #bindDialog modalClass="manage-env-dialog modal-xl-s">
+  <modal-header>
+    <h4 class="modal-title">Manage environment</h4>
+  </modal-header>
+  <modal-content>
+    <div class="content-box">
+      <div *ngIf="usersList.length">
+        <form [formGroup]="manageUsersForm" (submit)="setBudgetLimits(manageUsersForm.value)" novalidate>
+          <mat-list>
+            <mat-list-item class="list-header">
+              <div class="username">User</div>
+              <div class="quotes" *ngIf="DICTIONARY.cloud_provider !== 'gcp'">Limit</div>
+              <div class="action">Actions</div>
+            </mat-list-item>
+            <div class="scrolling-content" id="scrolling" formArrayName="users">
+              <mat-list-item  *ngFor="let item of usersEnvironments.controls; let i=index" [formGroupName]="i" class="list-item"> 
+                <div class="username ellipsis">{{ manageUsersForm.controls['users'].controls[i].value['name'] }}</div>
+                <div class="quotes" *ngIf="DICTIONARY.cloud_provider !== 'gcp'">
+                    <input type="number" min="0" placeholder="Enter limit, in USD" formControlName="budget">
+                    <span class="danger_color" *ngIf="!manageUsersForm?.controls['users'].controls[i].controls['budget'].valid && !manageUsersForm?.controls['users'].controls[i].controls['budget'].hasError('overrun')">Only positive integers are allowed</span>
+                    <span class="danger_color" *ngIf="manageUsersForm?.controls['users'].controls[i].controls['budget'].hasError('overrun')">Per-user quotes cannot be greater than total budget</span>
+                </div>
+                <div class="action">
+                  <span *ngIf=" manageUsersForm.controls['users'].controls[i].value['status'] === 'ACTIVE'; else not_active" matTooltip="Stop" matTooltipPosition="above" (click)="applyAction('stop', item)"><i class="material-icons">pause_circle_outline</i></span>
+
+                  <ng-template #not_active>
+                    <span class="disabled" matTooltip="User's environment is not active" matTooltipPosition="above">
+                      <i class="material-icons">pause_circle_outline</i>
+                    </span>
+                  </ng-template>
+
+                  <span matTooltip="Terminate" matTooltipPosition="above" (click)="applyAction('terminate', item)"><i class="material-icons">phonelink_off</i></span>
+                </div>
+              </mat-list-item>
+            </div>
+            <div class="control-group total-budget" *ngIf="DICTIONARY.cloud_provider !== 'gcp'">
+              <label class="label">Total budget</label>
+              <div class="control">
+                <input type="number" formControlName="total" placeholder="Enter total budget, in USD">
+                <span class="danger_color" *ngIf="manageUsersForm?.controls['total'].hasError('overrun')">Total budget cannot be lower than a sum of users quotes</span>
+              </div>
+            </div>
+            <div class="text-center m-top-30" *ngIf="DICTIONARY.cloud_provider !== 'gcp'">
+              <button mat-raised-button type="button" (click)="bindDialog.close()" class="butt action">Cancel</button>
+              <button mat-raised-button type="submit" [disabled]="!manageUsersForm.valid"
+                      class="butt butt-success" [ngClass]="{'not-allowed': !manageUsersForm.valid}">Apply</button>
+            </div>
+          </mat-list>
+        </form>
+      </div>
+      <div class="info message" *ngIf="!usersList.length">No active users environments</div>
+    </div>
+  </modal-content>
+</modal-dialog>
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.scss b/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.scss
new file mode 100644
index 0000000..c10c2e8
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.scss
@@ -0,0 +1,86 @@
+/***************************************************************************
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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.
+
+****************************************************************************/
+
+.manage-env-dialog {
+  .mat-list {
+    .mat-list-item {
+      height: 60px;
+      position: relative;
+      .mat-list-item-content {
+        padding: 0 !important;
+        justify-content: space-between;
+        color: #577289;
+      }
+    }
+  }
+  .scrolling-content {
+    max-height: 300px;
+    min-height: 85px;
+    overflow-y: auto;
+  }
+  .username {
+    width: 45%;
+  }
+  .quotes {
+    width: 40%;
+    margin-right: 10px;
+    position: relative;
+    .danger_color {
+      position: absolute;
+      left: 0;
+      top: 36px;
+    }
+  }
+  .action {
+    width: 15%;
+    span {
+      padding: 3px;
+      cursor: pointer;
+      &:hover {
+        color: #35afd5;
+      }
+      i {
+        font-size: 20px;
+      }
+    }
+    .disabled {
+      cursor: not-allowed !important;
+      pointer-events: all;
+      opacity: .6;
+      &:hover {
+        color: #6b8299;
+      }
+    }
+  }
+  .total-budget {
+    border-top: 1px solid #edf1f5;
+    padding-top: 15px;
+    .control {
+      position: relative;
+      width: 56%;
+      .danger_color {
+        position: absolute;
+        left: 0;
+        bottom: -20px;
+      }
+    }
+    .label {
+      width: 44%;
+    }
+  }
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.ts b/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.ts
new file mode 100644
index 0000000..212a3b6
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.ts
@@ -0,0 +1,126 @@
+/***************************************************************************
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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 { Component, ViewChild, Output, EventEmitter, ViewEncapsulation, Inject } from '@angular/core';
+import { Validators, FormBuilder, FormGroup, FormArray } from '@angular/forms';
+import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
+import { DICTIONARY } from '../../../dictionary/global.dictionary';
+
+@Component({
+  selector: 'dlab-manage-env-dilog',
+  templateUrl: './manage-environment-dilog.component.html',
+  styleUrls: ['./manage-environment-dilog.component.scss'],
+  encapsulation: ViewEncapsulation.None
+})
+export class ManageEnvironmentComponent {
+  readonly DICTIONARY = DICTIONARY;
+  public usersList: Array<string> = [];
+  public manageUsersForm: FormGroup;
+  public manageTotalsForm: FormGroup;
+
+  @ViewChild('bindDialog') bindDialog;
+  @Output() manageEnv: EventEmitter<{}> = new EventEmitter();
+  @Output() setBudget: EventEmitter<{}> = new EventEmitter();
+
+  constructor(
+    private _fb: FormBuilder,
+    public dialog: MatDialog
+  ) { }
+
+  get usersEnvironments(): FormArray{
+    return <FormArray>this.manageUsersForm.get('users');
+  }
+
+  public open(param, data, settings): void {
+    this.usersList = data;
+    !this.manageUsersForm && this.initForm();
+
+    this.manageUsersForm.setControl('users',
+    this._fb.array((this.usersList || []).map((x: any) => this._fb.group({
+      name: x.name, budget: [x.budget, [Validators.min(0), this.userValidityCheck.bind(this)]], status: x.status
+    }))));
+    this.manageUsersForm.controls['total'].setValue(settings.conf_max_budget || null);
+    this.bindDialog.open(param);
+  }
+
+  public setBudgetLimits(value) {
+    this.setBudget.emit(value);
+    this.bindDialog.close();
+  }
+
+  public applyAction(action, user) {
+    const dialogRef: MatDialogRef<ConfirmActionDialogComponent> = this.dialog.open(
+      ConfirmActionDialogComponent, { data: {action, user: user.value.name}, width: '550px' });
+    dialogRef.afterClosed().subscribe(result => {
+      if (result) this.manageEnv.emit({action, user: user.value.name});
+    });
+  }
+
+  private initForm(): void {
+    this.manageUsersForm = this._fb.group({
+      total: [null, [Validators.min(0), this.totalValidityCheck.bind(this)]],
+      users: this._fb.array([this._fb.group({ name: '', budget: null, status: ''})])
+    });
+  }
+
+  private getCurrentUsersTotal(): number {
+    return this.manageUsersForm.value.users.reduce((memo, el) => memo += el.budget, 0);
+  }
+
+  private getCurrentTotalValue(): number {
+    return this.manageUsersForm.value.total;
+  }
+
+  private totalValidityCheck(control) {
+    return (control && control.value)
+      ? (control.value >= this.getCurrentUsersTotal() ? null : { overrun: true })
+      : null;
+  }
+
+  private userValidityCheck(control) {
+    if (control && control.value) {
+      return (this.getCurrentTotalValue() && this.getCurrentTotalValue() < this.getCurrentUsersTotal()) ? { overrun: true } : null;
+    }
+  }
+}
+
+@Component({
+  selector: 'dialog-result-example-dialog',
+  template: `
+  <div mat-dialog-content class="content">
+    <p>Environment of <b>{{ data.user }}</b> will be 
+      <span *ngIf="data.action === 'terminate'"> terminated.</span>
+      <span *ngIf="data.action === 'stop'">stopped.</span>
+    </p>
+    <p class="m-top-20"><strong>Do you want to proceed?</strong></p>
+  </div>
+  <div class="text-center">
+    <button type="button" class="butt" mat-raised-button (click)="dialogRef.close()">No</button>
+    <button type="button" class="butt butt-success" mat-raised-button (click)="dialogRef.close(true)">Yes</button>
+  </div>
+  `,
+  styles: [`
+    .content { color: #718ba6; padding: 20px 50px; font-size: 14px; font-weight: 400 }
+  `]
+})
+export class ConfirmActionDialogComponent {
+  constructor(
+    public dialogRef: MatDialogRef<ConfirmActionDialogComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: any
+  ) { }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/group-name-validarion.directive.ts b/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/group-name-validarion.directive.ts
new file mode 100644
index 0000000..2b35c8d
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/group-name-validarion.directive.ts
@@ -0,0 +1,36 @@
+/***************************************************************************
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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 { Directive, forwardRef, Input } from '@angular/core';
+import { AbstractControl, NG_VALIDATORS, Validator } from '@angular/forms';
+
+@Directive({
+  selector: '[validator][ngModel],[group-dir][ngFormControl]',
+  providers: [{
+    multi: true,
+    provide: NG_VALIDATORS,
+    useExisting: forwardRef(() => GroupNameValidationDirective)
+  }]
+})
+export class GroupNameValidationDirective implements Validator {
+  @Input() validator: Function;
+
+  validate(control: AbstractControl): { [key: string]: any; } {
+    return this.validator(control);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.html b/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.html
new file mode 100644
index 0000000..0803011
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.html
@@ -0,0 +1,154 @@
+<!--
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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.
+
+-->
+
+<modal-dialog #bindDialog modalClass="manage-roles-dialog modal-xxl">
+  <modal-header>
+    <h4 class="modal-title">Manage roles</h4>
+  </modal-header>
+  <modal-content>
+    <div class="content-box">
+      <button mat-raised-button class="butt add-group" (click)="stepperView = !stepperView">
+        <i class="material-icons">people_outline</i>Add group
+      </button>
+      <mat-horizontal-stepper #stepper *ngIf="stepperView" class="stepper ani">
+        <mat-step>
+          <ng-template matStepLabel>Groups</ng-template>
+          <div class="inner-step mat-reset">
+            <input [validator]="groupValidarion()" type="text" placeholder="Enter group name" [(ngModel)]="setupGroup" #setupGroupName="ngModel">
+            <div class="danger_color" *ngIf="setupGroupName.errors?.patterns && setupGroupName.dirty">Group name can only contain letters, numbers, hyphens and '_'</div>
+            <div class="danger_color" *ngIf="setupGroupName.errors?.duplicate && setupGroupName.dirty">Group name already exists</div>
+          </div>
+          <div class="text-center m-bott-10">
+            <button mat-raised-button (click)="resetDialog()" class="butt">Cancel</button>
+            <button mat-raised-button matStepperNext class="butt">Next<i class="material-icons">keyboard_arrow_right</i></button>
+          </div>
+        </mat-step>
+        <mat-step>
+          <ng-template matStepLabel>Roles</ng-template>
+          <div class="inner-step mat-reset">
+            <div class="selector-wrapper">
+              <!-- <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'role'" [items]="rolesList" [model]="setupRoles"></multi-select-dropdown> -->
+              <mat-form-field>
+                  <mat-select multiple [compareWith]="compareObjects" name="roles" [(value)]="setupRoles" placeholder="Select roles">
+                    <mat-option class="multiple-select" disabled>
+                      <a class="select ani" (click)="selectAllOptions(setupRoles, rolesList)">
+                        <i class="material-icons">playlist_add_check</i>&nbsp;All
+                      </a>
+                      <a class="deselect ani" (click)="selectAllOptions(setupRoles)">
+                        <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>
+          <div class="text-center m-bott-10">
+            <button mat-raised-button matStepperPrevious class="butt"><i class="material-icons">keyboard_arrow_left</i>Back</button>
+            <button mat-raised-button (click)="resetDialog()" class="butt">Cancel</button>
+            <button mat-raised-button matStepperNext class="butt">Next<i class="material-icons">keyboard_arrow_right</i></button>
+          </div>
+        </mat-step>
+        <mat-step>
+          <ng-template matStepLabel>Users</ng-template>
+          <div class="inner-step mat-reset">
+            <input type="text" placeholder="Enter user login" [(ngModel)]="setupUser">
+          </div>
+          <div class="text-center m-bott-10">
+            <button mat-raised-button matStepperPrevious class="butt"><i class="material-icons">keyboard_arrow_left</i>Back</button>
+            <button mat-raised-button (click)="resetDialog()" class="butt">Cancel</button>
+            <button mat-raised-button (click)="manageAction('create', 'group')" class="butt butt-success"
+                    [disabled]="!setupGroup || setupGroupName.errors?.pattern || !setupRoles.length > 0">Create</button>
+          </div>
+        </mat-step>
+      </mat-horizontal-stepper>
+      <mat-divider></mat-divider>
+      <div *ngIf="groupsData.length" class="ani">
+        <table class="dashboard_table">
+          <tr>
+            <th class="th_name groups">Name</th>
+            <th class="roles">Roles</th>
+            <th class="users">Users</th>
+            <th class="th_actions">Action</th>
+          </tr>
+          <tr *ngFor="let item of groupsData" class="dashboard_table_body filter-row">
+            <td>{{ item.group }}</td>
+            <td class="roles mat-reset">
+              <div class="selector-wrapper-edit">
+                <mat-form-field>
+                  <mat-select multiple [compareWith]="compareObjects" name="selected_roles" [(value)]="item.selected_roles" placeholder="Select roles">
+                    <mat-option class="multiple-select" disabled>
+                      <a class="select ani" (click)="selectAllOptions(item, rolesList, 'selected_roles')">
+                        <i class="material-icons">playlist_add_check</i>&nbsp;All
+                      </a>
+                      <a class="deselect ani" (click)="selectAllOptions(item, 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 ani">
+                    <i class="material-icons">keyboard_arrow_down</i>
+                  </button>
+                </mat-form-field>
+              </div>
+            </td>
+            <td class="users-list ani">
+              <mat-form-field class="chip-list">
+                <input #user matInput placeholder="Enter user login" pattern="[@.-_0-9a-zA-Z]" (keydown.enter)="addUser(user.value, item); user.value = ''">
+                <button mat-icon-button matSuffix (click)="addUser(user.value, item); user.value = ''">
+                  <mat-icon>person_add</mat-icon>
+                </button>
+              </mat-form-field>
+              <div class="list-selected list-container ani">
+                <mat-chip-list>
+                  <mat-chip *ngFor="let user of item.users">
+                    {{ user }}
+                    <a class="material-icons" (click)="removeUser(item.users, user)">clear</a>
+                  </mat-chip>
+                </mat-chip-list>
+              </div>
+            </td>
+            <td class="actions">
+              <button mat-icon-button class="reset ani" (click)="manageAction('delete', 'group', item)">
+                <i class="material-icons">close</i>
+              </button>
+
+              <button mat-icon-button class="apply ani" matTooltip="Group cannot be updated without any selected role"
+                      matTooltipPosition="above"
+                      [matTooltipDisabled]="item.selected_roles.length > 0"> 
+                <span class="mid" [ngClass]="{ 'not-allowed' : !item.selected_roles.length }"
+                      (click)="manageAction('update', 'group', item)">
+                  <i class="material-icons">done</i>
+                </span>
+              </button>
+            </td>
+          </tr>
+        </table>
+      </div>
+    </div>
+  </modal-content>
+</modal-dialog>
+
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.scss b/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.scss
new file mode 100644
index 0000000..205fd83
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.scss
@@ -0,0 +1,282 @@
+/***************************************************************************
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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.
+
+****************************************************************************/
+
+::ng-deep .mat-option:first-child .mat-pseudo-checkbox { display: none; }
+
+.caret {
+  width: 40px;
+  color: #4ab8dc;
+  border: none;
+  border-left: 1px solid #ececec;
+  background-color: #fff;
+  position: absolute;
+  right: 0;
+  top: 0px;
+  height: 36px;
+  cursor: pointer;
+  &.not-allowed {
+    background-color: #dcdcdc;
+  }
+}
+
+
+.content-box {
+  padding: 20px 30px 35px;
+  height: 85vh;
+  overflow-y: auto;
+}
+.no-details {
+  color: #d8d8d8;
+}
+.mat-divider {
+  margin: 10px 0;
+}
+.stepper {
+  height: 190px;
+  margin-top: 10px;
+  .inner-step {
+    height: 70px;
+    padding: 5px;
+    display: flex;
+    justify-content: center;
+    flex-direction: column;
+    text-align: center;
+    input {
+      width: 490px;
+      align-self: center;
+    }
+    .caret {
+      i {
+        margin-top: 3px;
+      }
+    }
+  }
+}
+.selector-wrapper {
+  display: flex;
+  align-self: center;
+  width: 490px;
+  height: 36px;
+  padding-left: 10px;
+  font-family: 'Open Sans', sans-serif;
+  font-size: 15px;
+  font-weight: 300;
+  box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
+  mat-form-field {
+    width: 100%;
+    .mat-form-field-wrapper {
+      padding-bottom: 0;
+    }
+    .mat-icon {
+      font-size: 20px;
+    }
+  }
+  .dropdown-multiselect {
+    width: 100% !important;
+    > button {
+      padding: 6px 22px;
+    }
+  }
+}
+.list-header {
+  padding: 0 15px;
+}
+.scrolling-content {
+  max-height: 450px;
+  overflow-x: hidden;
+  overflow-y: auto;
+  display: block;
+  padding: 15px 5px;
+  &.stepper-opened {
+    height: 250px;
+  }
+}
+.roles {
+  width: 30%;
+  padding: 0 10px;
+  .selector-wrapper-edit {
+    position: relative;
+    display: flex;
+    justify-content: space-between;
+    height: 36px;
+    padding-left: 10px;
+    background: #fff;
+    box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
+    multi-select-dropdown {
+      width: 100%;
+      .dropdown-multiselect {
+        > button {
+          padding: 8px 22px 5px;
+        }
+      }
+    }
+    .caret {
+      &:hover {
+        box-shadow: 0 3px 1px -10px rgba(0, 0, 0, 0.2), 0 2px 1px 0 rgba(0, 0, 0, 0.17), 0 1px 5px 0 rgba(0, 0, 0, 0.12)
+      }
+    }
+  }
+}
+.groups {
+  width: 20%;
+}
+.users {
+  width: 30%;
+  padding: 0 10px;
+}
+.users-list {
+  padding: 5px 10px;
+  font-family: 'Open Sans', sans-serif;
+  font-size: 15px;
+  font-weight: 300;
+  color: #577289;
+  position: relative;
+  i {
+    color: #FF5722;
+    font-size: 18px;
+    cursor: pointer;
+  }
+  .list-selected {
+    width: 100%;
+    margin-top: 50px;
+    height: inherit;
+  }
+}
+.expanded-panel {
+  display: flex;
+  align-items: flex-end;
+  .add-input-block {
+    display: flex;
+    height: 36px;
+    padding-right: 0;
+    outline: none;
+    box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
+    input {
+      height: 36px;
+      padding: 0;
+      padding-left: 10px;
+      width: 170px;
+    }
+    .caret {
+      width: 50px;
+    }
+  }
+}
+
+
+mat-expansion-panel-header {
+  &.mat-expansion-panel-header {
+    font-family: 'Open Sans', sans-serif;
+    font-size: 15px;
+    font-weight: 300;
+    color: #577289;
+  }
+}
+
+.mat-step-header {
+  .mat-step-icon {
+    background-color: #36afd5 !important;
+  }
+  .mat-step-label {
+    font-family: 'Open Sans', sans-serif;
+    font-size: 16px;
+    font-weight: 300;
+  }
+}
+
+.dashboard_table {
+  .dashboard_table_body {
+    .actions {
+      padding: 10px 0;
+    }
+    &.filter-row {
+      .actions {
+        button {
+          background: none;
+          .mid {
+            vertical-align: sub;
+          }
+        }
+      }
+    }
+  }
+  .th_actions {
+    width: 10%;
+  }
+}
+
+.mat-chip:not(.mat-basic-chip) {
+  transition: box-shadow 280ms cubic-bezier(.4,0,.2,1);
+  padding: 7px 0 7px 10px;
+  border-radius: 24px;
+  cursor: default;
+  display: inline-block;
+  position: relative;
+  padding-right: 25px;
+  white-space: nowrap;
+  max-width: 100%;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  margin: 2px !important;
+}
+mat-chip.mat-chip a {
+  position: absolute;
+  right: 15px;
+}
+mat-form-field.chip-list {
+  &.mat-form-field {
+    position: absolute;
+    top: 2px;
+    width: 94%;
+    font-size: 16px;
+    font-weight: 300;
+  }
+}
+
+.mat-raised-button {
+  &.butt {
+    &.butt-success {
+      margin-left: 0;
+    }
+  }
+}
+.multiple-select {
+  border-bottom: 1px solid #dedbdb;
+  padding: 0;
+  a {
+    display: inline-block;
+    width: 50%;
+    padding: 0 15px;
+    vertical-align: middle;
+    color: #575757;
+    cursor: pointer;
+    i {
+      vertical-align: sub;
+      font-size: 20px;
+    }
+    &:hover {
+      color: #4eaf3e;
+      background: #f9fafb;
+    }
+    &.deselect {
+      &:hover {
+        color: #f1696e;
+      }
+    }
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.ts b/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.ts
new file mode 100644
index 0000000..25124ca
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.ts
@@ -0,0 +1,189 @@
+/***************************************************************************
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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 { Component, OnInit, ViewChild, Output, EventEmitter, Inject } from '@angular/core';
+import { ValidatorFn, FormControl, NgModel } from '@angular/forms';
+import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
+import { DICTIONARY } from '../../../dictionary/global.dictionary';
+
+@Component({
+  selector: 'dlab-manage-roles-groups',
+  templateUrl: './manage-roles-groups.component.html',
+  styleUrls: ['../../resources/resources-grid/resources-grid.component.css', './manage-roles-groups.component.scss']
+})
+export class ManageRolesGroupsComponent implements OnInit {
+  readonly DICTIONARY = DICTIONARY;
+
+  public groupsData: Array<any> = [];
+  public roles: Array<any> = [];
+  public rolesList: Array<string> = [];
+  public setupGroup: string = '';
+  public setupUser: string = '';
+  public manageUser: string = '';
+  public setupRoles: Array<string> = [];
+  public updatedRoles: Array<string> = [];
+  public delimitersRegex = /[-_]?/g;
+  public groupnamePattern = new RegExp(/^[a-zA-Z0-9_\-]+$/);
+
+  @ViewChild('bindDialog') bindDialog;
+  @Output() manageRolesGroupAction: EventEmitter<{}> = new EventEmitter();
+  stepperView: boolean = false;
+
+  constructor(public dialog: MatDialog) { }
+
+  ngOnInit() {
+    this.bindDialog.onClosing = () => this.resetDialog();
+  }
+
+  public open(param, groups, roles): void {
+    this.roles = roles;
+    this.rolesList = roles.map(role => role.description);
+    this.updateGroupData(groups);
+
+    this.stepperView = false;
+    this.bindDialog.open(param);
+  }
+
+  public onUpdate($event) {
+    if ($event.type === 'role') {
+      this.setupRoles = $event.model;
+    } else {
+      this.updatedRoles = $event.model;
+    }
+    $event.$event.preventDefault();
+  }
+
+  public selectAllOptions(item, values, byKey?) {
+    byKey ? (item[byKey] = values ? values : []) : this.setupRoles = values ? values : [];
+  }
+
+  public manageAction(action: string, type: string, item?: any, value?) {
+    if (action === 'create') {
+      this.manageRolesGroupAction.emit(
+        { action, type, value: {
+          name: this.setupGroup,
+          users: this.setupUser ? this.setupUser.split(',').map(elem => elem.trim()) : [],
+          roleIds: this.extractIds(this.roles, this.setupRoles)
+        }
+      });
+      this.stepperView = false;
+    } else if (action === 'delete') {
+      const data = (type === 'users') ? {group: item.group, user: value} : {group: item.group, id: item};
+      const dialogRef: MatDialogRef<ConfirmDeleteUserAccountDialogComponent> = this.dialog.open(
+        ConfirmDeleteUserAccountDialogComponent,
+        { data: data, width: '550px' }
+      );
+
+      dialogRef.afterClosed().subscribe(result => {
+        if (result) {
+          const emitValue = (type === 'users')
+            ? {action, type, id: item.name, value: { user: value, group: item.group }}
+            : {action, type, id: item.name, value: item.group} ;
+          this.manageRolesGroupAction.emit(emitValue);
+        }
+      });
+    } else if (action === 'update') {
+      this.manageRolesGroupAction.emit({action, type, value: {
+        name: item.group,
+        roleIds: this.extractIds(this.roles, item.selected_roles),
+        users: item.users || [] }});
+    }
+    this.resetDialog();
+  }
+
+  public extractIds(sourceList, target) {
+    return sourceList.reduce((acc, item) => {
+      target.includes(item.description) && acc.push(item._id);
+      return acc;
+    }, []);
+  }
+
+  public updateGroupData(groups) {
+    this.groupsData = groups;
+
+    this.groupsData.forEach(item => {
+      item.selected_roles = item.roles.map(role => role.description);
+    });
+  }
+
+  public groupValidarion(): ValidatorFn {
+
+    const duplicateList: any = this.groupsData.map(item => item.group);
+    return <ValidatorFn>((control: FormControl) => {
+      if (control.value && duplicateList.includes(this.delimitersFiltering(control.value)))
+        return { duplicate: true };
+
+      if (control.value && !this.groupnamePattern.test(control.value))
+        return { patterns: true };
+
+      return null;
+    });
+  }
+
+  public compareObjects(o1: any, o2: any): boolean {
+    return o1.toLowerCase() === o2.toLowerCase();
+  }
+
+  public delimitersFiltering(resource): string {
+    return resource.replace(this.delimitersRegex, '').toString().toLowerCase();
+  }
+
+  public resetDialog() {
+    this.stepperView = false;
+    this.setupGroup = '';
+    this.setupUser = '';
+    this.manageUser = '';
+    this.setupRoles = [];
+    this.updatedRoles = [];
+  }
+
+  public removeUser(list, item): void {
+    list.splice(list.indexOf(item), 1);
+  }
+
+  public addUser(value: string, item): void {
+    if (value && value.trim()) {
+      item.users instanceof Array ? item.users.push(value.trim()) : item.users = [value.trim()];
+    }
+  }
+}
+
+
+@Component({
+  selector: 'dialog-result-example-dialog',
+  template: `
+  <div mat-dialog-content class="content">
+    <p *ngIf="data.user">User <strong>{{ data.user }}</strong> will be deleted from <strong>{{ data.group }}</strong> group.</p>
+    <p *ngIf="data.id">Group <strong>{{ data.group }}</strong> will be decommissioned.</p>
+    <p class="m-top-20"><strong>Do you want to proceed?</strong></p>
+  </div>
+  <div class="text-center">
+    <button type="button" class="butt" mat-raised-button (click)="dialogRef.close()">No</button>
+    <button type="button" class="butt butt-success" mat-raised-button (click)="dialogRef.close(true)">Yes</button>
+  </div>
+  `,
+  styles: [`
+    .content { color: #718ba6; padding: 20px 50px; font-size: 14px; font-weight: 400 }
+  `]
+})
+export class ConfirmDeleteUserAccountDialogComponent {
+  constructor(
+    public dialogRef: MatDialogRef<ConfirmDeleteUserAccountDialogComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: any
+  ) { }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.html b/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.html
new file mode 100644
index 0000000..94f7564
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.html
@@ -0,0 +1,116 @@
+<!--
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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.
+
+-->
+
+<modal-dialog #bindDialog modalClass="ssn-monitor-dialog modal-lg">
+  <modal-header>
+    <h4 class="modal-title">SSN Monitor</h4>
+  </modal-header>
+  <modal-content>
+    <div class="content-box" *ngIf="monitorData">
+      <div class="ssn-info">
+        <mat-tab-group *ngIf="monitorData?.processorInfo" [dynamicHeight]="true">
+          <mat-tab label="CPU">
+            <div class="scrolling-content" id="scrolling">
+              <mat-list-item class="list-header">
+                <div class="col">Name</div>
+                <div class="col">{{ monitorData.processorInfo.name }}</div>
+              </mat-list-item>
+              <mat-list-item class="list-header">
+                <div class="col">Vendor</div>
+                <div class="col">{{ monitorData.processorInfo.vendor }}</div>
+              </mat-list-item>
+              <mat-list-item class="list-header">
+                <div class="col">Logical Core Count</div>
+                <div class="col">{{ monitorData.processorInfo.logicalCoreCount }}</div>
+              </mat-list-item>
+              <mat-list-item class="list-header">
+                <div class="col">Physical Core Count</div>
+                <div class="col">{{ monitorData.processorInfo.physicalCoreCount }}</div>
+              </mat-list-item>
+              <mat-list-item class="list-header">
+                <div class="col">Current System Load</div>
+                <div class="col">{{ monitorData.processorInfo.currentSystemLoad /100 | percent:'1.0-2' }}</div>
+              </mat-list-item>
+              <mat-list-item class="list-header">
+                <div class="col">System Load Average</div>
+                <div class="col">{{ monitorData.processorInfo.systemLoadAverage /100 | percent:'1.0-2' }}</div>
+              </mat-list-item>
+              <mat-list-item class="list-header">
+                <div class="col">CPU 64 Bit</div>
+                <div class="col">{{ monitorData.processorInfo.cpu64Bit }}</div>
+              </mat-list-item>
+            </div>
+          </mat-tab>
+
+          <mat-tab label="Memory">
+            <div class="scrolling-content" id="scrolling">
+              <mat-list-item class="list-header">
+                <div class="col">Available Memory</div>
+                <div class="col">{{ convertSize(monitorData.memoryInfo.availableMemory) }}</div>
+              </mat-list-item>
+              <mat-list-item class="list-header">
+                <div class="col">Total Memory</div>
+                <div class="col">{{ convertSize(monitorData.memoryInfo.totalMemory) }}</div>
+              </mat-list-item>
+              <mat-list-item class="list-header">
+                <div class="col">Swap Total</div>
+                <div class="col">{{ convertSize(monitorData.memoryInfo.swapTotal) }}</div>
+              </mat-list-item>
+              <mat-list-item class="list-header">
+                <div class="col">Swap Used</div>
+                <div class="col">{{ convertSize(monitorData.memoryInfo.swapUsed) }}</div>
+              </mat-list-item>
+              <mat-list-item class="list-header">
+                <div class="col">Pages Page In</div>
+                <div class="col">{{ convertSize(monitorData.memoryInfo.pagesPageIn) }}</div>
+              </mat-list-item>
+              <mat-list-item class="list-header">
+                <div class="col">Pages Page Out</div>
+                <div class="col">{{ convertSize(monitorData.memoryInfo.pagesPageOut) }}</div>
+              </mat-list-item>
+            </div>
+
+          </mat-tab>
+          <mat-tab label="HDD">
+            <div class="scrolling-content" id="scrolling">
+              <div *ngFor="let disk of monitorData.disksInfo; let i = index">
+                <mat-list-item>
+                  <div class="col"><strong>Disk {{i +1}}</strong></div>
+                </mat-list-item>
+                <mat-list-item>
+                  <div class="col">Used Space</div>
+                  <div class="col">{{ convertSize(disk.usedByteSpace) }}</div>
+                </mat-list-item>
+                <mat-list-item>
+                  <div class="col">Total Space</div>
+                  <div class="col">{{ convertSize(disk.totalByteSpace) }}</div>
+                </mat-list-item>
+              </div>
+            </div>
+          </mat-tab>
+        </mat-tab-group>
+        <div class="text-center">
+          <button type="button" class="butt" mat-raised-button (click)="close()">Close</button>
+        </div>
+      </div>
+      <div class="info message" *ngIf="isEmpty(monitorData)">
+        No ssn monitor data available
+      </div>
+    </div>
+  </modal-content>
+</modal-dialog>
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.scss b/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.scss
new file mode 100644
index 0000000..a4d6f9d
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.scss
@@ -0,0 +1,49 @@
+/***************************************************************************
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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.
+
+****************************************************************************/
+
+.ssn-monitor-dialog {
+  .content-box {
+    padding-top: 10px !important;
+  }
+  .ssn-info {
+    min-height: 400px;
+    max-height: 500px;
+    .scrolling-content {
+      max-height: 310px;
+      overflow-y: auto;
+    }
+    .text-center {
+      position: absolute;
+      bottom: 20px;
+      left: 0;
+      right: 0;
+    }
+  }
+  .mat-list-item-content {
+    display: flex;
+    justify-content: initial;
+    color: #577289;
+    padding: 15px 5px;
+    border-bottom: 1px solid #f3f2f2;
+    font-size: 15px;
+    .col {
+      width: 50%;
+      font-weight: 300;
+     }
+  }
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.ts b/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.ts
new file mode 100644
index 0000000..b7d5e0c
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.ts
@@ -0,0 +1,58 @@
+/***************************************************************************
+
+Copyright (c) 2016, EPAM SYSTEMS INC
+
+Licensed 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 { Component, OnInit, ViewChild, Output, EventEmitter, ViewEncapsulation } from '@angular/core';
+import { DICTIONARY } from './../../../dictionary/global.dictionary';
+
+@Component({
+  selector: 'dlab-ssn-monitor',
+  templateUrl: './ssn-monitor.component.html',
+  styleUrls: ['./ssn-monitor.component.scss'],
+  encapsulation: ViewEncapsulation.None
+})
+export class SsnMonitorComponent implements OnInit {
+  readonly DICTIONARY = DICTIONARY;
+
+  public errorMessage: string = '';
+  public monitorData = {};
+
+  @ViewChild('bindDialog') bindDialog;
+  @Output() manageEnv: EventEmitter<{}> = new EventEmitter();
+
+  ngOnInit() {}
+
+  public open(param, data): void {
+    this.monitorData = data || {};
+    this.bindDialog.open(param);
+  }
+  public close(param, data): void {
+    this.bindDialog.close();
+  }
+
+  public isEmpty(obj) {
+    if (obj) return Object.keys(obj).length === 0;
+  }
+
+  public convertSize(bytes) {
+    if (Number(bytes) === 0) return '0 Byte';
+
+    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(1024));
+    return parseFloat((bytes / Math.pow(1024, i)).toFixed(3)) + ' ' + sizes[i];
+  }
+}


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


[incubator-dlab] 02/03: [DLAB-375]: added isAdmin property to manage views

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit b879b8c4e2a1acec83176748c8407699a0d52a07
Author: Andriana Kovalyshyn <An...@epam.com>
AuthorDate: Fri Mar 1 12:52:24 2019 +0200

    [DLAB-375]: added isAdmin property to manage views
---
 .../management-grid/management-grid.component.ts          | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.ts
index efcf6e8..f444ac6 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.ts
@@ -35,10 +35,11 @@ export interface ManageAction {
     '../../resources/computational/computational-resources-list/computational-resources-list.component.scss'
   ]
 })
-export class ManagementGridComponent {
+export class ManagementGridComponent implements OnInit{
   @Input() allEnvironmentData: Array<any>;
   @Input() resources: Array<any>;
   @Input() uploadKey: boolean;
+  @Input() isAdmin: boolean;
   @Output() refreshGrid: EventEmitter<{}> = new EventEmitter();
   @Output() actionToggle: EventEmitter<ManageAction> = new EventEmitter();
 
@@ -47,13 +48,17 @@ export class ManagementGridComponent {
 
   constructor(public dialog: MatDialog) {}
 
+  ngOnInit() {
+
+  }
+
   buildGrid(): void {
     this.refreshGrid.emit();
   }
 
-  toggleResourceAction(environment, action, resource?) {
+  toggleResourceAction(environment, action: string, resource?) {
     if (resource) {
-      let resource_name = resource ? resource.computational_name : environment.name;
+      const resource_name = resource ? resource.computational_name : environment.name;
       const dialogRef: MatDialogRef<ConfirmationDialog> = this.dialog.open(ConfirmationDialog, {
         data: { action, resource_name, user: environment.user },
         width: '550px'
@@ -63,7 +68,9 @@ export class ManagementGridComponent {
       });
     } else {
       if (action === 'stop') {
-        this.confirmationDialog.open({ isFooter: false }, environment, environment.name === 'edge node' ? ConfirmationDialogType.StopEdgeNode : ConfirmationDialogType.StopExploratory);
+        this.confirmationDialog.open(
+          { isFooter: false }, environment,
+          environment.name === 'edge node' ? ConfirmationDialogType.StopEdgeNode : ConfirmationDialogType.StopExploratory);
       } else if (action === 'terminate') {
         this.confirmationDialog.open({ isFooter: false }, environment, ConfirmationDialogType.TerminateExploratory);
       }


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


[incubator-dlab] 01/03: [DLAB-375]: active manage env link

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 66e0eaac96001190d3752ce87ab05ada9d640b44
Author: Andriana Kovalyshyn <An...@epam.com>
AuthorDate: Fri Mar 1 12:46:56 2019 +0200

    [DLAB-375]: active manage env link
---
 .../resources/webapp/src/app/shared/navbar/navbar.component.html    | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
index b7b833c..e551b89 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
@@ -28,9 +28,11 @@ limitations under the License.
     <nav role="navigation">
       <mat-menu #menu="matMenu" [overlapTrigger]="false">
         <a class="nav-item" mat-menu-item [routerLink]="['/resources_list']" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">List of Resources</a>
-        <a class="nav-item" mat-menu-item [routerLink]="['/environment_health_status']" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">Environment Health Status</a>
         <a *ngIf="healthStatus.billingEnabled" class="nav-item" mat-menu-item [routerLink]="['/billing_report']" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">Billing Report</a>
-        <a *ngIf="healthStatus.admin" class="nav-item" mat-menu-item [routerLink]="['/environment_management']" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">Environment Management</a>
+        <a class="nav-item" mat-menu-item [routerLink]="['/environment_management']" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">Environment Management</a>
+
+
+        <a class="nav-item" mat-menu-item [routerLink]="['/environment_health_status']" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">Environment Health Status</a>
       </mat-menu>
     </nav>
     <a [routerLink]="['/resources_list']" class="navbar-logo">


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