You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@submarine.apache.org by li...@apache.org on 2020/09/18 01:51:28 UTC

[submarine] branch master updated: SUBMARINE-608. [WEB] Create environment through UI

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

liuxun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git


The following commit(s) were added to refs/heads/master by this push:
     new 329fec8  SUBMARINE-608. [WEB] Create environment through UI
329fec8 is described below

commit 329fec8e53355b9d3465b044c9e7c75b96c31e80
Author: kobe860219 <ko...@gmail.com>
AuthorDate: Thu Sep 17 11:14:59 2020 +0800

    SUBMARINE-608. [WEB] Create environment through UI
    
    ### What is this PR for?
    Complete creation environment through UI.
    
    ### What type of PR is it?
    [Feature]
    
    ### Todos
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/browse/SUBMARINE-608
    
    ### How should this be tested?
    https://travis-ci.org/github/kobe860219/submarine/builds/727321947
    
    ### Screenshots (if appropriate)
    ![螢幕錄製 2020-09-15 下午4](https://user-images.githubusercontent.com/48027290/93199002-5a3c5780-f780-11ea-939f-bb31c6d4069b.gif)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: kobe860219 <ko...@gmail.com>
    
    Closes #402 from kobe860219/SUBMARINE-608 and squashes the following commits:
    
    207f0ef [kobe860219] SUBMARINE-608. [WEB] Create environment through UI
    5a457f4 [kobe860219] SUBMARINE-608. [WEB] Create environment through UI
---
 .../src/app/interfaces/environment-spec.ts         |   2 -
 .../environment/environment.component.html         | 104 +++++++++++++++++++
 .../workbench/environment/environment.component.ts | 112 +++++++++++++++++++--
 .../workbench/notebook/notebook.component.html     |   2 +-
 .../src/app/services/environment.service.ts        |  15 ++-
 5 files changed, 224 insertions(+), 11 deletions(-)

diff --git a/submarine-workbench/workbench-web-ng/src/app/interfaces/environment-spec.ts b/submarine-workbench/workbench-web-ng/src/app/interfaces/environment-spec.ts
index ffc32e8..90cd3b6 100644
--- a/submarine-workbench/workbench-web-ng/src/app/interfaces/environment-spec.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/interfaces/environment-spec.ts
@@ -24,8 +24,6 @@ export interface KernelSpec {
 
 export interface EnvironmentSpec {
   name: string;
-  description: string;
   dockerImage: string;
-  image: string;
   kernelSpec: KernelSpec;
 }
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/environment/environment.component.html b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/environment/environment.component.html
index 10de4d5..8fcdd17 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/environment/environment.component.html
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/environment/environment.component.html
@@ -58,6 +58,7 @@
           id="createEnvironment"
           nzType="primary"
           style="margin-right: 5px; margin-bottom: 15px; margin-top: 15px;"
+          (click)="initEnvForm()"
         >
           <i nz-icon nzType="plus"></i>
           New Environment
@@ -115,3 +116,106 @@
     <router-outlet></router-outlet>
   </div>
 </nz-layout>
+
+<nz-modal [(nzVisible)]="isVisible" nzTitle="Create Environment" [nzWidth]="700">
+  <div *nzModalFooter>
+    <button nz-button nzType="default" (click)="closeModal()">Cancel</button>
+    <button id="go" nz-button nzType="primary" [disabled]="checkStatus()" (click)="createEnvironment()">
+      Create
+    </button>
+  </div>
+  <div>
+    <form [formGroup]="environmentForm">
+      <h2>Meta</h2>
+      <div class="single-field-group">
+        <label for="environmentName">
+          <span class="red-star">*</span>
+          Environment Name
+        </label>
+        <input
+          required
+          nz-input
+          type="text"
+          name="environmentName"
+          id="environmentName"
+          formControlName="environmentName"
+        />
+      </div>
+      <div class="single-field-group">
+        <label for="dockerImage">
+          <span class="red-star">*</span>
+          Docker Image
+        </label>
+        <input required nz-input type="text" name="dockerImage" id="dockerImage" formControlName="dockerImage" />
+      </div>
+      <h2>Kernel Spec</h2>
+      <div class="single-field-group">
+        <label for="name">
+          <span class="red-star">*</span>
+          Name
+        </label>
+        <input required nz-input type="text" name="name" id="name" formControlName="name" />
+      </div>
+      <div formArrayName="channels">
+        <div *ngFor="let channel of channels.controls; let i = index">
+          <div class="single-field-group">
+            <label>Channel {{ i + 1 }}:</label>
+            <input required nz-input type="text" name="channel{{ i }}" id="channel{{ i }}" [formControlName]="i" />
+            <i
+              nz-icon
+              style="margin-left: 5px;"
+              nzType="close-circle"
+              nzTheme="fill"
+              (click)="deleteItem(channels, i)"
+            ></i>
+          </div>
+        </div>
+      </div>
+      <div style="margin: 10px;">
+        <button
+          nz-button
+          style="display: block; margin: auto;"
+          id="addChannel-btn"
+          type="default"
+          (click)="addChannel()"
+        >
+          New Channel
+        </button>
+      </div>
+      <div formArrayName="dependencies">
+        <div *ngFor="let channel of dependencies.controls; let i = index">
+          <div class="single-field-group">
+            <label>Dependency {{ i + 1 }}:</label>
+            <input
+              required
+              nz-input
+              type="text"
+              name="dependencies{{ i }}"
+              id="dependencies{{ i }}"
+              [formControlName]="i"
+            />
+            <i
+              nz-icon
+              style="margin-left: 5px;"
+              nzType="close-circle"
+              nzTheme="fill"
+              (click)="deleteItem(dependencies, i)"
+            ></i>
+          </div>
+        </div>
+      </div>
+      <div style="margin: 10px;">
+        <button
+          style="margin-top: 10px;"
+          nz-button
+          style="display: block; margin: auto;"
+          id="addDep-btn"
+          type="default"
+          (click)="addDependencies()"
+        >
+          New Dependency
+        </button>
+      </div>
+    </form>
+  </div>
+</nz-modal>
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/environment/environment.component.ts b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/environment/environment.component.ts
index dbef9ec..023769c 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/environment/environment.component.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/environment/environment.component.ts
@@ -18,6 +18,7 @@
  */
 
 import { Component, OnInit } from '@angular/core';
+import { FormArray, FormControl, FormGroup, Validators } from '@angular/forms';
 import { Environment } from '@submarine/interfaces/environment-info';
 import { EnvironmentService } from '@submarine/services/environment.service';
 import { NzMessageService } from 'ng-zorro-antd';
@@ -28,15 +29,23 @@ import { NzMessageService } from 'ng-zorro-antd';
   styleUrls: ['./environment.component.scss']
 })
 export class EnvironmentComponent implements OnInit {
-  constructor(
-    private environmentService: EnvironmentService,
-    private nzMessageService: NzMessageService) {}
+  constructor(private environmentService: EnvironmentService, private nzMessageService: NzMessageService) {}
 
   environmentList: Environment[] = [];
   checkedList: boolean[] = [];
   selectAllChecked: boolean = false;
 
+  isVisible = false;
+  environmentForm;
+
   ngOnInit() {
+    this.environmentForm = new FormGroup({
+      environmentName: new FormControl(null, Validators.required),
+      dockerImage: new FormControl(null, Validators.required),
+      name: new FormControl(null, Validators.required),
+      channels: new FormArray([]),
+      dependencies: new FormArray([])
+    });
     this.fetchEnvironmentList();
   }
 
@@ -50,8 +59,99 @@ export class EnvironmentComponent implements OnInit {
     });
   }
 
