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/06/19 12:56:13 UTC

[incubator-dlab] branch feature/projects updated (62e2b23 -> a825837)

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

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


    from 62e2b23  [DLAB-805]: clenup shapes Default Options settings
     new a072c13  [DLAB-805]: spot instance limits fixes
     new a9f5306  [DLAB-805]: clusters creation validation fixes
     new a825837  [DLAB-805]: clusters creation validation fixes

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.


Summary of changes:
 .../project-form/project-form.component.html       |  64 ++++---
 .../resources/webapp/src/app/core/util/patterns.ts |   4 +-
 ...utational-resource-create-dialog.component.html | 139 ++++++++-------
 ...mputational-resource-create-dialog.component.ts | 193 +++++++--------------
 .../resources-grid/resources-grid.component.html   |  88 +++++-----
 .../src/app/shared/navbar/navbar.component.html    |  33 ++--
 6 files changed, 233 insertions(+), 288 deletions(-)


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


[incubator-dlab] 01/03: [DLAB-805]: spot instance limits fixes

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

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

commit a072c13b02fd35ea3c3b3af6983f26dc47cd8f2c
Author: Andriana Kovalyshyn <kv...@kvellia-MBP.kyiv.epam.com>
AuthorDate: Wed Jun 19 14:48:48 2019 +0300

    [DLAB-805]: spot instance limits fixes
---
 ...utational-resource-create-dialog.component.html | 110 +++++++++++++--------
 ...mputational-resource-create-dialog.component.ts |  29 +++---
 2 files changed, 85 insertions(+), 54 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
index db45e21..f63602d 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
@@ -18,7 +18,7 @@
   -->
 
 <div class="create-cluster" id="dialog-box">
- <header class="dialog-header">
+  <header class="dialog-header">
     <h4 class="modal-title">Add computational resources</h4>
     <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
   </header>
@@ -26,10 +26,10 @@
     <div class="content-box mat-reset">
       <form [formGroup]="resourceForm" *ngIf="cluster_types.length && resourceForm; else empty">
 
-        <div class="form-wrapper" [ngClass]="{ compress: selectedImage.image === 'docker.dlab-dataengine' }">
+        <div class="form-wrapper" [ngClass]="{ compress: selectedImage?.image === 'docker.dlab-dataengine' }">
           <div class="col">
 
-      <!-- <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="model.resourceImages.length === 1">
+            <!-- <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="model.resourceImages.length === 1">
               <label class="label">Select cluster type</label>
               <div class="control">
                 <dropdown-list #clusterType (selectedItem)="onUpdate($event)"></dropdown-list>
@@ -49,8 +49,10 @@
                 <mat-form-field>
                   <mat-label>Select cluster type</mat-label>
                   <mat-select formControlName="template_name" disableOptionCentering>
-                    <mat-option *ngFor="let type of cluster_types" [value]="type.template_name" (click)="selectedImage = type">{{ type.template_name }}</mat-option>
-                    <mat-option *ngIf="!cluster_types.length" class="multiple-select ml-10" disabled>Clusters types list is empty</mat-option>
+                    <mat-option *ngFor="let type of cluster_types" [value]="type.template_name"
+                      (click)="selectImage(type)">{{ type.template_name }}</mat-option>
+                    <mat-option *ngIf="!cluster_types.length" class="multiple-select ml-10" disabled>Clusters types list
+                      is empty</mat-option>
                   </mat-select>
                   <button class="caret">
                     <i class="material-icons">keyboard_arrow_down</i>
@@ -65,8 +67,10 @@
                 <mat-form-field>
                   <mat-label>Select template</mat-label>
                   <mat-select formControlName="version" disableOptionCentering>
-                    <mat-option *ngFor="let template of selectedImage.templates" [value]="template.version">{{ template.version }}</mat-option>
-                    <mat-option *ngIf="!selectedImage.templates" class="multiple-select ml-10" disabled>Templates list is empty</mat-option>
+                    <mat-option *ngFor="let template of selectedImage.templates" [value]="template.version">
+                      {{ template.version }}</mat-option>
+                    <mat-option *ngIf="!selectedImage.templates" class="multiple-select ml-10" disabled>Templates list
+                      is empty</mat-option>
                   </mat-select>
                   <button class="caret">
                     <i class="material-icons">keyboard_arrow_down</i>
@@ -78,15 +82,20 @@
             <div class="control-group alias-name" *ngIf="selectedImage?.image">
               <label class="label">Cluster alias</label>
               <div class="control">
-                  <input [class.danger_field]="computationalResourceExist || !resourceForm?.controls['cluster_alias_name'].valid
+                <input
+                  [class.danger_field]="computationalResourceExist || !resourceForm?.controls['cluster_alias_name'].valid
                         && resourceForm?.controls['cluster_alias_name'].dirty && resourceForm?.controls['cluster_alias_name'].hasError('duplication')"
-                        type="text" class="form-control" placeholder="Enter cluster alias" formControlName="cluster_alias_name" />
-                  <span class="error" *ngIf="resourceForm?.controls['cluster_alias_name'].hasError('duplication')">This cluster name already exists.</span>
-                  <span class="error" *ngIf="!resourceForm?.controls.cluster_alias_name.valid
+                  type="text" class="form-control" placeholder="Enter cluster alias"
+                  formControlName="cluster_alias_name" />
+                <span class="error" *ngIf="resourceForm?.controls['cluster_alias_name'].hasError('duplication')">This
+                  cluster name already exists.</span>
+                <span class="error" *ngIf="!resourceForm?.controls.cluster_alias_name.valid
                                             && resourceForm?.controls['cluster_alias_name'].dirty
                                             && !resourceForm?.controls['cluster_alias_name'].hasError('duplication')">
-                    Cluster name <span *ngIf="DICTIONARY.cloud_provider !== 'aws'">cannot be longer than 10 characters and</span> can only contain letters, numbers, hyphens and '_' but can not end with special characters
-                  </span>
+                  Cluster name <span *ngIf="DICTIONARY.cloud_provider !== 'aws'">cannot be longer than 10 characters
+                    and</span> can only contain letters, numbers, hyphens and '_' but can not end with special
+                  characters
+                </span>
               </div>
             </div>
           </div>
@@ -96,9 +105,10 @@
               <label class="label">{{ DICTIONARY[selectedImage.image].instance_number }}</label>
               <div class="control">
                 <input type="number" class="form-control" min="{{minInstanceNumber}}" max="{{maxInstanceNumber}}"
-                      formControlName="instance_number" (keypress)="CheckUtils.isNumberKey($event)" />
+                  formControlName="instance_number" (keypress)="CheckUtils.isNumberKey($event)" />
                 <span class="error" *ngIf="!resourceForm?.controls.instance_number.valid">
-                  <span>Only integer values greater than or equal to {{ minInstanceNumber }} and less than {{ maxInstanceNumber }} are allowed</span>
+                  <span>Only integer values greater than or equal to {{ minInstanceNumber }} and less than
+                    {{ maxInstanceNumber }} are allowed</span>
                 </span>
               </div>
             </div>
@@ -122,7 +132,8 @@
                 <mat-form-field>
                   <mat-label>Select {{ DICTIONARY.notebook_instance_size }}</mat-label>
                   <mat-select formControlName="shape_master" disableOptionCentering>
