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/06/15 07:02:32 UTC

[incubator-dlab] branch DLAB-1861 created (now 9023420)

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

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


      at 9023420  [DLAB-1861]: Added check box to 'Environment management' page

This branch includes the following new commits:

     new 1b1006b  [DLAB-1861]: Added checkboxes to environment management
     new d4b1d86  [DLAB-1861]: Added actions to checkboxes environment management
     new 9023420  [DLAB-1861]: Added check box to 'Environment management' page

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] 02/03: [DLAB-1861]: Added actions to checkboxes environment management

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

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

commit d4b1d867c75f5bfd7c730a6f529a789c89fc69a6
Author: Dmytro_Gnatyshyn <di...@ukr.net>
AuthorDate: Thu Jun 11 15:28:41 2020 +0300

    [DLAB-1861]: Added actions to checkboxes environment management
---
 .../management-grid/management-grid.component.html |  2 +-
 .../management-grid/management-grid.component.ts   | 38 ++-----------
 .../management/management.component.html           | 35 +++++++++++-
 .../management/management.component.ts             | 64 ++++++++++++++++++++++
 .../resources/webapp/src/assets/styles/_theme.scss | 50 +++++++++++++++++
 5 files changed, 155 insertions(+), 34 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
index 56fd4c5..a7f217a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
@@ -23,7 +23,7 @@
       <th mat-header-cell *matHeaderCellDef class="checkbox label-header">
      </th>
       <td mat-cell *matCellDef="let element">
-        <div *ngIf="element.type !== 'edge node'" class="empty-checkbox" [ngClass]="{'checked': element.isSelected}" (click)="toggleActionForAll(element);$event.stopPropagation()" >
+        <div *ngIf="element.type !== 'edge node' && (element.status==='running' || element.status==='stopped')" class="empty-checkbox" [ngClass]="{'checked': element.isSelected}" (click)="toggleActionForAll(element);$event.stopPropagation()" >
           <span class="checked-checkbox" *ngIf="element.isSelected"></span>
         </div>
       </td>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