-  // TODO(kobe860219): Create new environment
-  createEnvironment(data) {}
+  get environmentName() {
+    return this.environmentForm.get('environmentName');
+  }
+
+  get dockerImage() {
+    return this.environmentForm.get('dockerImage');
+  }
+
+  get name() {
+    return this.environmentForm.get('name');
+  }
+
+  get channels() {
+    return this.environmentForm.get('channels') as FormArray;
+  }
+
+  get dependencies() {
+    return this.environmentForm.get('dependencies') as FormArray;
+  }
+
+  initEnvForm() {
+    this.isVisible = true;
+    this.environmentName.reset();
+    this.dockerImage.reset();
+    this.name.reset();
+    this.channels.clear();
+    this.dependencies.clear();
+  }
+
+  checkStatus() {
+    return (
+      this.environmentName.invalid ||
+      this.dockerImage.invalid ||
+      this.name.invalid ||
+      this.channels.invalid ||
+      this.dependencies.invalid
+    );
+  }
+
+  closeModal() {
+    this.isVisible = false;
+  }
+
+  addChannel() {
+    this.channels.push(new FormControl('', Validators.required));
+  }
+
+  addDependencies() {
+    this.dependencies.push(new FormControl('', Validators.required));
+  }
+
+  deleteItem(arr: FormArray, index: number) {
+    arr.removeAt(index);
+  }
+
+  createEnvironment() {
+    this.isVisible = false;
+    const newEnvironmentSpec = this.createEnvironmentSpec();
+    console.log(newEnvironmentSpec);
+    this.environmentService.createEnvironment(newEnvironmentSpec).subscribe(
+      () => {
+        this.nzMessageService.success('Create Environment Success!');
+        this.fetchEnvironmentList();
+      },
+      (err) => {
+        this.nzMessageService.error(`${err}, please try again`, {
+          nzPauseOnHover: true
+        });
+      }
+    );
+  }
+
+  createEnvironmentSpec() {
+    const environmentSpec = {
+      name: this.environmentForm.get('environmentName').value,
+      dockerImage: this.environmentForm.get('dockerImage').value,
+      kernelSpec: {
+        name: this.environmentForm.get('name').value,
+        channels: [],
+        dependencies: []
+      }
+    };
+
+    for (const channel of this.channels.controls) {
+      environmentSpec.kernelSpec.channels.push(channel.value);
+    }
+
+    for (const dependency of this.dependencies.controls) {
+      environmentSpec.kernelSpec.dependencies.push(dependency.value);
+    }
+
+    return environmentSpec;
+  }
 
   // TODO(kobe860219): Update an environment
   updateEnvironment(id: string, data) {}