-                    <mat-optgroup *ngFor="let item of (selectedImage.computation_resources_shapes | keys)" [label]="item.key | underscoreless">
+                    <mat-optgroup *ngFor="let item of (selectedImage.computation_resources_shapes | keys)"
+                      [label]="item.key | underscoreless">
                       <mat-option *ngFor="let list_item of item.value" [value]="list_item.Type">
                         <strong class="highlight icon-label">{{ list_item.Size }}</strong> {{ list_item.Type }}
                       </mat-option>
@@ -135,13 +146,15 @@
               </div>
             </div>
 
-            <div class="control-group" *ngIf="selectedImage?.image" [hidden]="selectedImage?.image === 'docker.dlab-dataengine'">
+            <div class="control-group" *ngIf="selectedImage?.image"
+              [hidden]="selectedImage?.image === 'docker.dlab-dataengine'">
               <label class="label">{{ DICTIONARY[selectedImage.image].data_engine_slave_instance_size }}</label>
               <div class="control selector-wrapper">
                 <mat-form-field>
                   <mat-label>Select {{ DICTIONARY.notebook_instance_size }}</mat-label>
                   <mat-select formControlName="shape_slave" disableOptionCentering>
-                    <mat-optgroup *ngFor="let item of (selectedImage.computation_resources_shapes | keys)" [label]="item.key | underscoreless">
+                    <mat-optgroup *ngFor="let item of (selectedImage.computation_resources_shapes | keys)"
+                      [label]="item.key | underscoreless">
                       <mat-option *ngFor="let list_item of item.value" [value]="list_item.Type">
                         <strong class="highlight icon-label">{{ list_item.Size }}</strong> {{ list_item.Type }}
                       </mat-option>
@@ -157,23 +170,22 @@
           </div>
         </div>
 
-        <div class="preemptible checkbox-group control-group m-top-30 m-bott-10" *ngIf="PROVIDER === 'gcp' && selectedImage?.image === 'docker.dlab-dataengine-service'">
+        <div class="preemptible checkbox-group control-group m-top-30 m-bott-10"
+          *ngIf="PROVIDER === 'gcp' && selectedImage?.image === 'docker.dlab-dataengine-service'">
           <label class="label">
             <input #preemptibleNode type="checkbox" (change)="selectPreemptibleNodes($event)" />
             <span>Preemptible node</span>
             <span class="align" *ngIf="preemptible?.nativeElement['checked'] || false"> count</span>
           </label>
-          <div *ngIf="preemptible?.nativeElement['checked']"
-                class="preemptible-details control"
-                [ngClass]="{ show: preemptible?.nativeElement['checked'] || false}">
-            <input type="text" class="form-control"
-              formControlName="preemptible_instance_number"
-              (keypress)="CheckUtils.isNumberKey($event)"
-              (keydown.arrowup)="preemptibleCounter($event, 'increment')"
+          <div *ngIf="preemptible?.nativeElement['checked']" class="preemptible-details control"
+            [ngClass]="{ show: preemptible?.nativeElement['checked'] || false}">
+            <input type="text" class="form-control" formControlName="preemptible_instance_number"
+              (keypress)="CheckUtils.isNumberKey($event)" (keydown.arrowup)="preemptibleCounter($event, 'increment')"
               (keydown.arrowdown)="preemptibleCounter($event, 'decrement')" />
             <span class="error" *ngIf="!resourceForm?.controls.preemptible_instance_number.valid">
               <span *ngIf="minPreemptibleInstanceNumber !== maxPreemptibleInstanceNumber; else equal">
-                Only integer values greater than or equal to {{ minPreemptibleInstanceNumber }} and less than {{ maxPreemptibleInstanceNumber }} are allowed
+                Only integer values greater than or equal to {{ minPreemptibleInstanceNumber }} and less than
+                {{ maxPreemptibleInstanceNumber }} are allowed
               </span>
               <ng-template #equal>Please manage total machines count</ng-template>
             </span>
@@ -181,54 +193,68 @@
         </div>
 
         <div class="checkbox-group control-group m-top-15" *ngIf="PROVIDER === 'aws'"
-            [hidden]="!selectedImage.templates.length">
+          [hidden]="!selectedImage.templates.length">
           <label class="spot-label label">
             <input #spotInstancesCheck type="checkbox" (change)="selectSpotInstances($event)" />
             <span>Spot instance</span>
             <span *ngIf="spotInstancesSelect?.nativeElement['checked'] || false"> bit, %</span>
           </label>
-          <div class="control spot-details" [ngClass]="{ show: spotInstancesSelect?.nativeElement['checked'] || false }" *ngIf="spotInstancesSelect?.nativeElement['checked'] || false">
-            <input type="number" class="form-control" step="5" min="{{minSpotPrice}}" max="{{maxSpotPrice}}" formControlName="instance_price" (keypress)="CheckUtils.isNumberKey($event)">
+          <div class="control spot-details" [ngClass]="{ show: spotInstancesSelect?.nativeElement['checked'] || false }"
+            *ngIf="spotInstancesSelect?.nativeElement['checked'] || false">
+            <input type="number" class="form-control" step="5" min="{{minSpotPrice}}" max="{{maxSpotPrice}}"
+              formControlName="instance_price" (keypress)="CheckUtils.isNumberKey($event)">
             <span class="error" *ngIf="!resourceForm?.controls.instance_price.valid">
               Only integer values greater than or equal to {{minSpotPrice}} and less than {{maxSpotPrice}} are allowed
             </span>
           </div>
-          <span class="info" *ngIf="spotInstancesSelect?.nativeElement['checked'] || false">When the current Spot price rises above your bid price, the Spot instance is reclaimed by AWS so that it can be given to another customer. Make sure to backup your data on periodic basis.</span>
+          <span class="info" *ngIf="spotInstancesSelect?.nativeElement['checked'] || false">When the current Spot price
+            rises above your bid price, the Spot instance is reclaimed by AWS so that it can be given to another
+            customer. Make sure to backup your data on periodic basis.</span>
         </div>
 
 
-        <div class="checkbox-group m-top-20" [hidden]="PROVIDER === 'gcp' && selectedImage?.image === 'docker.dlab-dataengine-service'"
-             *ngIf="notebook_instance?.image !== 'docker.dlab-zeppelin'">
+        <div class="checkbox-group m-top-20"
+          [hidden]="PROVIDER === 'gcp' && selectedImage?.image === 'docker.dlab-dataengine-service'"
+          *ngIf="notebook_instance?.image !== 'docker.dlab-zeppelin'">
           <label>
-            <input #configurationNode type="checkbox" (change)="selectConfiguration()"/> Cluster configurations
+            <input #configurationNode type="checkbox" (change)="selectConfiguration()" /> Cluster configurations
           </label>
           <div class="config-link" *ngIf="(configuration?.nativeElement['checked'] || false)
             && selectedImage?.image === 'docker.dlab-dataengine-service'
             && DICTIONARY.cloud_provider === 'aws'">