index 0403c69..b0295e2 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
@@ -60,9 +60,11 @@ export class ManagementGridComponent implements OnInit {
   @Input() currentUser: string = '';
   @Output() refreshGrid: EventEmitter<{}> = new EventEmitter();
   @Output() actionToggle: EventEmitter<ManageAction> = new EventEmitter();
+  @Output() emitSelectedList: EventEmitter<ManageAction> = new EventEmitter();
 
   displayedColumns: string[] = [ 'checkbox', 'user', 'type', 'project', 'shape', 'status', 'resources', 'actions'];
   displayedFilterColumns: string[] = ['checkbox-filter', 'user-filter', 'type-filter', 'project-filter', 'shape-filter', 'status-filter', 'resource-filter', 'actions-filter'];
+  private selected;
 
   constructor(
     private healthStatusService: HealthStatusService,
@@ -151,38 +153,7 @@ export class ManagementGridComponent implements OnInit {
   }
 
   toggleResourceAction(environment: any, action: string, resource?): void {
-    if (resource) {
-      const resource_name = resource ? resource.computational_name : environment.name;
-      this.dialog.open(ReconfirmationDialogComponent, {
-        data: { action, resource_name, user: environment.user },
-        width: '550px', panelClass: 'error-modalbox'
-      }).afterClosed().subscribe(result => {
-        result && this.actionToggle.emit({ action, environment, resource });
-      });
-    } else {
-      const type = (environment.type.toLowerCase() === 'edge node')
-        ? ConfirmationDialogType.StopEdgeNode : ConfirmationDialogType.StopExploratory;
-
-      if (action === 'stop') {
-        this.dialog.open(ConfirmationDialogComponent, {
-          data: { notebook: environment, type: type, manageAction: true }, panelClass: 'modal-md'
-        }).afterClosed().subscribe(() => this.buildGrid());
-      } else if (action === 'terminate') {
-        this.dialog.open(ConfirmationDialogComponent, {
-          data: { notebook: environment, type: ConfirmationDialogType.TerminateExploratory, manageAction: true }, panelClass: 'modal-md'
-        }).afterClosed().subscribe(() => this.buildGrid());
-      } else if (action === 'run') {
-        this.healthStatusService.runEdgeNode().subscribe(() => {
-          this.buildGrid();
-          this.toastr.success('Edge node is starting!', 'Processing!');
-        }, () => this.toastr.error('Edge Node running failed!', 'Oops!'));
-      } else if (action === 'recreate') {
-        this.healthStatusService.recreateEdgeNode().subscribe(() => {
-          this.buildGrid();
-          this.toastr.success('Edge Node recreation is processing!', 'Processing!');
-        }, () => this.toastr.error('Edge Node recreation failed!', 'Oops!'));
-      }
-    }
+    this.actionToggle.emit({ action, environment, resource });
   }
 
   isResourcesInProgress(notebook) {
@@ -243,6 +214,9 @@ export class ManagementGridComponent implements OnInit {
 
   toggleActionForAll(element) {
     element.isSelected = !element.isSelected;
+    this.selected = this.allFilteredEnvironmentData.filter(item => !!item.isSelected);
+    console.log(this.selected);
+    this.emitSelectedList.emit(this.selected)
   }
 }
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
index 4c4bdae..2509429 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
@@ -20,6 +20,39 @@
 <div class="base-retreat">
   <div class="sub-nav">
     <div *ngIf="healthStatus?.admin" class="admin-group">
+      <div class="action-wrapper admin-group" >
+        <span class="action-button-wrapper">
+          <button
+            type="button" class="butt actions-btn"
+            mat-raised-button
+            [disabled]="!selected.length"
+            (click)="toogleActions();$event.stopPropagation()"
+          >
+            Actions
+            <i class="material-icons" >{{ !isActionsOpen ?  'expand_more' : 'expand_less' }}</i>
+          </button>
+          </span>
+        <div class="action-menu" *ngIf="isActionsOpen">
+          <span>
+          <button
+           type="button" class="butt action-menu-item"
+            [ngClass]="{'disabled': selectedRunning.length === 0  || selectedStopped.length !== 0 }"
+            mat-raised-button
+            [disabled]="selectedRunning.length === 0  || selectedStopped.length !== 0"
+            (click)="resourseAction('stop');$event.stopPropagation()"
+          >
+            Stop
+          </button>
+            </span>
+          <button
+            type="button" class="butt action-menu-item"
+            mat-raised-button
+            (click)="resourseAction('terminate');$event.stopPropagation()"
+          >
+            Terminate
+          </button>
+        </div>
+      </div>
       <button mat-raised-button class="butt ssn" (click)="showEndpointsDialog()">
         <i class="material-icons"></i>Endpoints
       </button>
@@ -40,6 +73,6 @@
   <mat-divider></mat-divider>
   <management-grid [currentUser]="user.toLowerCase()" [isAdmin]="healthStatus?.admin"
     [environmentsHealthStatuses]="healthStatus?.list_resources" (refreshGrid)="buildGrid()"
-    (actionToggle)="manageEnvironmentAction($event)">
+    (actionToggle)="toggleResourceAction($event)" (emitSelectedList)="selectedList($event)">
   </management-grid>
 </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
index 87e554d..2c3813a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
@@ -39,6 +39,8 @@ import { ExploratoryModel } from '../../resources/resources-grid/resources-grid.
 
 import { EnvironmentsDataService } from './management-data.service';
 import { ProjectService } from '../../core/services';
+import {ConfirmationDialogComponent, ConfirmationDialogType} from '../../shared/modal-dialog/confirmation-dialog';
+import {ReconfirmationDialogComponent} from './management-grid/management-grid.component';
 
 @Component({
   selector: 'environments-management',
@@ -50,6 +52,10 @@ export class ManagementComponent implements OnInit {
   public healthStatus: GeneralEnvironmentStatus;
   // public anyEnvInProgress: boolean = false;
   public dialogRef: any;
+  private selected: any[] = [];
+  public isActionsOpen: boolean = false;
+  public selectedRunning: any[];
+  public selectedStopped: any[];
 
   constructor(
     public toastr: ToastrService,
@@ -171,4 +177,62 @@ export class ManagementComponent implements OnInit {
   private getTotalBudgetData() {
     return this.healthStatusService.getTotalBudgetData();
   }
+
+  public selectedList($event) {
+    this.selected = $event;
+    if (this.selected.length === 0) {
+      this.isActionsOpen = false;
+    }
+
+    this.selectedRunning = this.selected.filter(item => item.status === 'running');
+    this.selectedStopped = this.selected.filter(item => item.status === 'stopped');
+
+    console.log(this.selectedRunning.length, this.selectedStopped.length);
+  }
+
+  public toogleActions() {
+    this.isActionsOpen = !this.isActionsOpen;
+  }
+
+  toggleResourceAction($event): void {
+    const {environment, action, resource} = $event;
+    if (resource) {
+      const resource_name = resource ? resource.computational_name : environment.name;
+      this.dialog.open(ReconfirmationDialogComponent, {
+        data: { action, resource_name, user: environment.user },
+        width: '550px', panelClass: 'error-modalbox'
+      }).afterClosed().subscribe(result => {
+        result && this.manageEnvironmentAction({ action, environment, resource });
+      });
+    } else {
+      const type = (environment.type.toLowerCase() === 'edge node')
+        ? ConfirmationDialogType.StopEdgeNode : ConfirmationDialogType.StopExploratory;
+
+      if (action === 'stop') {
+        this.dialog.open(ConfirmationDialogComponent, {
+          data: { notebook: environment, type: type, manageAction: true }, panelClass: 'modal-md'
+        }).afterClosed().subscribe(() => this.buildGrid());
+      } else if (action === 'terminate') {
+        this.dialog.open(ConfirmationDialogComponent, {
+          data: { notebook: environment, type: ConfirmationDialogType.TerminateExploratory, manageAction: true }, panelClass: 'modal-md'
+        }).afterClosed().subscribe(() => this.buildGrid());
+      } else if (action === 'run') {
+        this.healthStatusService.runEdgeNode().subscribe(() => {
+          this.buildGrid();
+          this.toastr.success('Edge node is starting!', 'Processing!');
+        }, () => this.toastr.error('Edge Node running failed!', 'Oops!'));
+      } else if (action === 'recreate') {
+        this.healthStatusService.recreateEdgeNode().subscribe(() => {
+          this.buildGrid();
+          this.toastr.success('Edge Node recreation is processing!', 'Processing!');
+        }, () => this.toastr.error('Edge Node recreation failed!', 'Oops!'));
+      }
+    }
+  }
+
+  public resourseAction(action) {
+    this.selected.forEach(resource => {
+      this.toggleResourceAction({environment: resource, action: action});
+    })
+  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss b/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
index 1f80ef0..9c9963f 100644
--- a/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
+++ b/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
@@ -458,6 +458,56 @@ span.mat-slide-toggle-content {
   }
 }
 
+.action-wrapper{
+  position: relative;
+  display: block !important;
+
+  .action-button-wrapper{
+    position: relative;
+    width: 160px;
+  }
+
+  .mat-raised-button.butt{
+    margin-bottom: 0;
+
+    &.actions-btn{
+      padding-right: 38px;
+
+      .material-icons{
+        transition: ease-in-out 1s;
+        font-size: 25px;
+        position: absolute;
+        top: 7px;
+        right: 30px;
+      }
+    }
+  }
+
+  .action-menu{
+    position: absolute;
+    text-align: center;
+    display: block;
+    background-color: #fff;
+
+    &-item.mat-raised-button.butt{
+      z-index: 101;
+      margin: 0;
+      box-shadow: 0 2px 1px -1px rgba(0,0,0,.2), 0 0px 0px 0 rgba(0,0,0,.14), 0 1px 5px 0 rgba(0,0,0,.12);
+      width: 160px;
+      padding: 0 20px;
+      border-radius: 0;
+      font-style: normal;
+      font-weight: 600;
+      font-size: 15px;
+      font-family: 'Open Sans', sans-serif;
+      color: #577289;
+      position: relative;
+      overflow: hidden;
+      line-height: 36px;
+    }
+  }
+}
+
 mat-horizontal-stepper {
   .mat-step-header {
     .mat-step-icon {


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


[incubator-dlab] 01/03: [DLAB-1861]: Added checkboxes to environment management

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

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

commit 1b1006bebbfaac48d21b916d9eacaa5b555885b2
Author: Dmytro_Gnatyshyn <di...@ukr.net>
AuthorDate: Wed Jun 10 18:00:04 2020 +0300

    [DLAB-1861]: Added checkboxes to environment management
---
 .../management-grid/management-grid.component.html | 16 ++++++++++++++
 .../management-grid/management-grid.component.scss |  5 ++++-
 .../management-grid/management-grid.component.ts   | 10 ++++++---
 .../resources/webapp/src/assets/styles/_theme.scss | 25 ++++++++++++++++++++++
 4 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
index 8b7e459..56fd4c5 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
@@ -19,6 +19,16 @@
 
 <div class="ani">
   <table mat-table [dataSource]="allFilteredEnvironmentData" class="data-grid management mat-elevation-z6">
+    <ng-container matColumnDef="checkbox">
+      <th mat-header-cell *matHeaderCellDef class="checkbox label-header">
+     </th>
+      <td mat-cell *matCellDef="let element">
+        <div *ngIf="element.type !== 'edge node'" class="empty-checkbox" [ngClass]="{'checked': element.isSelected}" (click)="toggleActionForAll(element);$event.stopPropagation()" >
+          <span class="checked-checkbox" *ngIf="element.isSelected"></span>
+        </div>
+      </td>
+    </ng-container>
+
     <ng-container matColumnDef="user">
       <th mat-header-cell *matHeaderCellDef class="user label-header">
         <span class="label">User</span>
@@ -176,6 +186,12 @@
 
 
     <!-- FILTERING -->
+    <ng-container matColumnDef="checkbox-filter" sticky>
+      <th mat-header-cell *matHeaderCellDef class="filter-row-item">
+
+      </th>
+    </ng-container>
+
     <ng-container matColumnDef="user-filter" sticky>
       <th mat-header-cell *matHeaderCellDef class="filter-row-item">
         <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'users'" [items]="filterConfiguration.users"
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.scss
index 5d40c3e..14b700e 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.scss
@@ -19,7 +19,10 @@
 
 .data-grid {
   &.management {
-
+    .mat-column-checkbox{
+      padding-left: 10px;
+      padding-right: 10px;
+    }
     .user{
       width: 15%;
     }
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
index 796859a..0403c69 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
@@ -61,8 +61,8 @@ export class ManagementGridComponent implements OnInit {
   @Output() refreshGrid: EventEmitter<{}> = new EventEmitter();
   @Output() actionToggle: EventEmitter<ManageAction> = new EventEmitter();
 
-  displayedColumns: string[] = ['user', 'type', 'project', 'shape', 'status', 'resources', 'actions'];
-  displayedFilterColumns: string[] = ['user-filter', 'type-filter', 'project-filter', 'shape-filter', 'status-filter', 'resource-filter', 'actions-filter'];
+  displayedColumns: string[] = [ 'checkbox', 'user', 'type', 'project', 'shape', 'status', 'resources', 'actions'];
+  displayedFilterColumns: string[] = ['checkbox-filter', 'user-filter', 'type-filter', 'project-filter', 'shape-filter', 'status-filter', 'resource-filter', 'actions-filter'];
 
   constructor(
     private healthStatusService: HealthStatusService,
@@ -113,7 +113,7 @@ export class ManagementGridComponent implements OnInit {
     let filteredData = this.getEnvironmentDataCopy();
 
     const containsStatus = (list, selectedItems) => {
-      if (list){
+      if (list) {
         return list.filter((item: any) => { if (selectedItems.indexOf(item.status) !== -1) return item; });
       }
     };
@@ -240,6 +240,10 @@ export class ManagementGridComponent implements OnInit {
     })
       .afterClosed().subscribe(() => {});
   }
+
+  toggleActionForAll(element) {
+    element.isSelected = !element.isSelected;
+  }
 }
 
 
diff --git a/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss b/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
index 43e9c50..1f80ef0 100644
--- a/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
+++ b/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
@@ -433,6 +433,31 @@ span.mat-slide-toggle-content {
   }
 }
 
+.empty-checkbox {
+  min-width: 16px;
+  width: 16px;
+  height: 16px;
+  border-radius: 2px;
+  border: 2px solid lightgrey;
+  margin-top: 2px;
+  position: relative;
+  cursor: pointer;
+  &.checked {
+    border-color: #35afd5;
+    background-color: #35afd5;
+  }
+  .checked-checkbox {
+    top: 0;
+    left: 4px;
+    width: 5px;
+    height: 10px;
+    border-bottom: 2px solid white;
+    border-right: 2px solid white;
+    position: absolute;
+    transform: rotate(45deg);
+  }
+}
+
 mat-horizontal-stepper {
   .mat-step-header {
     .mat-step-icon {


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


[incubator-dlab] 03/03: [DLAB-1861]: Added check box to 'Environment management' page

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

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

commit 902342065ce8179493e43769a42d0247c44a6398
Author: Dmytro_Gnatyshyn <di...@ukr.net>
AuthorDate: Mon Jun 15 10:02:12 2020 +0300

    [DLAB-1861]: Added check box to 'Environment management' page
---
 .../management-grid/management-grid.component.html |  23 ++++-
 .../management-grid/management-grid.component.scss |   8 +-
 .../management-grid/management-grid.component.ts   | 105 +++++++++++++++++++--
 .../management/management.component.html           |   2 +-
 .../management/management.component.ts             |  91 ++++++++++++------
 .../resources/webapp/src/assets/styles/_theme.scss |  21 ++++-
 6 files changed, 206 insertions(+), 44 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
index a7f217a..88b005c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
@@ -21,7 +21,16 @@
   <table mat-table [dataSource]="allFilteredEnvironmentData" class="data-grid management mat-elevation-z6">
     <ng-container matColumnDef="checkbox">
       <th mat-header-cell *matHeaderCellDef class="checkbox label-header">
-     </th>
+        <div  class="empty-checkbox header-checkbox" [ngClass]="{'checked': selected?.length === allActiveNotebooks?.length}" (click)="toggleSelectionAll();$event.stopPropagation()" >
+          <span class="checked-checkbox" *ngIf="selected?.length === allActiveNotebooks?.length"></span>
+        </div>
+        <button mat-icon-button aria-label="More" class="ar checkbox-border" (click)="toggleFilterRow()">
+          <i class="material-icons">
+<!--            <span *ngIf="filtering && filterForm.users.length > 0 && !collapsedFilterRow">filter_list</span>-->
+            <span>more_vert</span>
+          </i>
+        </button>
+      </th>
       <td mat-cell *matCellDef="let element">
         <div *ngIf="element.type !== 'edge node' && (element.status==='running' || element.status==='stopped')" class="empty-checkbox" [ngClass]="{'checked': element.isSelected}" (click)="toggleActionForAll(element);$event.stopPropagation()" >
           <span class="checked-checkbox" *ngIf="element.isSelected"></span>
@@ -147,10 +156,14 @@
         <span class="label"> Actions </span>
       </th>
       <td mat-cell *matCellDef="let element" class="settings actions-col">
-        <span #settings class="actions" (click)="actions.toggle($event, settings)" *ngIf="element.type !== 'edge node'"
-          [ngClass]="{
-            'disabled' : isActiveResources(element),
-            'disabled' : element.status !== 'running' && element.status !== 'stopped' && element.status !== 'stopping' && element.status !== 'failed' }"></span>
+        <span [ngClass]="{'not-allow' : selected?.length}">
+          <span #settings class="actions" (click)="actions.toggle($event, settings)" *ngIf="element.type !== 'edge node'"
+            [ngClass]="{
+              'disabled' : isActiveResources(element),
+              'disabled' : (element.status !== 'running' && element.status !== 'stopped' && element.status !== 'stopping' && element.status !== 'failed') || selected?.length}">
+
+          </span>
+        </span>
         <bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
           <ul class="list-unstyled">
             <li
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.scss
index 14b700e..99fde37 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.scss
@@ -22,6 +22,12 @@
     .mat-column-checkbox{
       padding-left: 10px;
       padding-right: 10px;
+      &.label-header{
+        width: 65px;
+        display: flex;
+        align-items: center;
+      }
+
     }
     .user{
       width: 15%;
@@ -48,7 +54,7 @@
     }
 
     .resources {
-      width: 22%;
+      width: 21%;
       padding: 5px;
     }
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
index b0295e2..38e4590 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
@@ -65,6 +65,7 @@ export class ManagementGridComponent implements OnInit {
   displayedColumns: string[] = [ 'checkbox', 'user', 'type', 'project', 'shape', 'status', 'resources', 'actions'];
   displayedFilterColumns: string[] = ['checkbox-filter', 'user-filter', 'type-filter', 'project-filter', 'shape-filter', 'status-filter', 'resource-filter', 'actions-filter'];
   private selected;
+  private allActiveNotebooks: any;
 
   constructor(
     private healthStatusService: HealthStatusService,
@@ -125,8 +126,8 @@ export class ManagementGridComponent implements OnInit {
       filteredData = filteredData.filter(item => {
 
         const isUser = config.users.length > 0 ? (config.users.indexOf(item.user) !== -1) : true;
-        const isTypeName = item.name ?
-          item.name.toLowerCase().indexOf(config.type.toLowerCase()) !== -1 : item.type.toLowerCase().indexOf(config.type.toLowerCase()) !== -1;
+        const isTypeName = item.name ? item.name.toLowerCase()
+          .indexOf(config.type.toLowerCase()) !== -1 : item.type.toLowerCase().indexOf(config.type.toLowerCase()) !== -1;
         const isStatus = config.statuses.length > 0 ? (config.statuses.indexOf(item.status) !== -1) : (config.type !== 'active');
         const isShape = config.shapes.length > 0 ? (config.shapes.indexOf(item.shape) !== -1) : true;
         const isProject = config.projects.length > 0 ? (config.projects.indexOf(item.project) !== -1) : true;
@@ -146,6 +147,7 @@ export class ManagementGridComponent implements OnInit {
       });
     }
     this.allFilteredEnvironmentData = filteredData;
+    this.allActiveNotebooks = this.allFilteredEnvironmentData.filter(v => v.name && (v.status === 'running' || v.status === 'stopped'));
   }
 
   getEnvironmentDataCopy() {
@@ -153,7 +155,7 @@ export class ManagementGridComponent implements OnInit {
   }
 
   toggleResourceAction(environment: any, action: string, resource?): void {
-    this.actionToggle.emit({ action, environment, resource });
+    this.actionToggle.emit({ environment, action, resource });
   }
 
   isResourcesInProgress(notebook) {
@@ -215,8 +217,17 @@ export class ManagementGridComponent implements OnInit {
   toggleActionForAll(element) {
     element.isSelected = !element.isSelected;
     this.selected = this.allFilteredEnvironmentData.filter(item => !!item.isSelected);
-    console.log(this.selected);
-    this.emitSelectedList.emit(this.selected)
+    this.emitSelectedList.emit(this.selected);
+  }
+
+  toggleSelectionAll() {
+    if (this.selected && this.selected.length === this.allActiveNotebooks.length) {
+      this.allActiveNotebooks.forEach(notebook => notebook.isSelected = false);
+    } else {
+      this.allActiveNotebooks.forEach(notebook => notebook.isSelected = true);
+    }
+    this.selected = this.allFilteredEnvironmentData.filter(item => !!item.isSelected);
+    this.emitSelectedList.emit(this.selected);
   }
 }
 
@@ -229,23 +240,101 @@ export class ManagementGridComponent implements OnInit {
     <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
   </div>
   <div mat-dialog-content class="content">
+    <div *ngIf="data.type === 'cluster'">
       <p>Resource <span class="strong"> {{ data.resource_name }}</span> of user <span class="strong"> {{ data.user }} </span> will be
       <span *ngIf="data.action === 'terminate'"> decommissioned.</span>
       <span *ngIf="data.action === 'stop'">stopped.</span>
     </p>
-    <p class="m-top-20"><span class="strong">Do you want to proceed?</span></p>
+    </div>
+    <div class="resource-list" *ngIf="data.type === 'notebook'">
+      <div class="resource-list-header">
+        <div class="resource-name">Notebook</div>
+        <div class="clusters-list">
+          <div class="clusters-list-item">
+            <div class="cluster">Cluster</div>
+            <div class="status">Further status</div>
+          </div>
+        </div>
+
+      </div>
+      <div class="scrolling-content resource-heigth">
+        <div class="resource-list-row sans node" *ngFor="let notebook of notebooks">
+          <div class="resource-name ellipsis">
+            {{notebook.name}}
+          </div>
+
+          <div class="clusters-list">
+            <div class="clusters-list-item">
+              <div class="cluster"></div>
+              <div class="status"
+                   [ngClass]="{
+                   'stopped': data.action==='stop', 'terminated': data.action === 'terminate'
+                    }"
+              >
+                {{data.action  === 'stop' ? 'Stopped' : 'Terminated'}}
+              </div>
+            </div>
+            <div class="clusters-list-item" *ngFor="let cluster of notebook?.resources">
+              <div class="cluster">{{cluster.computational_name}}</div>
+              <div class="status" [ngClass]="{
+              'stopped': (data.action==='stop' && cluster.image==='docker.dlab-dataengine'), 'terminated': data.action === 'terminate' || (data.action==='stop' && cluster.image!=='docker.dlab-dataengine')
+              }">{{data.action  === 'stop' && cluster.image === "docker.dlab-dataengine" ? 'Stopped' : 'Terminated'}}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div class="text-center ">
+    <p class="strong">Do you want to proceed?</p>
   </div>
-  <div class="text-center">
+  <div class="text-center m-top-20">
     <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; margin: 0; }
+      .info { color: #35afd5; }
+      .info .confirm-dialog { color: #607D8B; }
+      header { display: flex; justify-content: space-between; color: #607D8B; }
+      header h4 i { vertical-align: bottom; }
+      header a i { font-size: 20px; }
+      header a:hover i { color: #35afd5; cursor: pointer; }
+      .plur { font-style: normal; }
+      .scrolling-content{overflow-y: auto; max-height: 200px; }
+      .cluster { width: 50%; text-align: left; color: #577289;}
+      .status { width: 50%;text-align: left;}
+      .label { font-size: 15px; font-weight: 500; font-family: "Open Sans",sans-serif;}
+      .node { font-weight: 300;}
+      .resource-name { width: 40%;text-align: left; padding: 10px 0;line-height: 26px;}
+      .clusters-list { width: 60%;text-align: left; padding: 10px 0;line-height: 26px;}
+      .clusters-list-item { width: 100%;text-align: left;display: flex}
+      .resource-list{max-width: 100%; margin: 0 auto;margin-top: 20px; }
+      .resource-list-header{display: flex; font-weight: 600; font-size: 16px;height: 48px; border-top: 1px solid #edf1f5; border-bottom: 1px solid #edf1f5; padding: 0 20px;}
+      .resource-list-row{display: flex; border-bottom: 1px solid #edf1f5;padding: 0 20px;}
+      .confirm-resource-terminating{text-align: left; padding: 10px 20px;}
+      .confirm-message{color: #ef5c4b;font-size: 13px;min-height: 18px; text-align: center; padding-top: 20px}
+      .checkbox{margin-right: 5px;vertical-align: middle; margin-bottom: 3px;}
+      label{cursor: pointer}
+      .bottom-message{padding-top: 15px;}
+      .table-header{padding-bottom: 10px;}`
   ]
 })
+
 export class ReconfirmationDialogComponent {
+  private notebooks;
   constructor(
     public dialogRef: MatDialogRef<ReconfirmationDialogComponent>,
     @Inject(MAT_DIALOG_DATA) public data: any
-  ) { }
+  ) {
+    if (data.notebooks && data.notebooks.length) {
+      this.notebooks = JSON.parse(JSON.stringify(data.notebooks));
+      this.notebooks = this.notebooks.map(notebook => {
+        notebook.resources = notebook.resources.filter(res => res.status !== 'terminated' && res.status.slice(0, 4) !== data.action);
+        return notebook;
+      });
+    }
+  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
index 2509429..eeb2d9b 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
@@ -20,7 +20,7 @@
 <div class="base-retreat">
   <div class="sub-nav">
     <div *ngIf="healthStatus?.admin" class="admin-group">
-      <div class="action-wrapper admin-group" >
+      <div class="action-select-wrapper admin-group" >
         <span class="action-button-wrapper">
           <button
             type="button" class="butt actions-btn"
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
index 2c3813a..3062a07 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-import { Component, OnInit } from '@angular/core';
+import {Component, OnInit, ViewChild} from '@angular/core';
 import { MatDialog } from '@angular/material/dialog';
 import { ToastrService } from 'ngx-toastr';
 
@@ -40,7 +40,8 @@ import { ExploratoryModel } from '../../resources/resources-grid/resources-grid.
 import { EnvironmentsDataService } from './management-data.service';
 import { ProjectService } from '../../core/services';
 import {ConfirmationDialogComponent, ConfirmationDialogType} from '../../shared/modal-dialog/confirmation-dialog';
-import {ReconfirmationDialogComponent} from './management-grid/management-grid.component';
+import {ManagementGridComponent, ReconfirmationDialogComponent} from './management-grid/management-grid.component';
+import {FolderTreeComponent} from '../../resources/bucket-browser/folder-tree/folder-tree.component';
 
 @Component({
   selector: 'environments-management',
@@ -57,6 +58,9 @@ export class ManagementComponent implements OnInit {
   public selectedRunning: any[];
   public selectedStopped: any[];
 
+  @ViewChild(ManagementGridComponent, {static: true}) managementGrid;
+
+
   constructor(
     public toastr: ToastrService,
     public dialog: MatDialog,
@@ -186,8 +190,6 @@ export class ManagementComponent implements OnInit {
 
     this.selectedRunning = this.selected.filter(item => item.status === 'running');
     this.selectedStopped = this.selected.filter(item => item.status === 'stopped');
-
-    console.log(this.selectedRunning.length, this.selectedStopped.length);
   }
 
   public toogleActions() {
@@ -199,40 +201,75 @@ export class ManagementComponent implements OnInit {
     if (resource) {
       const resource_name = resource ? resource.computational_name : environment.name;
       this.dialog.open(ReconfirmationDialogComponent, {
-        data: { action, resource_name, user: environment.user },
+        data: { action, resource_name, user: environment.user, type: 'cluster'},
         width: '550px', panelClass: 'error-modalbox'
       }).afterClosed().subscribe(result => {
         result && this.manageEnvironmentAction({ action, environment, resource });
       });
     } else {
-      const type = (environment.type.toLowerCase() === 'edge node')
-        ? ConfirmationDialogType.StopEdgeNode : ConfirmationDialogType.StopExploratory;
-
+      const notebooks = this.selected.length ? this.selected : [environment];
       if (action === 'stop') {
-        this.dialog.open(ConfirmationDialogComponent, {
-          data: { notebook: environment, type: type, manageAction: true }, panelClass: 'modal-md'
-        }).afterClosed().subscribe(() => this.buildGrid());
+        this.dialog.open(ReconfirmationDialogComponent, {
+          data: { notebooks: notebooks, type: 'notebook', action },
+          width: '550px', panelClass: 'error-modalbox'
+        }).afterClosed().subscribe((res) => {
+          if (res) {
+            notebooks.forEach((env) => {
+              this.manageEnvironmentsService.environmentManagement(env.user, 'stop', env.project, env.name)
+                .subscribe(
+                  response => {
+                    console.log(response);
+                    this.buildGrid();
+                  },
+                  error => console.log(error)
+                );
+            });
+          }
+          this.clearSelection();
+        });
       } else if (action === 'terminate') {
-        this.dialog.open(ConfirmationDialogComponent, {
-          data: { notebook: environment, type: ConfirmationDialogType.TerminateExploratory, manageAction: true }, panelClass: 'modal-md'
-        }).afterClosed().subscribe(() => this.buildGrid());
-      } else if (action === 'run') {
-        this.healthStatusService.runEdgeNode().subscribe(() => {
-          this.buildGrid();
-          this.toastr.success('Edge node is starting!', 'Processing!');
-        }, () => this.toastr.error('Edge Node running failed!', 'Oops!'));
-      } else if (action === 'recreate') {
-        this.healthStatusService.recreateEdgeNode().subscribe(() => {
-          this.buildGrid();
-          this.toastr.success('Edge Node recreation is processing!', 'Processing!');
-        }, () => this.toastr.error('Edge Node recreation failed!', 'Oops!'));
+        this.dialog.open(ReconfirmationDialogComponent, {
+          data: { notebooks: notebooks, type: 'notebook', action }, width: '550px', panelClass: 'error-modalbox'
+        }).afterClosed().subscribe((res) => {
+          if (res) {
+            notebooks.forEach((env) => {
+              this.manageEnvironmentsService.environmentManagement(env.user, 'terminate', env.project, env.name)
+                .subscribe(
+                  response => {
+                    this.buildGrid();
+
+                  },
+                  error => console.log(error)
+                );
+            });
+          }
+          this.clearSelection();
+        });
+      // } else if (action === 'run') {
+      //   this.healthStatusService.runEdgeNode().subscribe(() => {
+      //     this.buildGrid();
+      //     this.toastr.success('Edge node is starting!', 'Processing!');
+      //   }, () => this.toastr.error('Edge Node running failed!', 'Oops!'));
+      // } else if (action === 'recreate') {
+      //   this.healthStatusService.recreateEdgeNode().subscribe(() => {
+      //     this.buildGrid();
+      //     this.toastr.success('Edge Node recreation is processing!', 'Processing!');
+      //   }, () => this.toastr.error('Edge Node recreation failed!', 'Oops!'));
       }
     }
   }
 
+  private clearSelection() {
+    this.selected = [];
+    this.isActionsOpen = false;
+    if (this.managementGrid.selected && this.managementGrid.selected.length !== 0) {
+      this.managementGrid.selected.forEach(item => item.isSelected = false);
+      this.managementGrid.selected = [];
+    }
+  }
+
+
   public resourseAction(action) {
-    this.selected.forEach(resource => {
-      this.toggleResourceAction({environment: resource, action: action});
-    })
+      this.toggleResourceAction({environment: this.selected, action: action});
   }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss b/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
index 9c9963f..bf3529d 100644
--- a/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
+++ b/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
@@ -458,7 +458,7 @@ span.mat-slide-toggle-content {
   }
 }
 
-.action-wrapper{
+.action-select-wrapper{
   position: relative;
   display: block !important;
 
@@ -469,10 +469,14 @@ span.mat-slide-toggle-content {
 
   .mat-raised-button.butt{
     margin-bottom: 0;
+    padding-left: 45px;
+    text-align: left;
+
 
     &.actions-btn{
       padding-right: 38px;
 
+
       .material-icons{
         transition: ease-in-out 1s;
         font-size: 25px;
@@ -504,6 +508,19 @@ span.mat-slide-toggle-content {
       position: relative;
       overflow: hidden;
       line-height: 36px;
+      padding-left: 45px;
+      text-align: left;
+      &.action-menu-item{
+        &:hover{
+          color:  #00bcd4;
+          background-color: #fafafa;
+        }
+        &.disabled{
+          &:hover{
+            color: #577289;
+          }
+        }
+      }
     }
   }
 }
@@ -636,7 +653,7 @@ mat-horizontal-stepper {
 
     .content {
       color: #718ba6;
-      padding: 20px 0;
+      padding: 20px 40px;
       font-size: 14px;
       font-weight: 400;
       text-align: center;


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