@@ -74,7 +174,7 @@ export class EnvironmentComponent implements OnInit {
 
   deleteEnvironments() {
     for (let i = this.checkedList.length - 1; i >= 0; i--) {
-      console.log(this.environmentList[i].environmentSpec.name)
+      console.log(this.environmentList[i].environmentSpec.name);
       if (this.checkedList[i] === true) {
         this.onDeleteEnvironment(this.environmentList[i].environmentSpec.name, false);
       }
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.component.html b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.component.html
index cdd0ed9..e1c4f7e 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.component.html
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.component.html
@@ -190,7 +190,7 @@
       </div>
     </div>
     <button nz-button style="display: block; margin: auto;" id="envVar-btn" type="default" (click)="onCreateEnvVar()">
-      Add new env
+      Add New EnvVar
     </button>
   </form>
 </nz-modal>
diff --git a/submarine-workbench/workbench-web-ng/src/app/services/environment.service.ts b/submarine-workbench/workbench-web-ng/src/app/services/environment.service.ts
index 7f28365..9a14d3d 100644
--- a/submarine-workbench/workbench-web-ng/src/app/services/environment.service.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/services/environment.service.ts
@@ -24,6 +24,7 @@ import { Environment } from '@submarine/interfaces/environment-info';
 import { BaseApiService } from '@submarine/services/base-api.service';
 import { of, throwError, Observable } from 'rxjs';
 import { catchError, map, switchMap } from 'rxjs/operators';
+import { EnvironmentSpec } from '@submarine/interfaces/environment-spec';
 
 @Injectable({
   providedIn: 'root'
@@ -48,8 +49,18 @@ export class EnvironmentService {
   // TODO(kobe860219): Query environment
   querySpecificEnvironment(id: string) {}
 
-  // TODO(kobe860219): Create new environment
-  createEnvironment(createData) {}
+  createEnvironment(spec: object): Observable<Environment> {
+    const apiUrl = this.baseApi.getRestApi(`/v1/environment/`);
+    return this.httpClient.post<Rest<Environment>>(apiUrl, spec).pipe(
+      switchMap((res) => {
+        if (res.success) {
+          return of(res.result);
+        } else {
+          throw this.baseApi.createRequestError(res.message, res.code, apiUrl, 'post', spec);
+        }
+      })
+    );
+  }
 
   // TODO(kobe860219): Update an environment
   updateEnvironment(updateData) {}


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@submarine.apache.org
For additional commands, e-mail: dev-help@submarine.apache.org