-            To view example JSON of configurations refer for <a href="https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-configure-apps.html" target="_blank">AWS official documentation</a>
+            To view example JSON of configurations refer for <a
+              href="https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-configure-apps.html" target="_blank">AWS
+              official documentation</a>
           </div>
         </div>
         <div class="checkbox-group">
           <div class="config-details" [ngClass]="{ show: configuration?.nativeElement['checked'] || false }">
-            <textarea formControlName="configuration_parameters" placeholder="Cluster configuration template, JSON" data-gramm_editor="false"></textarea>
-            <span class="error" *ngIf="!resourceForm?.controls.configuration_parameters.valid && resourceForm?.controls['configuration_parameters'].dirty">Configuration parameters is not in a valid format</span>
+            <textarea formControlName="configuration_parameters" placeholder="Cluster configuration template, JSON"
+              data-gramm_editor="false"></textarea>
+            <span class="error"
+              *ngIf="!resourceForm?.controls.configuration_parameters.valid && resourceForm?.controls['configuration_parameters'].dirty">Configuration
+              parameters is not in a valid format</span>
           </div>
         </div>
         <div *ngIf="notebook_instance?.image === 'docker.dlab-zeppelin'">
-          <small>Spark default configuration for Apache Zeppelin can not be changed from DLab UI.  Currently it can be done directly through Apache Zeppelin interpreter menu.
-            For more details please refer for Apache Zeppelin <a href="https://zeppelin.apache.org/docs/0.8.0/usage/interpreter/overview.html" target="_blank">official documentation</a>.
+          <small>Spark default configuration for Apache Zeppelin can not be changed from DLab UI. Currently it can be
+            done directly through Apache Zeppelin interpreter menu.
+            For more details please refer for Apache Zeppelin <a
+              href="https://zeppelin.apache.org/docs/0.8.0/usage/interpreter/overview.html" target="_blank">official
+              documentation</a>.
           </small>
         </div>
         <div class="text-center m-top-30">
           <button mat-raised-button type="button" (click)="dialogRef.close()" class="butt action">Cancel</button>
           <button mat-raised-button type="button" [disabled]="!resourceForm?.valid"
-                  (click)="createComputationalResource(resourceForm.value)"
-                  class="butt butt-success action" [ngClass]="{'not-allowed': !resourceForm?.valid}">Create</button>
+            (click)="createComputationalResource(resourceForm.value)" class="butt butt-success action"
+            [ngClass]="{'not-allowed': !resourceForm?.valid}">Create</button>
         </div>
       </form>
 
       <ng-template #empty>
-        <div class="info message">Computational resource creations are not available.<br>Please, check your permissions.</div>
+        <div class="info message">Computational resource creations are not available.<br>Please, check your permissions.
+        </div>
       </ng-template>
     </div>
   </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
index 7a96dc8..b7b77fe 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
@@ -62,10 +62,10 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
   public maxSpotPrice: number = 0;
   public resourceForm: FormGroup;
 
-  @ViewChild('name') name;
-  @ViewChild('templatesList') templates_list;
-  @ViewChild('masterShapesList') master_shapes_list;
-  @ViewChild('shapesSlaveList') slave_shapes_list;
+  // @ViewChild('name') name;
+  // @ViewChild('templatesList') templates_list;
+  // @ViewChild('masterShapesList') master_shapes_list;
+  // @ViewChild('shapesSlaveList') slave_shapes_list;
   @ViewChild('spotInstancesCheck') spotInstancesSelect;
   @ViewChild('preemptibleNode') preemptible;
   @ViewChild('configurationNode') configuration;
@@ -158,6 +158,11 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
     if (DICTIONARY.cloud_provider === 'aws') this.spotInstancesSelect.nativeElement['checked'];
   }
 
+  public selectImage($event) {
+    this.selectedImage = $event;
+    this.getComputationalResourceLimits();
+  }
+
   public selectPreemptibleNodes($event) {
     if ($event.target.checked)
       this.resourceForm.controls['preemptible_instance_number'].setValue(this.minPreemptibleInstanceNumber);
@@ -177,10 +182,10 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
   private filterAvailableSpots() {
     const filtered = JSON.parse(JSON.stringify(this.selectedImage.computation_resources_shapes));
     for (const item in this.selectedImage.computation_resources_shapes) {
-        filtered[item] = filtered[item].filter(el => el.spot);
-        if (filtered[item].length <= 0) {
-          delete filtered[item];
-        }
+      filtered[item] = filtered[item].filter(el => el.spot);
+      if (filtered[item].length <= 0) {
+        delete filtered[item];
+      }
     }
     return filtered;
   }
@@ -207,7 +212,7 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
       shape_master: ['', Validators.required],
       shape_slave: [''],
       cluster_alias_name: ['', [Validators.required, Validators.pattern(this.clusterNamePattern),
-                                this.providerMaxLength, this.checkDuplication.bind(this)]],
+      this.providerMaxLength, this.checkDuplication.bind(this)]],
       instance_number: ['', [Validators.required, Validators.pattern(this.nodeCountPattern), this.validInstanceNumberRange.bind(this)]],
       preemptible_instance_number: [0, Validators.compose([Validators.pattern(this.integerRegex), this.validPreemptibleRange.bind(this)])],
       instance_price: [0, [this.validInstanceSpotRange.bind(this)]],
@@ -324,10 +329,10 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
     if (this.notebook_instance.template_name.toLowerCase().indexOf('tensorflow') !== -1
       || this.notebook_instance.template_name.toLowerCase().indexOf('deep learning') !== -1) {
       const allowed: any = ['GPU optimized'];
-      const filtered = Object.keys(this.selectedImage.shapes.resourcesShapeTypes)
+      const filtered = Object.keys(this.selectedImage.computation_resources_shapes)
         .filter(key => allowed.includes(key))
         .reduce((obj, key) => {
-          obj[key] = this.selectedImage.shapes.resourcesShapeTypes[key];
+          obj[key] = this.selectedImage.computation_resources_shapes[key];
           return obj;
         }, {});
 
@@ -336,7 +341,7 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
         this.cluster_types = images;
         // (images.length > 0) ? this.model.setSelectedClusterType(0) : this.model.availableTemplates = false;
       }
-      this.selectedImage.shapes.resourcesShapeTypes = filtered;
+      this.selectedImage.computation_resources_shapes = filtered;
     }
   }
 


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


[incubator-dlab] 02/03: [DLAB-805]: clusters creation validation fixes

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

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

commit a9f53065ea18a0f0b5b51d76f0af1c7f94ecc091
Author: Andriana Kovalyshyn <An...@epam.com>
AuthorDate: Wed Jun 19 15:54:22 2019 +0300

    [DLAB-805]: clusters creation validation fixes
---
 .../project-form/project-form.component.html       | 64 +++++++++++++---------
 .../resources/webapp/src/app/core/util/patterns.ts |  4 +-
 .../src/app/shared/navbar/navbar.component.html    | 33 ++++-------
 3 files changed, 52 insertions(+), 49 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.html
index 92c003e..f16e70b 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.html
@@ -20,6 +20,10 @@
 <form [formGroup]="projectForm" novalidate>
   <mat-horizontal-stepper #stepper class="stepper ani">
     <mat-step>
+      <ng-template matStepLabel>Key upload</ng-template>
+      KEY UPLOAD
+    </mat-step>
+    <mat-step>
       <ng-template matStepLabel>Project</ng-template>
       <section class="inner-step mat-reset">
 
@@ -30,41 +34,45 @@
               <div class="control">
                 <input type="text" formControlName="name" placeholder="Enter project name"
                   (blur)="generateProjectTag($event)" [ngClass]="{ 'not-allowed' : item }">
-                <span class="error" *ngIf="projectForm?.controls.name.hasError('duplication')">This project name already exists.</span>
+                <span class="error" *ngIf="projectForm?.controls.name.hasError('duplication')">This project name already
+                  exists.</span>
                 <span class="error" *ngIf="!projectForm?.controls.name.valid
                   && !projectForm?.controls.name.hasError('duplication')
-                  && projectForm?.controls.name.dirty">Project name can only contain letters, numbers, hyphens and '_' but can not end with special characters
+                  && projectForm?.controls.name.dirty">Project name can only contain letters, numbers, hyphens and '_'
+                  but can not end with special characters
                 </span>
               </div>
             </div>
             <div class="control-group">
               <label class="label">Project tag</label>
               <div class="control">
-                <input type="text" formControlName="tag" placeholder="dlab-{ project name }" [ngClass]="{ 'not-allowed' : item }">
+                <input type="text" formControlName="tag" placeholder="dlab-{ project name }"
+                  [ngClass]="{ 'not-allowed' : item }">
               </div>
             </div>
             <div class="control-group">
-                <div class="selector-wrapper">
-                  <mat-form-field [ngClass]="{ 'not-allowed' : item }">
-                    <mat-select multiple formControlName="endpoints" placeholder="Select endpoints">
-                      <mat-option class="multiple-select" disabled>
-                        <a class="select ani" (click)="selectOptions(endpointsList, 'endpoints', 'all')">
-                          <i class="material-icons">playlist_add_check</i>&nbsp;All
-                        </a>
-                        <a class="deselect ani" (click)="selectOptions(endpointsList, 'endpoints')">
-                          <i class="material-icons">clear</i>&nbsp;None
-                        </a>
-                      </mat-option>
-                      <mat-option *ngFor="let endpoint of endpointsList" [value]="endpoint.name">
-                        {{ endpoint.name }}
-                      </mat-option>
-                      <mat-option *ngIf="!endpointsList.length" class="multiple-select empty ml-10" disabled>Endpoints list is empty</mat-option>
-                    </mat-select>
-                    <button class="caret">
-                      <i class="material-icons">keyboard_arrow_down</i>
-                    </button>
-                  </mat-form-field>
-                </div>
+              <div class="selector-wrapper">
+                <mat-form-field [ngClass]="{ 'not-allowed' : item }">
+                  <mat-select multiple formControlName="endpoints" placeholder="Select endpoints">
+                    <mat-option class="multiple-select" disabled>
+                      <a class="select ani" (click)="selectOptions(endpointsList, 'endpoints', 'all')">
+                        <i class="material-icons">playlist_add_check</i>&nbsp;All
+                      </a>
+                      <a class="deselect ani" (click)="selectOptions(endpointsList, 'endpoints')">
+                        <i class="material-icons">clear</i>&nbsp;None
+                      </a>
+                    </mat-option>
+                    <mat-option *ngFor="let endpoint of endpointsList" [value]="endpoint.name">
+                      {{ endpoint.name }}
+                    </mat-option>
+                    <mat-option *ngIf="!endpointsList.length" class="multiple-select empty ml-10" disabled>Endpoints
+                      list is empty</mat-option>
+                  </mat-select>
+                  <button class="caret">
+                    <i class="material-icons">keyboard_arrow_down</i>
+                  </button>
+                </mat-form-field>
+              </div>
             </div>
           </div>
 
@@ -96,7 +104,8 @@
                   <mat-option *ngFor="let group of groupsList" [value]="group">
                     {{ group }}
                   </mat-option>
-                  <mat-option *ngIf="!groupsList.length" class="multiple-select ml-10" disabled>Groups list is empty</mat-option>
+                  <mat-option *ngIf="!groupsList.length" class="multiple-select ml-10" disabled>Groups list is empty
+                  </mat-option>
                 </mat-select>
                 <button class="caret">
                   <i class="material-icons">keyboard_arrow_down</i>
@@ -110,11 +119,12 @@
                 class="material-icons">keyboard_arrow_left</i>Back</button>
             <button mat-raised-button type="button" class="butt butt-success" [disabled]="!projectForm.valid"
               (click)="confirm(projectForm.value)">
-              <span *ngIf="item; else update">Update</span><ng-template #update>Create</ng-template>
+              <span *ngIf="item; else update">Update</span>
+              <ng-template #update>Create</ng-template>
             </button>
           </div>
         </div>
       </div>
     </mat-step>
   </mat-horizontal-stepper>
-</form>
\ No newline at end of file
+</form>
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/patterns.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/patterns.ts
index 65996ea..c99ac09 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/patterns.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/patterns.ts
@@ -20,5 +20,7 @@
 export const PATTERNS = {
   namePattern: '[-_a-zA-Z0-9]*[_-]*[a-zA-Z0-9]+',
   delimitersRegex: '/[-_]?/g',
-  url: '[-_a-zA-Z0-9/:.#!*();:@&=+$,/?#[]]*[_-]*[a-zA-Z0-9]+'
+  url: '[-_a-zA-Z0-9/:.#!*();:@&=+$,/?#[]]*[_-]*[a-zA-Z0-9]+',
+  nodeCountPattern: '^[1-9]\\d*$',
+  integerRegex: '^[0-9]*$'
 }
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 a123015..b7eec53 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
@@ -69,9 +69,7 @@
   <mat-sidenav #drawer mode="side" opened role="navigation" [style.width]="isExpanded ? '220px' : '60px'">
     <mat-nav-list>
       <nav>
-        <a class="nav-item" 
-          [routerLink]="['/resources_list']"
-          [routerLinkActive]="['active']"
+        <a class="nav-item" [routerLink]="['/resources_list']" [routerLinkActive]="['active']"
           [routerLinkActiveOptions]="{exact:true}">
           <span *ngIf="isExpanded; else resources">List of Resources</span>
           <ng-template #resources><i class="material-icons">dashboard</i></ng-template>
@@ -79,32 +77,25 @@
         <a class="nav-item has-children" *ngIf="healthStatus?.admin">
           <span *ngIf="isExpanded">Administration</span>
 
-          <a class="sub-nav-item" [style.margin-left.px]="isExpanded ? '30' : '0'"
-             [routerLink]="['/roles']"
-             [routerLinkActive]="['active']"
-             [routerLinkActiveOptions]="{exact:true}">
-             <span *ngIf="isExpanded; else roles">Roles</span>
-             <ng-template #roles><i class="material-icons">account_box</i></ng-template>
+          <a class="sub-nav-item" [style.margin-left.px]="isExpanded ? '30' : '0'" [routerLink]="['/roles']"
+            [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">
+            <span *ngIf="isExpanded; else roles">Roles</span>
+            <ng-template #roles><i class="material-icons">account_box</i></ng-template>
           </a>
-          <a class="sub-nav-item" [style.margin-left.px]="isExpanded ? '30' : '0'"
-             [routerLink]="['/projects']"
-             [routerLinkActive]="['active']"
-             [routerLinkActiveOptions]="{exact:true}">
-             <span *ngIf="isExpanded; else projects">Projects</span>
-             <ng-template #projects><i class="material-icons">dns</i></ng-template>
+          <a class="sub-nav-item" [style.margin-left.px]="isExpanded ? '30' : '0'" [routerLink]="['/projects']"
+            [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">
+            <span *ngIf="isExpanded; else projects">Projects</span>
+            <ng-template #projects><i class="material-icons">dns</i></ng-template>
           </a>
           <a class="sub-nav-item" [style.margin-left.px]="isExpanded ? '30' : '0'"
-            [routerLink]="['/environment_management']"
-            [routerLinkActive]="['active']"
+            [routerLink]="['/environment_management']" [routerLinkActive]="['active']"
             [routerLinkActiveOptions]="{exact:true}">
             <span *ngIf="isExpanded; else env">Environment Management</span>
             <ng-template #env><i class="material-icons">settings</i></ng-template>
           </a>
         </a>
-        <a *ngIf="healthStatus?.billingEnabled" class="nav-item"
-          [routerLink]="['/billing_report']"
-          [routerLinkActive]="['active']"
-          [routerLinkActiveOptions]="{exact:true}">
+        <a *ngIf="healthStatus?.billingEnabled" class="nav-item" [routerLink]="['/billing_report']"
+          [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">
           <span *ngIf="isExpanded; else billing">Billing Report</span>
           <ng-template #billing><i class="material-icons">account_balance_wallet</i></ng-template>
         </a>


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


[incubator-dlab] 03/03: [DLAB-805]: clusters creation validation fixes

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

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

commit a825837a397303dc7ae0e69f58ba605b6dbdc27f
Author: Andriana Kovalyshyn <An...@epam.com>
AuthorDate: Wed Jun 19 15:55:58 2019 +0300

    [DLAB-805]: clusters creation validation fixes
---
 ...utational-resource-create-dialog.component.html |  35 +---
 ...mputational-resource-create-dialog.component.ts | 190 +++++++--------------
 .../resources-grid/resources-grid.component.html   |  88 +++++-----
 3 files changed, 112 insertions(+), 201 deletions(-)

diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
index f63602d..627b7de 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
@@ -24,34 +24,20 @@
   </header>
   <div class="dialog-content selection">
     <div class="content-box mat-reset">
-      <form [formGroup]="resourceForm" *ngIf="cluster_types.length && resourceForm; else empty">
+      <form [formGroup]="resourceForm" *ngIf="clusterTypes.length && resourceForm; else empty">
 
         <div class="form-wrapper" [ngClass]="{ compress: selectedImage?.image === 'docker.dlab-dataengine' }">
           <div class="col">
 
-            <!-- <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="model.resourceImages.length === 1">
-              <label class="label">Select cluster type</label>
-              <div class="control">
-                <dropdown-list #clusterType (selectedItem)="onUpdate($event)"></dropdown-list>
-              </div>
-            </div> 
-
-            <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="!selectedImage.templates.length">
-              <label class="label">Select template</label>
-              <div class="control">
-                <dropdown-list #templatesList (selectedItem)="onUpdate($event)"></dropdown-list>
-              </div>
-            </div> -->
-
-            <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="cluster_types.length === 1">
+            <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="clusterTypes.length === 1">
               <label class="label">Select cluster type</label>
               <div class="control selector-wrapper">
                 <mat-form-field>
                   <mat-label>Select cluster type</mat-label>
                   <mat-select formControlName="template_name" disableOptionCentering>
-                    <mat-option *ngFor="let type of cluster_types" [value]="type.template_name"
+                    <mat-option *ngFor="let type of clusterTypes" [value]="type.template_name"
                       (click)="selectImage(type)">{{ type.template_name }}</mat-option>
-                    <mat-option *ngIf="!cluster_types.length" class="multiple-select ml-10" disabled>Clusters types list
+                    <mat-option *ngIf="!clusterTypes.length" class="multiple-select ml-10" disabled>Clusters types list
                       is empty</mat-option>
                   </mat-select>
                   <button class="caret">
@@ -112,19 +98,6 @@
                 </span>
               </div>
             </div>
-            <!-- <div class="control-group" *ngIf="selectedImage?.image">
-              <label class="label" *ngIf="selectedImage">{{ DICTIONARY[selectedImage.image].data_engine_master_instance_size }}</label>
-              <div class="control">
-                <dropdown-list #masterShapesList (selectedItem)="onUpdate($event)"></dropdown-list>
-              </div>
-            </div> -->
-
-            <!-- <div class="control-group" *ngIf="selectedImage?.image" [hidden]="selectedImage?.image === 'docker.dlab-dataengine'">
-              <label class="label">{{ DICTIONARY[selectedImage.image].data_engine_slave_instance_size }}</label>
-              <div class="control">
-                <dropdown-list #shapesSlaveList (selectedItem)="onUpdate($event)"></dropdown-list>
-              </div>
-            </div> -->
 
             <div class="control-group" *ngIf="selectedImage?.image">
               <label class="label">{{ DICTIONARY[selectedImage.image].data_engine_master_instance_size }}</label>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
index b7b77fe..85ade39 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
@@ -17,14 +17,14 @@
  * under the License.
  */
 
-import { Component, OnInit, EventEmitter, Output, ViewChild, Inject } from '@angular/core';
+import { Component, OnInit, ViewChild, Inject } from '@angular/core';
 import { FormGroup, FormBuilder, Validators } from '@angular/forms';
 import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 import { ToastrService } from 'ngx-toastr';
 
 import { ComputationalResourceModel } from './computational-resource-create.model';
 import { UserResourceService } from '../../../core/services';
-import { HTTP_STATUS_CODES, CheckUtils } from '../../../core/util';
+import { HTTP_STATUS_CODES, PATTERNS, CheckUtils } from '../../../core/util';
 
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 import { CLUSTER_CONFIGURATION } from './cluster-configuration-templates';
@@ -42,17 +42,10 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
   readonly CheckUtils = CheckUtils;
 
   notebook_instance: any;
-  full_list: any;
-
-  cluster_types = [];
+  resourcesList: any;
+  clusterTypes = [];
   selectedImage: any;
-
-  shapes: any;
   spotInstance: boolean = true;
-  clusterNamePattern: string = '[-_a-zA-Z0-9]*[_-]*[a-zA-Z0-9]+';
-  nodeCountPattern: string = '^[1-9]\\d*$';
-  delimitersRegex = /[-_]?/g;
-  integerRegex = '^[0-9]*$';
 
   public minInstanceNumber: number;
   public maxInstanceNumber: number;
@@ -62,85 +55,29 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
   public maxSpotPrice: number = 0;
   public resourceForm: FormGroup;
 
-  // @ViewChild('name') name;
-  // @ViewChild('templatesList') templates_list;
-  // @ViewChild('masterShapesList') master_shapes_list;
-  // @ViewChild('shapesSlaveList') slave_shapes_list;
   @ViewChild('spotInstancesCheck') spotInstancesSelect;
   @ViewChild('preemptibleNode') preemptible;
   @ViewChild('configurationNode') configuration;
 
-  @Output() buildGrid: EventEmitter<{}> = new EventEmitter();
-
   constructor(
     @Inject(MAT_DIALOG_DATA) public data: any,
     public toastr: ToastrService,
+    public dialogRef: MatDialogRef<ComputationalResourceCreateDialogComponent>,
     private userResourceService: UserResourceService,
     private model: ComputationalResourceModel,
-    private _fb: FormBuilder,
-    public dialogRef: MatDialogRef<ComputationalResourceCreateDialogComponent>,
+    private _fb: FormBuilder
   ) { }
 
   ngOnInit() {
     this.initFormModel();
     this.notebook_instance = this.data.notebook;
-    this.full_list = this.data.full_list;
+    this.resourcesList = this.data.resourcesList;
     this.getTemplates(this.notebook_instance.project);
   }
 
-  // public onUpdate($event): void {
-  //   if ($event.model.type === 'template') {
-  //     this.model.setSelectedTemplate($event.model.index);
-  //     this.master_shapes_list.setDefaultOptions(this.model.selectedImage.shapes.resourcesShapeTypes,
-  //       this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'description'), 'master_shape', 'description', 'json');
-  //     this.slave_shapes_list.setDefaultOptions(this.model.selectedImage.shapes.resourcesShapeTypes,
-  //       this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'description'), 'slave_shape', 'description', 'json');
-
-  //     this.shapes.master_shape = this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'type');
-  //     this.shapes.slave_shape = this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'type');
-  //   }
-  //   if ($event.model.type === 'cluster_type') {
-  //     this.model.setSelectedClusterType($event.model.index);
-  //     this.setDefaultParams();
-  //     this.getComputationalResourceLimits();
-  //     this.selectConfiguration();
-  //   }
-
-  //   if (this.shapes[$event.model.type])
-  //     this.shapes[$event.model.type] = $event.model.value.type;
-
-  //   if (DICTIONARY.cloud_provider === 'aws')
-  //     if ($event.model.type === 'slave_shape' && this.spotInstancesSelect.nativeElement['checked']) {
-  //       this.spotInstance = $event.model.value.spot;
-  //     }
-  // }
-
-  public createComputationalResource(data) {
-    this.model.createComputationalResource(data, this.selectedImage, this.notebook_instance, this.spotInstance)
-      .subscribe((response: any) => {
-        if (response.status === HTTP_STATUS_CODES.OK) {
-          this.dialogRef.close();
-          this.buildGrid.emit();
-        }
-      });
-  }
-
-  public containsComputationalResource(conputational_resource_name: string): boolean {
-    if (conputational_resource_name)
-      for (let index = 0; index < this.full_list.length; index++) {
-        if (this.notebook_instance.name === this.full_list[index].name) {
-          for (let iindex = 0; iindex < this.full_list[index].resources.length; iindex++) {
-            const computational_name = this.full_list[index].resources[iindex].computational_name.toString().toLowerCase();
-            if (this.delimitersFiltering(conputational_resource_name) === this.delimitersFiltering(computational_name))
-              return true;
-          }
-        }
-      }
-    return false;
-  }
-
-  public delimitersFiltering(resource): string {
-    return resource.replace(this.delimitersRegex, '').toString().toLowerCase();
+  public selectImage($event) {
+    this.selectedImage = $event;
+    this.getComputationalResourceLimits();
   }
 
   public selectSpotInstances($event?): void {
@@ -154,15 +91,6 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
     }
   }
 
-  public selectTemplate($event) {
-    if (DICTIONARY.cloud_provider === 'aws') this.spotInstancesSelect.nativeElement['checked'];
-  }
-
-  public selectImage($event) {
-    this.selectedImage = $event;
-    this.getComputationalResourceLimits();
-  }
-
   public selectPreemptibleNodes($event) {
     if ($event.target.checked)
       this.resourceForm.controls['preemptible_instance_number'].setValue(this.minPreemptibleInstanceNumber);
@@ -179,15 +107,12 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
     }
   }
 
-  private filterAvailableSpots() {
-    const filtered = JSON.parse(JSON.stringify(this.selectedImage.computation_resources_shapes));
-    for (const item in this.selectedImage.computation_resources_shapes) {
-      filtered[item] = filtered[item].filter(el => el.spot);
-      if (filtered[item].length <= 0) {
-        delete filtered[item];
-      }
-    }
-    return filtered;
+  public preemptibleCounter($event, action): void {
+    $event.preventDefault();
+
+    const value = this.resourceForm.controls['preemptible_instance_number'].value;
+    const newValue = (action === 'increment' ? Number(value) + 1 : Number(value) - 1);
+    this.resourceForm.controls.preemptible_instance_number.setValue(newValue);
   }
 
   public isAvailableSpots(): boolean {
@@ -197,12 +122,11 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
     return false;
   }
 
-  public preemptibleCounter($event, action): void {
-    $event.preventDefault();
-
-    const value = this.resourceForm.controls['preemptible_instance_number'].value;
-    const newValue = (action === 'increment' ? Number(value) + 1 : Number(value) - 1);
-    this.resourceForm.controls.preemptible_instance_number.setValue(newValue);
+  public createComputationalResource(data) {
+    this.model.createComputationalResource(data, this.selectedImage, this.notebook_instance, this.spotInstance)
+      .subscribe((response: any) => {
+        if (response.status === HTTP_STATUS_CODES.OK) this.dialogRef.close();
+      });
   }
 
   private initFormModel(): void {
@@ -211,10 +135,10 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
       version: [''],
       shape_master: ['', Validators.required],
       shape_slave: [''],
-      cluster_alias_name: ['', [Validators.required, Validators.pattern(this.clusterNamePattern),
+      cluster_alias_name: ['', [Validators.required, Validators.pattern(PATTERNS.namePattern),
       this.providerMaxLength, this.checkDuplication.bind(this)]],
-      instance_number: ['', [Validators.required, Validators.pattern(this.nodeCountPattern), this.validInstanceNumberRange.bind(this)]],
-      preemptible_instance_number: [0, Validators.compose([Validators.pattern(this.integerRegex), this.validPreemptibleRange.bind(this)])],
+      instance_number: ['', [Validators.required, Validators.pattern(PATTERNS.nodeCountPattern), this.validInstanceNumberRange.bind(this)]],
+      preemptible_instance_number: [0, Validators.compose([Validators.pattern(PATTERNS.integerRegex), this.validPreemptibleRange.bind(this)])],
       instance_price: [0, [this.validInstanceSpotRange.bind(this)]],
       configuration_parameters: ['', [this.validConfiguration.bind(this)]]
     });
@@ -249,6 +173,7 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
     }
   }
 
+  //  Validation
   private validInstanceNumberRange(control) {
     if (control && control.value)
       if (DICTIONARY.cloud_provider === 'gcp' && this.selectedImage.image === 'docker.dlab-dataengine-service') {
@@ -304,25 +229,15 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
       return control.value.length <= 10 ? null : { valid: false };
   }
 
-  private setDefaultParams(): void {
-    // if (this.model.selectedImage && this.model.selectedImage.shapes) {
-    //   this.filterShapes();
-    //   this.shapes = {
-    //     master_shape: this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'type'),
-    //     slave_shape: this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'type')
-    //   };
-    //   if (DICTIONARY.cloud_provider !== 'azure' && this.cluster_type) {
-    //     this.cluster_type.setDefaultOptions(this.model.resourceImages,
-    //       this.model.selectedImage.template_name, 'cluster_type', 'template_name', 'array');
-    //       // if (this.model.selectedImage.image === 'docker.dlab-dataengine-service')
-    //       //   this.templates_list.setDefaultOptions(this.model.templates,
-    //       //     this.model.selectedItem.version, 'template', 'version', 'array');
-    //   }
-    //   this.master_shapes_list && this.master_shapes_list.setDefaultOptions(this.model.selectedImage.shapes.resourcesShapeTypes,
-    //     this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'description'), 'master_shape', 'description', 'json');
-    //     this.slave_shapes_list && this.slave_shapes_list.setDefaultOptions(this.model.selectedImage.shapes.resourcesShapeTypes,
-    //     this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'description'), 'slave_shape', 'description', 'json');
-    // }
+  private getTemplates(project) {
+    this.userResourceService.getComputationalTemplates(project).subscribe(
+      clusterTypes => {
+        this.clusterTypes = clusterTypes;
+        this.selectedImage = clusterTypes[0];
+        this.getComputationalResourceLimits();
+        this.filterShapes();
+        this.resourceForm.get('template_name').setValue(this.selectedImage.template_name)
+      });
   }
 
   private filterShapes(): void {
@@ -337,22 +252,35 @@ export class ComputationalResourceCreateDialogComponent implements OnInit {
         }, {});
 
       if (DICTIONARY.cloud_provider !== 'azure') {
-        const images = this.cluster_types.filter(image => image.image === 'docker.dlab-dataengine');
-        this.cluster_types = images;
-        // (images.length > 0) ? this.model.setSelectedClusterType(0) : this.model.availableTemplates = false;
+        const images = this.clusterTypes.filter(image => image.image === 'docker.dlab-dataengine');
+        this.clusterTypes = images;
       }
       this.selectedImage.computation_resources_shapes = filtered;
     }
   }
 
-  private getTemplates(project) {
-    this.userResourceService.getComputationalTemplates(project).subscribe(
-      cluster_types => {
-        this.cluster_types = cluster_types;
-        this.selectedImage = cluster_types[0];
-        this.getComputationalResourceLimits();
-        this.filterShapes();
-        this.resourceForm.get('template_name').setValue(this.selectedImage.template_name)
-      });
+  private filterAvailableSpots() {
+    const filtered = JSON.parse(JSON.stringify(this.selectedImage.computation_resources_shapes));
+    for (const item in this.selectedImage.computation_resources_shapes) {
+      filtered[item] = filtered[item].filter(el => el.spot);
+      if (filtered[item].length <= 0) {
+        delete filtered[item];
+      }
+    }
+    return filtered;
+  }
+
+  private containsComputationalResource(conputational_resource_name: string): boolean {
+    if (conputational_resource_name)
+      for (let index = 0; index < this.resourcesList.length; index++) {
+        if (this.notebook_instance.name === this.resourcesList[index].name) {
+          for (let iindex = 0; iindex < this.resourcesList[index].resources.length; iindex++) {
+            const computational_name = this.resourcesList[index].resources[iindex].computational_name.toString().toLowerCase();
+            if (CheckUtils.delimitersFiltering(conputational_resource_name) === CheckUtils.delimitersFiltering(computational_name))
+              return true;
+          }
+        }
+      }
+    return false;
   }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.html
index 68d7125..80b35f0 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.html
@@ -19,8 +19,8 @@
 
 <table class="dashboard_table data-grid">
   <tr>
-    <th *ngFor="let column of filteringColumns"
-        ngClass="{{column.className || ''}}" [hidden]="column.name === 'cost' && !healthStatus?.billingEnabled">
+    <th *ngFor="let column of filteringColumns" ngClass="{{column.className || ''}}"
+      [hidden]="column.name === 'cost' && !healthStatus?.billingEnabled">
       {{column.title}}
       <button mat-icon-button *ngIf="column.filtering" aria-label="More" class="ar" (click)="toggleFilterRow()">
         <i class="material-icons">
@@ -33,16 +33,21 @@
 
   <tr *ngIf="filteredEnvironments && collapseFilterRow" class="filter-row">
     <td>
-      <input placeholder="Filter by environment name" type="text" class="form-control filter-field" [value]="filterForm.name" (input)="filterForm.name = $event.target.value" />
+      <input placeholder="Filter by environment name" type="text" class="form-control filter-field"
+        [value]="filterForm.name" (input)="filterForm.name = $event.target.value" />
     </td>
     <td>
-      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'statuses'" [items]="filterConfiguration.statuses" [model]="filterForm.statuses"></multi-select-dropdown>
+      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'statuses'"
+        [items]="filterConfiguration.statuses" [model]="filterForm.statuses"></multi-select-dropdown>
     </td>
     <td>
-      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="DICTIONARY.cloud_provider === 'aws' ? 'shapes': 'sizes'" [items]="filterConfiguration.shapes" [model]="filterForm.shapes"></multi-select-dropdown>
+      <multi-select-dropdown (selectionChange)="onUpdate($event)"
+        [type]="DICTIONARY.cloud_provider === 'aws' ? 'shapes': 'sizes'" [items]="filterConfiguration.shapes"
+        [model]="filterForm.shapes"></multi-select-dropdown>
     </td>
     <td>
-      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'resources'" [items]="filterConfiguration.resources" [model]="filterForm.resources"></multi-select-dropdown>
+      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'resources'"
+        [items]="filterConfiguration.resources" [model]="filterForm.resources"></multi-select-dropdown>
     </td>
     <td *ngIf="healthStatus?.billingEnabled"></td>
     <td>
@@ -51,37 +56,44 @@
           <i class="material-icons">close</i>
         </button>
 
-        <button mat-icon-button class="btn apply" (click)="applyFilter_btnClick(filterForm)" [disabled]="filteredEnvironments.length == 0 && !filtering">
+        <button mat-icon-button class="btn apply" (click)="applyFilter_btnClick(filterForm)"
+          [disabled]="filteredEnvironments.length == 0 && !filtering">
           <i class="material-icons" [ngClass]="{'not-allowed': filteredEnvironments.length == 0 && !filtering}">done</i>
         </button>
       </div>
     </td>
   </tr>
 
-  <tr *ngIf="(!filteredEnvironments) && !filtering || (filteredEnvironments.length == 0) && !filtering" class="message_block">
-    <td [colSpan]="!healthStatus?.billingEnabled ? filteringColumns.length -1 : filteringColumns.length">To start working, please, create new environment</td>
+  <tr *ngIf="(!filteredEnvironments) && !filtering || (filteredEnvironments.length == 0) && !filtering"
+    class="message_block">
+    <td [colSpan]="!healthStatus?.billingEnabled ? filteringColumns.length -1 : filteringColumns.length">To start
+      working, please, create new environment</td>
   </tr>
 
   <tr *ngIf="(filteredEnvironments.length == 0) && filtering" class="message_block">
-    <td [colSpan]="!healthStatus?.billingEnabled ? filteringColumns.length -1 : filteringColumns.length">No matches found</td>
+    <td [colSpan]="!healthStatus?.billingEnabled ? filteringColumns.length -1 : filteringColumns.length">No matches
+      found</td>
   </tr>
 
-  <tr *ngFor="let env of filteredEnvironments;" class="dashboard_table_body" [ngClass]="{'dropdown-outscreen': isOutscreenDropdown}">
+  <tr *ngFor="let env of filteredEnvironments;" class="dashboard_table_body"
+    [ngClass]="{'dropdown-outscreen': isOutscreenDropdown}">
     <td (click)="printDetailEnvironmentModal(env)">{{env.name}}</td>
     <td class="status" ngClass="{{env.status.toLowerCase() || ''}}">{{ env.status | underscoreless }}</td>
     <td>{{env.shape}}</td>
     <td>
-      <computational-resources-list [resources]="env.resources" [environment]="env" (buildGrid)="buildGrid($event)"></computational-resources-list>
+      <computational-resources-list [resources]="env.resources" [environment]="env" (buildGrid)="buildGrid($event)">
+      </computational-resources-list>
     </td>
     <td *ngIf="healthStatus?.billingEnabled">
       <span class="total_cost">{{ env.cost || 'N/A' }} {{ env.currency_code || '' }}</span>
-      <span (click)="env.billing && printCostDetails(env)" class="currency_details" [ngClass]="{ 'not-allowed' : !env.billing }">
+      <span (click)="env.billing && printCostDetails(env)" class="currency_details"
+        [ngClass]="{ 'not-allowed' : !env.billing }">
         <i class="material-icons">help_outline</i>
       </span>
     </td>
     <td class="settings">
       <span #settings (click)="actions.toggle($event, settings)" class="actions"
-            [ngClass]="{ 'disabled': env.status.toLowerCase() === 'creating' }">
+        [ngClass]="{ 'disabled': env.status.toLowerCase() === 'creating' }">
       </span>
 
       <bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
@@ -90,50 +102,48 @@
                 && env.status !== 'terminating'
                 && env.status !== 'terminated'
                 && env.status !== 'creating image'">
-            <li *ngIf="env.status !== 'stopped' && env.status !== 'stopping' && env.status !== 'starting' && env.status !== 'creating image'"
-                matTooltip="Unable to stop notebook because at least one computational resource is in progress"
-                matTooltipPosition="above"
-                [matTooltipDisabled]="!isResourcesInProgress(env)">
-                <div (click)="exploratoryAction(env, 'stop')" [ngClass]="{'not-allowed': isResourcesInProgress(env) }">
-                  <i class="material-icons">pause_circle_outline</i>
-                  <span>Stop</span>
-                </div>
+            <li
+              *ngIf="env.status !== 'stopped' && env.status !== 'stopping' && env.status !== 'starting' && env.status !== 'creating image'"
+              matTooltip="Unable to stop notebook because at least one computational resource is in progress"
+              matTooltipPosition="above" [matTooltipDisabled]="!isResourcesInProgress(env)">
+              <div (click)="exploratoryAction(env, 'stop')" [ngClass]="{'not-allowed': isResourcesInProgress(env) }">
+                <i class="material-icons">pause_circle_outline</i>
+                <span>Stop</span>
+              </div>
             </li>
             <li *ngIf="env.status.toLowerCase() === 'stopped' || env.status.toLowerCase() === 'stopping'"
-                matTooltip="Unable to run notebook until it will be stopped"
-                matTooltipPosition="above"
-                [matTooltipDisabled]="!isResourcesInProgress(env) && env.status.toLowerCase() !== 'stopping'">
-              <div (click)="exploratoryAction(env, 'run')" [ngClass]="{'not-allowed': isResourcesInProgress(env) || env.status.toLowerCase() === 'stopping' }">
+              matTooltip="Unable to run notebook until it will be stopped" matTooltipPosition="above"
+              [matTooltipDisabled]="!isResourcesInProgress(env) && env.status.toLowerCase() !== 'stopping'">
+              <div (click)="exploratoryAction(env, 'run')"
+                [ngClass]="{'not-allowed': isResourcesInProgress(env) || env.status.toLowerCase() === 'stopping' }">
                 <i class="material-icons">play_circle_outline</i>
                 <span>Run</span>
               </div>
             </li>
             <li *ngIf="env.status.toLowerCase() === 'running' || env.status.toLowerCase() === 'stopped'"
-                matTooltip="Unable to terminate notebook because at least one computational resource is in progress"
-                matTooltipPosition="above"
-                [matTooltipDisabled]="!isResourcesInProgress(env)">
-              <div (click)="exploratoryAction(env, 'terminate')" [ngClass]="{'not-allowed': isResourcesInProgress(env) }">
+              matTooltip="Unable to terminate notebook because at least one computational resource is in progress"
+              matTooltipPosition="above" [matTooltipDisabled]="!isResourcesInProgress(env)">
+              <div (click)="exploratoryAction(env, 'terminate')"
+                [ngClass]="{'not-allowed': isResourcesInProgress(env) }">
                 <i class="material-icons">phonelink_off</i>
                 <span>Terminate</span>
               </div>
             </li>
-            <li (click)="exploratoryAction(env, 'deploy')"
-                *ngIf="env.status != 'stopping'
+            <li (click)="exploratoryAction(env, 'deploy')" *ngIf="env.status != 'stopping'
                 && env.status !== 'stopped'
                 && env.status !== 'starting'
                 && env.status !== 'creating image'">
               <i class="material-icons">memory</i>
               <span>Add compute</span>
             </li>
-            <li (click)="exploratoryAction(env, 'schedule')"
-                *ngIf="env.status.toLowerCase() === 'running'
+            <li (click)="exploratoryAction(env, 'schedule')" *ngIf="env.status.toLowerCase() === 'running'
                 || env.status.toLowerCase() === 'stopped'">
-                <i class="material-icons">schedule</i>
+              <i class="material-icons">schedule</i>
               <span>Scheduler</span>
             </li>
           </div>
           <li (click)="exploratoryAction(env, 'ami')"
-              *ngIf="env.status === 'running' && DICTIONARY.cloud_provider !== 'gcp'">
+            *ngIf="env.status === 'running' && DICTIONARY.cloud_provider !== 'gcp'">
             <i class="material-icons">view_module</i>
             <span>Create {{ DICTIONARY.image }}</span>
           </li>
@@ -141,12 +151,12 @@
             <i class="material-icons">developer_board</i>
             <span>Manage libraries</span>
           </li>
-          <li>
-            <a target="_blank" [routerLink]="['/terminal',  env.ip]" class="navigate">
+          <!-- <li>
+            <a target="_blank" [routerLink]="['/terminal', env.ip]" class="navigate">
               <i class="material-icons">laptop</i>
               <span>Open terminal</span>
             </a>
-          </li>
+          </li> -->
         </ul>
       </bubble-up>
     </td>


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