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

pingsutw 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 ade9311  SUBMARINE-700. [WEB] Refactor notebook page of Workbench
ade9311 is described below

commit ade9311f74abf41ed8867e1e76e4ee76ca24c0e1
Author: kobe860219 <[email protected]>
AuthorDate: Fri Jan 29 17:55:25 2021 +0800

    SUBMARINE-700. [WEB] Refactor notebook page of Workbench
    
    ### What is this PR for?
    Refactor the architecture of notebook component in workbench. The new 
architecture is as below :
    
    ![Notebook 
Architecture](https://user-images.githubusercontent.com/48027290/105056481-359a1880-5aaf-11eb-9a7d-56fefac1a12b.png)
    
    ### What type of PR is it?
    [Refactoring]
    
    ### Todos
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/browse/SUBMARINE-700
    
    ### How should this be tested?
    https://travis-ci.org/github/kobe860219/submarine/builds/755191807
    
    ### Screenshots (if appropriate)
    ![notebook page demo 
20210127](https://user-images.githubusercontent.com/48027290/105964193-d21a7700-60bc-11eb-9e1e-c2bf717c75f6.gif)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: kobe860219 <[email protected]>
    
    Signed-off-by: Kevin <[email protected]>
    
    Closes #494 from kobe860219/SUBMARINE-700 and squashes the following 
commits:
    
    24e25a8 [kobe860219] Fix test failure and update image
    981224f [kobe860219] Prettier code
    8189a95 [kobe860219] Fix interval and prettier code
    d50ae4a [kobe860219] Add popconfirm
    5fd746f [kobe860219] Fix architecture and form
    a648e6a [kobe860219] Remove unuse css
    d4e4aa3 [kobe860219] SUBMARINE-700. [WEB] Refactor notebook page of 
Workbench
---
 docs/assets/created-notebook.png                   | Bin 71556 -> 219016 bytes
 docs/assets/notebook-form.png                      | Bin 68260 -> 241529 bytes
 docs/assets/notebook-list.png                      | Bin 65219 -> 189814 bytes
 .../apache/submarine/integration/notebookIT.java   |   6 +-
 .../{ => notebook-interfaces}/notebook-info.ts     |   5 +-
 .../{ => notebook-interfaces}/notebook-spec.ts     |   0
 .../notebook-form/notebook-form.component.html     | 112 ++++++++
 .../notebook-form/notebook-form.component.scss}    |  20 +-
 .../notebook-form/notebook-form.component.ts}      | 245 +++++------------
 .../notebook-home/notebook-home.component.html     |  38 +++
 .../notebook-home/notebook-home.component.scss}    |  16 +-
 .../notebook-home/notebook-home.component.ts       |  86 ++++++
 .../notebook-list/notebook-list.component.html     |  77 ++++++
 .../notebook-list/notebook-list.component.scss}    |  16 +-
 .../notebook-list/notebook-list.component.ts       |  52 ++++
 ...tebook.module.ts => notebook-routing.module.ts} |  27 +-
 .../workbench/notebook/notebook.component.html     | 226 +--------------
 .../workbench/notebook/notebook.component.scss     |  49 ----
 .../pages/workbench/notebook/notebook.component.ts | 304 +--------------------
 .../pages/workbench/notebook/notebook.module.ts    |  24 +-
 .../pages/workbench/workbench-routing.module.ts    |   3 +-
 .../src/app/pages/workbench/workbench.module.ts    |  14 +-
 .../{ => notebook-services}/notebook.service.ts    |  17 +-
 .../workbench-web/src/app/services/polling.ts      | 105 -------
 24 files changed, 520 insertions(+), 922 deletions(-)

diff --git a/docs/assets/created-notebook.png b/docs/assets/created-notebook.png
index 6d08f3f..d903361 100644
Binary files a/docs/assets/created-notebook.png and 
b/docs/assets/created-notebook.png differ
diff --git a/docs/assets/notebook-form.png b/docs/assets/notebook-form.png
index 04208ad..a95310f 100644
Binary files a/docs/assets/notebook-form.png and 
b/docs/assets/notebook-form.png differ
diff --git a/docs/assets/notebook-list.png b/docs/assets/notebook-list.png
index 6a90526..aaceded 100644
Binary files a/docs/assets/notebook-list.png and 
b/docs/assets/notebook-list.png differ
diff --git 
a/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/notebookIT.java
 
b/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/notebookIT.java
index ff5290a..2bb1537 100644
--- 
a/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/notebookIT.java
+++ 
b/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/notebookIT.java
@@ -58,7 +58,7 @@ public class notebookIT extends AbstractSubmarineIT {
 
     // Test for creating new notebook
     LOG.info("Create Notebook Test");
-    pollingWait(By.xpath("//button[@id='btnNewNotebook']"), 
MAX_BROWSER_TIMEOUT_SEC).click();
+    pollingWait(By.xpath("//button[@id='btn-newNotebook']"), 
MAX_BROWSER_TIMEOUT_SEC).click();
     pollingWait(By.cssSelector("input[ng-reflect-name='notebookName']"), 
MAX_BROWSER_TIMEOUT_SEC).sendKeys("test-nb");
     pollingWait(By.cssSelector("input[ng-reflect-name='cpus']"), 
MAX_BROWSER_TIMEOUT_SEC).clear();
     pollingWait(By.cssSelector("input[ng-reflect-name='cpus']"), 
MAX_BROWSER_TIMEOUT_SEC).sendKeys("2");
@@ -68,12 +68,12 @@ public class notebookIT extends AbstractSubmarineIT {
     pollingWait(By.xpath("//button[@id='envVar-btn']"), 
MAX_BROWSER_TIMEOUT_SEC).click();
     pollingWait(By.xpath("//input[@name='key0']"), 
MAX_BROWSER_TIMEOUT_SEC).sendKeys("testKey0");
     pollingWait(By.xpath("//input[@name='value0']"), 
MAX_BROWSER_TIMEOUT_SEC).sendKeys("testValue0");
-    pollingWait(By.xpath("//button[@id='create-btn']"), 
MAX_BROWSER_TIMEOUT_SEC).click();
+    pollingWait(By.xpath("//button[@id='nb-form-btn-create']"), 
MAX_BROWSER_TIMEOUT_SEC).click();
     /*
     Future add k8s test.
     Assert.assertEquals(pollingWait(By.xpath("//td[contains(., 'test-nb')]"), 
MAX_BROWSER_TIMEOUT_SEC).isDisplayed(), true);
     */
-    
Assert.assertEquals(pollingWait(By.xpath("//button[@id='btnNewNotebook']"), 
MAX_BROWSER_TIMEOUT_SEC).isDisplayed(), true);
+    
Assert.assertEquals(pollingWait(By.xpath("//button[@id='btn-newNotebook']"), 
MAX_BROWSER_TIMEOUT_SEC).isDisplayed(), true);
     LOG.info("Test Success!");
 
   }
diff --git 
a/submarine-workbench/workbench-web/src/app/interfaces/notebook-info.ts 
b/submarine-workbench/workbench-web/src/app/interfaces/notebook-interfaces/notebook-info.ts
similarity index 87%
copy from submarine-workbench/workbench-web/src/app/interfaces/notebook-info.ts
copy to 
submarine-workbench/workbench-web/src/app/interfaces/notebook-interfaces/notebook-info.ts
index 91a8d21..128f7a4 100644
--- a/submarine-workbench/workbench-web/src/app/interfaces/notebook-info.ts
+++ 
b/submarine-workbench/workbench-web/src/app/interfaces/notebook-interfaces/notebook-info.ts
@@ -18,14 +18,15 @@
  */
 
 import { Url } from 'url';
-import { NotebookSpec } from '@submarine/interfaces/notebook-spec';
+import { NotebookSpec } from 
'@submarine/interfaces/notebook-interfaces/notebook-spec';
 
-export interface Notebook {
+export interface NotebookInfo {
   notebookId: string;
   name: string;
   uid: string;
   url: Url;
   status: string;
+  reason: string;
   createdTime: string;
   deletedTime: string;
   spec: NotebookSpec;
diff --git 
a/submarine-workbench/workbench-web/src/app/interfaces/notebook-spec.ts 
b/submarine-workbench/workbench-web/src/app/interfaces/notebook-interfaces/notebook-spec.ts
similarity index 100%
rename from 
submarine-workbench/workbench-web/src/app/interfaces/notebook-spec.ts
rename to 
submarine-workbench/workbench-web/src/app/interfaces/notebook-interfaces/notebook-spec.ts
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-form/notebook-form.component.html
 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-form/notebook-form.component.html
new file mode 100644
index 0000000..141200a
--- /dev/null
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-form/notebook-form.component.html
@@ -0,0 +1,112 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<nz-modal [(nzVisible)]="isVisible" (nzOnCancel)="isVisible = false" 
nzTitle="Create Notebook" [nzWidth]="700">
+  <div *nzModalFooter>
+    <button nz-button id="nb-form-btn-cancel" nzType="default" 
(click)="isVisible = false">Cancel</button>
+    <button nz-button id="nb-form-btn-create" nzType="primary" 
[disabled]="checkStatus()" (click)="submitForm()">
+      Create
+    </button>
+  </div>
+  <form [formGroup]="notebookForm">
+    <nz-form-item>
+      <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired 
nzFor="notebookName">Notebook Name</nz-form-label>
+      <nz-form-control [nzSm]="14" [nzXs]="24">
+        <input nz-input required type="text" name="notebookName" 
id="notebookName" formControlName="notebookName" />
+      </nz-form-control>
+    </nz-form-item>
+    <nz-form-item>
+      <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired 
nzFor="environment">Environment</nz-form-label>
+      <nz-form-control [nzSm]="14" [nzXs]="24">
+        <nz-select required name="select-envName" formControlName="envName">
+          <nz-option
+            *ngFor="let env of envNameList; let i; of: index"
+            id="env{{ i }}"
+            [nzValue]="env"
+            [nzLabel]="env"
+          ></nz-option>
+        </nz-select>
+      </nz-form-control>
+    </nz-form-item>
+    <nz-form-item>
+      <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired 
nzFor="cpus">CPU</nz-form-label>
+      <nz-form-control [nzSm]="14" [nzXs]="24">
+        <input nz-input min="0" required type="number" name="cpus" id="cpus" 
formControlName="cpus" />
+      </nz-form-control>
+    </nz-form-item>
+    <nz-form-item>
+      <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired 
nzFor="gpus">GPU</nz-form-label>
+      <nz-form-control [nzSm]="14" [nzXs]="24">
+        <input nz-input min="0" type="number" name="gpus" id="gpus" 
formControlName="gpus" />
+      </nz-form-control>
+    </nz-form-item>
+    <nz-form-item>
+      <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired 
nzFor="memoryNum">Memory</nz-form-label>
+      <nz-form-control [nzSm]="14" [nzXs]="24">
+        <div nz-col nzSpan="6">
+          <input nz-input required name="memoryNum" placeholder="EX:1024" 
formControlName="memoryNum" />
+        </div>
+        <div nz-col nzSpan="6" style="margin-left: 5px">
+          <nz-select formControlName="unit">
+            <nz-option *ngFor="let unit of MEMORY_UNITS" [nzValue]="unit" 
[nzLabel]="unit"></nz-option>
+          </nz-select>
+        </div>
+      </nz-form-control>
+    </nz-form-item>
+    <div formArrayName="envVars">
+      <ng-container *ngFor="let envVar of envVars.controls; index as i">
+        <nz-form-item>
+          <nz-form-label nzRequired [nzSm]="6" [nzXs]="24">EnvVar{{ i + 1 
}}</nz-form-label>
+          <div [formGroupName]="i">
+            <div nz-col nzSpan="12">
+              <input
+                style="width: 30%"
+                nz-input
+                required
+                id="key{{ i }}"
+                name="key{{ i }}"
+                placeholder="Key"
+                formControlName="key"
+              />
+              <input
+                style="width: 60%; margin-left: 10px"
+                nz-input
+                required
+                id="value{{ i }}"
+                name="value{{ i }}"
+                placeholder="Value"
+                formControlName="value"
+              />
+              <i
+                nz-icon
+                style="margin-left: 5px"
+                nzType="close-circle"
+                nzTheme="fill"
+                (click)="deleteItem(envVars, i)"
+              ></i>
+            </div>
+          </div>
+        </nz-form-item>
+      </ng-container>
+    </div>
+    <button nz-button style="display: block; margin: auto" id="envVar-btn" 
type="default" (click)="onCreateEnvVar()">
+      New EnvVar
+    </button>
+  </form>
+</nz-modal>
diff --git 
a/submarine-workbench/workbench-web/src/app/interfaces/notebook-info.ts 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-form/notebook-form.component.scss
similarity index 74%
copy from submarine-workbench/workbench-web/src/app/interfaces/notebook-info.ts
copy to 
submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-form/notebook-form.component.scss
index 91a8d21..9daa273 100644
--- a/submarine-workbench/workbench-web/src/app/interfaces/notebook-info.ts
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-form/notebook-form.component.scss
@@ -1,4 +1,4 @@
-/*
+/*!
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -17,16 +17,8 @@
  * under the License.
  */
 
-import { Url } from 'url';
-import { NotebookSpec } from '@submarine/interfaces/notebook-spec';
-
-export interface Notebook {
-  notebookId: string;
-  name: string;
-  uid: string;
-  url: Url;
-  status: string;
-  createdTime: string;
-  deletedTime: string;
-  spec: NotebookSpec;
-}
+.form-btn {
+   margin: 10px;
+   width : 140px;
+   height: 50px
+}
\ No newline at end of file
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.ts
 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-form/notebook-form.component.ts
similarity index 54%
copy from 
submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.ts
copy to 
submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-form/notebook-form.component.ts
index e0d1533..ef230ed 100644
--- 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.ts
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-form/notebook-form.component.ts
@@ -19,93 +19,67 @@
 
 import { Component, OnInit } from '@angular/core';
 import { FormArray, FormControl, FormGroup, Validators, FormBuilder } from 
'@angular/forms';
-import { NotebookService } from '@submarine/services/notebook.service';
-import { NzMessageService } from 'ng-zorro-antd/message';
-import { EnvironmentService } from '@submarine/services/environment.service';
 import { ExperimentValidatorService } from 
'@submarine/services/experiment.validator.service';
+import { EnvironmentService } from '@submarine/services/environment.service';
+import { NotebookService } from 
'@submarine/services/notebook-services/notebook.service';
 import { UserService } from '@submarine/services/user.service';
-import { nullSafeIsEquivalent } from '@angular/compiler/src/output/output_ast';
-import { Subscription } from 'rxjs';
-import { ExponentialBackoff } from '@submarine/services/polling';
-import { isEqual } from "lodash";
-import { NzNotificationService } from 'ng-zorro-antd/notification';
+import { NzMessageService } from 'ng-zorro-antd/message';
 
 @Component({
-  selector: 'submarine-notebook',
-  templateUrl: './notebook.component.html',
-  styleUrls: ['./notebook.component.scss']
+  selector: 'submarine-notebook-form',
+  templateUrl: './notebook-form.component.html',
+  styleUrls: ['./notebook-form.component.scss'],
 })
-export class NotebookComponent implements OnInit {
+export class NotebookFormComponent implements OnInit {
+  isVisible: boolean;
+
+  // User Information
+  userId;
+
   // Environment
   envList;
   envNameList = [];
   indexOfDeaultEnv;
 
-  // Namesapces
-  allNamespaceList = [];
-  currentNamespace;
-
-  // Notebook list
-  allNotebookList;
-  notebookTable;
-
-  // New Notebook Form
+  // Form
   notebookForm: FormGroup;
-  isVisible = false;
   MEMORY_UNITS = ['M', 'Gi'];
 
-  // User Information
-  userId;
-
-  // Sync //
-  // Subscription
-  subscriptions = new Subscription();
-  // Poller
-  poller: ExponentialBackoff;
-
   constructor(
-    private notebookService: NotebookService,
-    private nzMessageService: NzMessageService,
-    private environmentService: EnvironmentService,
+    private fb: FormBuilder,
     private experimentValidatorService: ExperimentValidatorService,
+    private environmentService: EnvironmentService,
+    private notebookService: NotebookService,
     private userService: UserService,
-    private fb: FormBuilder,
-    private nzNotificationService: NzNotificationService
+    private nzMessageService: NzMessageService
   ) {}
 
   ngOnInit() {
-    this.poller = new ExponentialBackoff({ interval: 1000, retries: 3 });
-    const resourcesSub = this.poller.start().subscribe(() => {
-      this.userService.fetchUserInfo().subscribe((res) => {
-        this.userId = res.id;
-        
this.notebookService.fetchNotebookList(this.userId).subscribe(resources => {
-          if (!isEqual(this.allNotebookList, resources)) {
-            this.allNotebookList = resources;
-            this.poller.reset();
-          }
-        });
-      });
+    this.userService.fetchUserInfo().subscribe((res) => {
+      this.userId = res.id;
     });
-    
-    this.subscriptions.add(resourcesSub);
 
     this.notebookForm = this.fb.group({
-      notebookName: [null, [
-        Validators.maxLength(63),
-        Validators.pattern('^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$'),
-        Validators.required]],
+      notebookName: [
+        null,
+        [Validators.maxLength(63), 
Validators.pattern('^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$'), Validators.required],
+      ],
       envName: [null, Validators.required], // Environment
       envVars: this.fb.array([], 
[this.experimentValidatorService.nameValidatorFactory('key')]),
       cpus: [null, [Validators.min(1), Validators.required]],
       gpus: [null],
       memoryNum: [null, [Validators.required]],
-      unit: [this.MEMORY_UNITS[0], [Validators.required]]
+      unit: [this.MEMORY_UNITS[0], [Validators.required]],
     });
+
     this.fetchEnvList();
+
+    this.initFormStatus();
   }
 
-  ngOnDestroy() {
-    this.subscriptions.unsubscribe();
+  initModal() {
+    this.isVisible = true;
+    this.initFormStatus();
   }
 
   // Get all environment
@@ -121,70 +95,15 @@ export class NotebookComponent implements OnInit {
     });
   }
 
-  // Get all notebooks, then set default namespace.
-  fetchNotebookList(id: string) {
-    this.notebookService.fetchNotebookList(id).subscribe((list) => {
-      this.allNotebookList = list;
-      console.log(this.allNotebookList);
-    });
-  }
-
-  /* (Future work. If we need a api for get all namespaces.)
-  getAllNamespaces() {
-    this.allNotebookList.forEach((element) => {
-      if (this.allNamespaceList.indexOf(element.spec.meta.namespace) < 0) {
-        this.allNamespaceList.push(element.spec.meta.namespace);
-      }
-    });
-  }
-  */
-
-  // Future work. If we have a api for get all namespaces.
-  /*
-  setDefaultTable() {
-    this.currentNamespace = this.allNamespaceList[0];
-    this.notebookTable = [];
-    this.allNotebookList.forEach((item) => {
-      if (item.spec.meta.namespace == this.currentNamespace) {
-        this.notebookTable.push(item);
-      }
-    });
-  }
-  */
-
-  // Future work. If we have a api for get all namespaces.
-  switchNamespace(namespace: string) {
-    this.notebookTable = [];
-    this.allNotebookList.forEach((item) => {
-      if (item.spec.meta.namespace == namespace) {
-        this.notebookTable.push(item);
-      }
-    });
-    console.log(this.notebookTable);
-  }
-
-  deleteNotebook(id: string) {
-    this.notebookService.deleteNotebook(id).subscribe(
-      () => {
-        this.updateNotebookTable(this.userId);
-      },
-      (err) => {
-        this.nzMessageService.error(err.message);
-      }
-    );
-  }
-
-  // Create or Delete, then update Notebook Table
-  updateNotebookTable(id: string) {
-    this.notebookService.fetchNotebookList(id).subscribe((list) => {
-      this.allNotebookList = list;
-      this.notebookTable = [];
-      this.allNotebookList.forEach((item) => {
-        if (item.spec.meta.namespace == this.currentNamespace) {
-          this.notebookTable.push(item);
-        }
-      });
-    });
+  // Init Form
+  initFormStatus() {
+    this.notebookName.reset();
+    this.envName.reset(this.envNameList[this.indexOfDeaultEnv]);
+    this.envVars.clear();
+    this.cpus.reset(1);
+    this.gpus.reset(0);
+    this.memoryNum.reset();
+    this.unit.reset(this.MEMORY_UNITS[0]);
   }
 
   get notebookName() {
@@ -209,42 +128,13 @@ export class NotebookComponent implements OnInit {
     return this.notebookForm.get('unit');
   }
 
-  // Init form when click create-btn
-  initNotebookStatus() {
-    this.isVisible = true;
-    this.notebookName.reset();
-    this.envName.reset(this.envNameList[this.indexOfDeaultEnv]);
-    this.envVars.clear();
-    this.cpus.reset(1);
-    this.gpus.reset(0);
-    this.memoryNum.reset();
-    this.unit.reset(this.MEMORY_UNITS[0]);
-  }
-
-  // Check form
-  checkStatus() {
-    return (
-      this.notebookName.invalid ||
-      this.envName.invalid ||
-      this.cpus.invalid ||
-      this.gpus.invalid ||
-      this.memoryNum.invalid ||
-      this.envVars.invalid
-    );
-  }
-
-  // Submmit
-  handleOk() {
-    this.createNotebookSpec();
-  }
-
   // EnvVars Form
   createEnvVar(defaultKey: string = '', defaultValue: string = '') {
     // Create a new FormGroup
     return new FormGroup(
       {
         key: new FormControl(defaultKey, [Validators.required]),
-        value: new FormControl(defaultValue, [Validators.required])
+        value: new FormControl(defaultValue, [Validators.required]),
       },
       [this.experimentValidatorService.envValidator]
     );
@@ -261,8 +151,20 @@ export class NotebookComponent implements OnInit {
     arr.removeAt(index);
   }
 
+  // Check form
+  checkStatus() {
+    return (
+      this.notebookName.invalid ||
+      this.envName.invalid ||
+      this.cpus.invalid ||
+      this.gpus.invalid ||
+      this.memoryNum.invalid ||
+      this.envVars.invalid
+    );
+  }
+
   // Develope submmit spec
-  createNotebookSpec() {
+  submitForm() {
     // Check GPU, then develope resources spec
     let resourceSpec;
     if (this.notebookForm.get('gpus').value === 0 || 
this.notebookForm.get('gpus').value == null) {
@@ -270,24 +172,25 @@ export class NotebookComponent implements OnInit {
         this.notebookForm.get('unit').value
       }`;
     } else {
-      resourceSpec = 
`cpu=${this.notebookForm.get('cpus').value},nvidia.com/gpu=${this.notebookForm.get('gpus').value},memory=${
-        this.notebookForm.get('memoryNum').value
-      }${this.notebookForm.get('unit').value}`;
+      resourceSpec = 
`cpu=${this.notebookForm.get('cpus').value},nvidia.com/gpu=${
+        this.notebookForm.get('gpus').value
+      
},memory=${this.notebookForm.get('memoryNum').value}${this.notebookForm.get('unit').value}`;
     }
+
     // Develope submmit spec
     const newNotebookSpec = {
       meta: {
         name: this.notebookForm.get('notebookName').value,
         namespace: 'default',
-        ownerId: this.userId
+        ownerId: this.userId,
       },
       environment: {
-        name: this.notebookForm.get('envName').value
+        name: this.notebookForm.get('envName').value,
       },
       spec: {
         envVars: {},
-        resources: resourceSpec
-      }
+        resources: resourceSpec,
+      },
     };
 
     for (const envVar of this.envVars.controls) {
@@ -296,34 +199,20 @@ export class NotebookComponent implements OnInit {
       }
     }
 
-    //console.log(newNotebookSpec);
-
     // Post
     this.notebookService.createNotebook(newNotebookSpec).subscribe({
-      next: (result) => {
-        this.fetchNotebookList(this.userId);
-      },
+      next: (result) => {},
       error: (msg) => {
         this.nzMessageService.error(`${msg}, please try again`, {
-          nzPauseOnHover: true
+          nzPauseOnHover: true,
         });
       },
       complete: () => {
+        this.nzMessageService.info(`Notebook Creating`, {
+          nzPauseOnHover: true,
+        });
         this.isVisible = false;
-      }
+      },
     });
   }
-
-  showReason(reason: string) {
-    this.nzNotificationService.blank(
-      'Notebook Status',
-      reason
-      );
-  }
-
-  // TODO(kobe860219): Make a notebook run
-  runNotebook() {}
-
-  // TODO(kobe860219): Stop a running notebook
-  stopNotebook() {}
 }
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-home.component.html
 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-home.component.html
new file mode 100644
index 0000000..e895d64
--- /dev/null
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-home.component.html
@@ -0,0 +1,38 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<div style="margin: 15px; padding: 15px; background-color: white">
+  <div align="right">
+    <button
+      nz-button
+      id="btn-newNotebook"
+      nzType="primary"
+      style="margin: 10px 4px 10px 4px"
+      (click)="form.initModal()"
+    >
+      <i nz-icon nzType="plus"></i>
+      New Notebook
+    </button>
+  </div>
+  <submarine-notebook-list
+    [notebookList]="notebookList"
+    (deleteNotebook)="onDeleteNotebook($event)"
+  ></submarine-notebook-list>
+  <submarine-notebook-form #form></submarine-notebook-form>
+</div>
diff --git 
a/submarine-workbench/workbench-web/src/app/interfaces/notebook-info.ts 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-home.component.scss
similarity index 74%
copy from submarine-workbench/workbench-web/src/app/interfaces/notebook-info.ts
copy to 
submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-home.component.scss
index 91a8d21..3d56d22 100644
--- a/submarine-workbench/workbench-web/src/app/interfaces/notebook-info.ts
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-home.component.scss
@@ -1,4 +1,4 @@
-/*
+/*!
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,17 +16,3 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import { Url } from 'url';
-import { NotebookSpec } from '@submarine/interfaces/notebook-spec';
-
-export interface Notebook {
-  notebookId: string;
-  name: string;
-  uid: string;
-  url: Url;
-  status: string;
-  createdTime: string;
-  deletedTime: string;
-  spec: NotebookSpec;
-}
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-home.component.ts
 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-home.component.ts
new file mode 100644
index 0000000..a19f74c
--- /dev/null
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-home.component.ts
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
+import { NotebookService } from 
'@submarine/services/notebook-services/notebook.service';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { UserService } from '@submarine/services/user.service';
+import { isEqual } from 'lodash';
+import { NotebookFormComponent } from 
'./notebook-form/notebook-form.component';
+import { interval, Subscription } from 'rxjs';
+import { mergeMap, timeout } from 'rxjs/operators';
+
+@Component({
+  selector: 'submarine-notebook-home',
+  templateUrl: './notebook-home.component.html',
+  styleUrls: ['./notebook-home.component.scss'],
+})
+export class NotebookHomeComponent implements OnInit, OnDestroy {
+  // User Information
+  userId;
+
+  // Notebook list
+  notebookList;
+
+  subscribtions = new Subscription();
+
+  @ViewChild('form', { static: true }) form: NotebookFormComponent;
+
+  constructor(
+    private notebookService: NotebookService,
+    private nzMessageService: NzMessageService,
+    private userService: UserService
+  ) {}
+
+  ngOnInit() {
+    this.userService.fetchUserInfo().subscribe((res) => {
+      this.userId = res.id;
+    });
+
+    const resourceSub = interval(1000).subscribe(() => {
+      this.notebookService.fetchNotebookList(this.userId).subscribe((res) => {
+        if (!isEqual(this.notebookList, res)) {
+          this.notebookList = res;
+        }
+      });
+    });
+
+    this.subscribtions.add(resourceSub);
+  }
+
+  ngOnDestroy() {
+    this.subscribtions.unsubscribe();
+  }
+
+  onDeleteNotebook(id: string) {
+    this.notebookService.deleteNotebook(id).subscribe({
+      next: (result) => {},
+      error: (msg) => {
+        this.nzMessageService.error(`${msg}, please try again`, {
+          nzPauseOnHover: true,
+        });
+      },
+      complete: () => {
+        this.nzMessageService.info(`Delete Notebook...`, {
+          nzPauseOnHover: true,
+        });
+      },
+    });
+  }
+}
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-list/notebook-list.component.html
 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-list/notebook-list.component.html
new file mode 100644
index 0000000..5a84233
--- /dev/null
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-list/notebook-list.component.html
@@ -0,0 +1,77 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<nz-table id="notebookListTable" style="padding-top: 5px" #basicTable 
[nzData]="notebookList" [nzNoResult]="'No data'">
+  <thead>
+    <tr>
+      <th></th>
+      <th>Name</th>
+      <th>Environment</th>
+      <th>Docker Image</th>
+      <th>Resources</th>
+      <th>Status</th>
+      <th>Action</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr *ngFor="let data of basicTable.data; let i = index">
+      <td *ngIf="data.status === 'running'">
+        <i
+          nz-icon
+          [nzType]="'check-circle'"
+          [nzTheme]="'twotone'"
+          [nzTwotoneColor]="'#52c41a'"
+          style="color: #08c; font-size: 24px"
+        ></i>
+      </td>
+      <td *ngIf="data.status !== 'running'">
+        <i nz-icon nzType="loading" nzTheme="outline" style="color: #08c; 
font-size: 24px"></i>
+      </td>
+      <td *ngIf="data.status === 'running'">
+        <a href="{{ data.url }}" target="_blank">{{ data.name }}</a>
+      </td>
+      <td *ngIf="data.status !== 'running'">
+        {{ data.name }}
+      </td>
+      <td>{{ data.spec.environment.name }}</td>
+      <td>{{ data.spec.environment.dockerImage }}</td>
+      <td>
+        {{ data.spec.spec.resources }}
+      </td>
+      <td>
+        <a (click)="showReason(data.reason)">
+          <nz-tag [nzColor]="statusColor[data.status]">{{ data.status 
}}</nz-tag>
+        </a>
+      </td>
+      <td>
+        <a
+          id="btn-deleteNotebook{{ i }}"
+          nz-popconfirm
+          nzPlacement="left"
+          nzTitle="Are you sure you want to delete?"
+          nzCancelText="Cancel"
+          nzOkText="Ok"
+          (nzOnConfirm)="onDeleteNotebook(data.notebookId)"
+        >
+          Delete
+        </a>
+      </td>
+    </tr>
+  </tbody>
+</nz-table>
diff --git 
a/submarine-workbench/workbench-web/src/app/interfaces/notebook-info.ts 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-list/notebook-list.component.scss
similarity index 74%
rename from 
submarine-workbench/workbench-web/src/app/interfaces/notebook-info.ts
rename to 
submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-list/notebook-list.component.scss
index 91a8d21..3d56d22 100644
--- a/submarine-workbench/workbench-web/src/app/interfaces/notebook-info.ts
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-list/notebook-list.component.scss
@@ -1,4 +1,4 @@
-/*
+/*!
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,17 +16,3 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import { Url } from 'url';
-import { NotebookSpec } from '@submarine/interfaces/notebook-spec';
-
-export interface Notebook {
-  notebookId: string;
-  name: string;
-  uid: string;
-  url: Url;
-  status: string;
-  createdTime: string;
-  deletedTime: string;
-  spec: NotebookSpec;
-}
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-list/notebook-list.component.ts
 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-list/notebook-list.component.ts
new file mode 100644
index 0000000..4cb5617
--- /dev/null
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-home/notebook-list/notebook-list.component.ts
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { NotebookInfo } from 
'@submarine/interfaces/notebook-interfaces/notebook-info';
+import { NzNotificationService } from 'ng-zorro-antd/notification';
+
+@Component({
+  selector: 'submarine-notebook-list',
+  templateUrl: './notebook-list.component.html',
+  styleUrls: ['./notebook-list.component.scss'],
+})
+export class NotebookListComponent implements OnInit {
+  constructor(private nzNotificationService: NzNotificationService) {}
+
+  @Input() notebookList: NotebookInfo[];
+
+  @Output() deleteNotebook = new EventEmitter<string>();
+
+  statusColor: { [key: string]: string } = {
+    creating: 'gold',
+    waiting: 'gold',
+    running: 'green',
+    terminating: 'blue',
+  };
+
+  ngOnInit() {}
+
+  showReason(reason: string) {
+    this.nzNotificationService.blank('Notebook Status', reason);
+  }
+
+  onDeleteNotebook(id: string) {
+    this.deleteNotebook.emit(id);
+  }
+}
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.module.ts
 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-routing.module.ts
similarity index 66%
copy from 
submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.module.ts
copy to 
submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-routing.module.ts
index 06996b9..6ad2d7d 100644
--- 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.module.ts
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook-routing.module.ts
@@ -17,16 +17,27 @@
  * under the License.
  */
 
-import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { NotebookHomeComponent } from 
'./notebook-home/notebook-home.component';
 import { NotebookComponent } from './notebook.component';
-import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { NgZorroAntdModule } from 'ng-zorro-antd';
-import { PipeSharedModule } from '@submarine/pipe/pipe-shared.module';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: NotebookComponent,
+    children: [
+      {
+        path: '',
+        pathMatch: 'full',
+        component: NotebookHomeComponent,
+      },
+    ],
+  },
+];
 
 @NgModule({
-  declarations: [NotebookComponent],
-  exports: [NotebookComponent],
-  imports: [CommonModule, FormsModule, ReactiveFormsModule, NgZorroAntdModule, 
PipeSharedModule]
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
 })
-export class NotebookModule {}
+export class NotebookRoutingModule {}
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.html
 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.html
index 9e7d814..f430035 100644
--- 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.html
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.html
@@ -16,218 +16,22 @@
   ~ specific language governing permissions and limitations
   ~ under the License.
   -->
-
-<nz-layout style="margin: -24px -24px 16px;">
-  <nz-layout class="inner-layout">
-    <div id="notebookOuter">
-      <nz-breadcrumb>
-        <nz-breadcrumb-item>
-          <!--<a [routerLink]="['/', 'workbench', 'home']">Home</a>-->
-          <a>Home</a>
-        </nz-breadcrumb-item>
-        <nz-breadcrumb-item>
-          <a [routerLink]="['/', 'workbench', 'notebook']">Notebook</a>
-        </nz-breadcrumb-item>
-      </nz-breadcrumb>
-      <div>
-        <br />
-        <h2>Notebook</h2>
-        <nz-content>Apache submarine support jupyter notebook.</nz-content>
-        <br />
-      </div>
-    </div>
-  </nz-layout>
-  <div id="notebookDiv">
-    <div nz-row>
-      <div nz-col nzSpan="12">
-        <h2>Notebook List</h2>
-        <!--
-        <label style="font-size: large; color: black;">Namespaces :</label>
-        <nz-select disabled="disabled" style="margin-left: 5px; width: 240px;" 
[(ngModel)]="currentNamespace">
-          <nz-option [nzValue]="currentNamespace" 
[nzLabel]="currentNamespace"></nz-option>
-        </nz-select>
-        -->
-      </div>
-      <div nz-col nzSpan="12" align="right">
-        <nz-input-group nzSearch style="width: 300px; margin-right: 5px;" 
[nzAddOnAfter]="suffixIconButton">
-          <input type="text" nz-input id="searchInput" placeholder="input 
search text" />
-        </nz-input-group>
-        <ng-template #suffixIconButton>
-          <button nz-button nzType="primary" nzSearch><i nz-icon 
nzType="search"></i></button>
-        </ng-template>
-        <button
-          id="btnNewNotebook"
-          nz-button
-          nzType="primary"
-          style="margin-right: 5px;"
-          (click)="initNotebookStatus()"
-        >
-          <i nz-icon nzType="plus"></i>
-          New Notebook
-        </button>
-      </div>
-    </div>
+<nz-layout style="margin: -24px -24px 16px">
+  <div style="background-color: white; padding-left: 30px; padding-top: 20px">
+    <nz-breadcrumb>
+      <nz-breadcrumb-item>
+        <a>Home</a>
+      </nz-breadcrumb-item>
+      <nz-breadcrumb-item>
+        <a [routerLink]="['/', 'workbench', 'notebook']">notebook</a>
+      </nz-breadcrumb-item>
+    </nz-breadcrumb>
     <div>
-      <nz-table id="notebookListTable" style="padding-top: 5px;" #basicTable 
[nzData]="allNotebookList">
-        <thead>
-          <tr>
-            <th></th>
-            <th>Name</th>
-            <th>Environment</th>
-            <th>Docker Image</th>
-            <th>Resources</th>
-            <th>Status</th>
-            <th>Action</th>
-          </tr>
-        </thead>
-        <tbody>
-          <tr *ngFor="let data of basicTable.data; let i = index">
-            <td *ngIf="data.status === 'running'">
-              <i
-                nz-icon
-                [nzType]="'check-circle'" 
-                [nzTheme]="'twotone'" 
-                [nzTwotoneColor]="'#52c41a'"
-                style="color: #08c; font-size: 24px;">
-              </i>
-            </td>
-            <td *ngIf="data.status !== 'running'">
-              <i 
-                nz-icon 
-                nzType="loading" 
-                nzTheme="outline" 
-                style="color: #08c; font-size: 24px;">
-              </i>
-            </td>
-            <td *ngIf="data.status === 'running'">
-              <a href="{{ data.url }}" target="_blank">{{ data.name }}</a>
-            </td>
-            <td *ngIf="data.status !== 'running'">
-              {{ data.name }}
-            </td>
-            <td>{{ data.spec.environment.name }}</td>
-            <td>{{ data.spec.environment.dockerImage }}</td>
-            <td>
-              {{ data.spec.spec.resources }}
-            </td>
-            <td>
-              <a (click)=showReason(data.reason)>{{ data.status }}</a>
-            </td>
-            <td>
-              <a id="delete{{ i }}" 
(click)="deleteNotebook(data.notebookId)">Delete</a></td>
-          </tr>
-        </tbody>
-      </nz-table>
+      <br />
+      <h2>Notebook</h2>
+      <nz-content>Apache submarine support jupyter notebook.</nz-content>
     </div>
+    <br />
   </div>
+  <router-outlet></router-outlet>
 </nz-layout>
-
-<nz-modal
-  [(nzVisible)]="isVisible"
-  nzTitle="Create Notebook"
-  [(nzOkText)]="okText"
-  (nzOnCancel)="isVisible = false"
-  [nzWidth]="700"
->
-  <form nz-form [formGroup]="notebookForm" nzLayout="horizontal">
-    <div *nzModalFooter>
-      <button nz-button nzType="default" (click)="isVisible = 
false">Cancel</button>
-      <button id="create-btn" nz-button nzType="primary" 
[disabled]="checkStatus()" (click)="handleOk()">
-        Create
-      </button>
-    </div>
-    <nz-form-item>
-        <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="notebookName">
-          Notebook Name
-        </nz-form-label>
-        <nz-form-control [nzSm]="14" [nzXs]="24">
-          <input nz-input required type="text" name="notebookName" 
id="notebookName" formControlName="notebookName" />
-        </nz-form-control>
-    </nz-form-item>
-    <nz-form-item>
-      <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="environment">
-        Environment
-      </nz-form-label>
-      <nz-form-control [nzSm]="14" [nzXs]="24">
-        <nz-select required name="select-envName" formControlName="envName">
-          <nz-option
-            *ngFor="let env of envNameList; let i; of: index"
-            id="env{{ i }}"
-            [nzValue]="env"
-            [nzLabel]="env"
-          ></nz-option>
-        </nz-select>
-      </nz-form-control>
-    </nz-form-item>
-    <nz-form-item>
-      <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="cpus">
-        CPU
-      </nz-form-label>
-      <nz-form-control [nzSm]="14" [nzXs]="24">
-        <input nz-input min="0" required type="number" name="cpus" id="cpus" 
formControlName="cpus" />
-      </nz-form-control>
-    </nz-form-item>
-    <nz-form-item>
-      <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="gpus">
-        GPU
-      </nz-form-label>
-      <nz-form-control [nzSm]="14" [nzXs]="24">
-        <input nz-input min="0" type="number" name="gpus" id="gpus" 
formControlName="gpus" />
-      </nz-form-control>
-    </nz-form-item>
-    <nz-form-item>
-      <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="memoryNum">
-        Memory
-      </nz-form-label>
-      <nz-form-control [nzSm]="14" [nzXs]="24">
-        <div nz-col nzSpan="6">
-        <input nz-input required name="memoryNum" placeholder="EX:1024" 
formControlName="memoryNum" />
-        </div>
-        <div nz-col nzSpan="6" style="margin-left: 5px;">
-          <nz-select formControlName="unit">
-            <nz-option *ngFor="let unit of MEMORY_UNITS" [nzValue]="unit" 
[nzLabel]="unit"></nz-option>
-          </nz-select>
-        </div>
-      </nz-form-control>
-    </nz-form-item>
-    <div formArrayName="envVars">
-      <ng-container *ngFor="let envVar of envVars.controls; index as i">
-        <nz-form-item>
-        <nz-form-label nzRequired [nzSm]="6" [nzXs]="24">EnvVar{{ i+1 
}}</nz-form-label>
-        <div [formGroupName]="i">
-          <div nz-col nzSpan="12">
-            <input
-              style="width: 30%;"
-              nz-input
-              required
-              id="key{{ i }}"
-              name="key{{ i }}"
-              placeholder="Key"
-              formControlName="key"
-            />
-            <input
-              style="width: 60%; margin-left: 10px;"
-              nz-input
-              required
-              id="value{{ i }}"
-              name="value{{ i }}"
-              placeholder="Value"
-              formControlName="value"
-            />
-            <i
-              nz-icon
-              style="margin-left: 5px;"
-              nzType="close-circle"
-              nzTheme="fill"
-              (click)="deleteItem(envVars, i)"
-            ></i>
-          </div>
-        </div>
-      </nz-form-item>
-      </ng-container>
-    </div>
-    <button nz-button style="display: block; margin: auto;" id="envVar-btn" 
type="default" (click)="onCreateEnvVar()">
-      New EnvVar
-    </button>
-  </form>
-</nz-modal>
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.scss
 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.scss
index 68e727f..3d56d22 100644
--- 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.scss
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.scss
@@ -16,52 +16,3 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-#notebookOuter{
-    background-color: white;
-    padding-left: 30px;
-    padding-top: 20px;
- }
-
- #notebookDiv{
-     margin: 10px;
-     background-color: white;
-     padding: 10px;
-     overflow: auto;
- }
-
- .red-star {
-     color: red;
- }
-
- .newNotebookForm {
-   display: flex;
-   align-items: center;
-   margin-bottom: 1.5rem;
-   & label {
-      flex: 0 0 25%;
-      text-align: right;
-      font-weight: 500;
-      &:not(:last-child) {
-         margin-right: 1.5rem;
-      }
-   }
-   & input {
-      flex: 0 0 48%;
-   }
-
-   & nz-select {
-      flex: 0 0 48%;
-   }
- }
-
- .memory-input-group {
-   display: flex;
-   & input {
-      width: 70%;
-   }
-
-   & > * {
-      width: 30%;
-   }
-}
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.ts
 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.ts
index e0d1533..6e3a11e 100644
--- 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.ts
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.component.ts
@@ -18,312 +18,14 @@
  */
 
 import { Component, OnInit } from '@angular/core';
-import { FormArray, FormControl, FormGroup, Validators, FormBuilder } from 
'@angular/forms';
-import { NotebookService } from '@submarine/services/notebook.service';
-import { NzMessageService } from 'ng-zorro-antd/message';
-import { EnvironmentService } from '@submarine/services/environment.service';
-import { ExperimentValidatorService } from 
'@submarine/services/experiment.validator.service';
-import { UserService } from '@submarine/services/user.service';
-import { nullSafeIsEquivalent } from '@angular/compiler/src/output/output_ast';
-import { Subscription } from 'rxjs';
-import { ExponentialBackoff } from '@submarine/services/polling';
-import { isEqual } from "lodash";
-import { NzNotificationService } from 'ng-zorro-antd/notification';
 
 @Component({
   selector: 'submarine-notebook',
   templateUrl: './notebook.component.html',
-  styleUrls: ['./notebook.component.scss']
+  styleUrls: ['./notebook.component.scss'],
 })
 export class NotebookComponent implements OnInit {
-  // Environment
-  envList;
-  envNameList = [];
-  indexOfDeaultEnv;
+  constructor() {}
 
-  // Namesapces
-  allNamespaceList = [];
-  currentNamespace;
-
-  // Notebook list
-  allNotebookList;
-  notebookTable;
-
-  // New Notebook Form
-  notebookForm: FormGroup;
-  isVisible = false;
-  MEMORY_UNITS = ['M', 'Gi'];
-
-  // User Information
-  userId;
-
-  // Sync //
-  // Subscription
-  subscriptions = new Subscription();
-  // Poller
-  poller: ExponentialBackoff;
-
-  constructor(
-    private notebookService: NotebookService,
-    private nzMessageService: NzMessageService,
-    private environmentService: EnvironmentService,
-    private experimentValidatorService: ExperimentValidatorService,
-    private userService: UserService,
-    private fb: FormBuilder,
-    private nzNotificationService: NzNotificationService
-  ) {}
-
-  ngOnInit() {
-    this.poller = new ExponentialBackoff({ interval: 1000, retries: 3 });
-    const resourcesSub = this.poller.start().subscribe(() => {
-      this.userService.fetchUserInfo().subscribe((res) => {
-        this.userId = res.id;
-        
this.notebookService.fetchNotebookList(this.userId).subscribe(resources => {
-          if (!isEqual(this.allNotebookList, resources)) {
-            this.allNotebookList = resources;
-            this.poller.reset();
-          }
-        });
-      });
-    });
-    
-    this.subscriptions.add(resourcesSub);
-
-    this.notebookForm = this.fb.group({
-      notebookName: [null, [
-        Validators.maxLength(63),
-        Validators.pattern('^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$'),
-        Validators.required]],
-      envName: [null, Validators.required], // Environment
-      envVars: this.fb.array([], 
[this.experimentValidatorService.nameValidatorFactory('key')]),
-      cpus: [null, [Validators.min(1), Validators.required]],
-      gpus: [null],
-      memoryNum: [null, [Validators.required]],
-      unit: [this.MEMORY_UNITS[0], [Validators.required]]
-    });
-    this.fetchEnvList();
-  }
-
-  ngOnDestroy() {
-    this.subscriptions.unsubscribe();
-  }
-
-  // Get all environment
-  fetchEnvList() {
-    this.environmentService.fetchEnvironmentList().subscribe((list) => {
-      this.envList = list;
-      this.envList.forEach((env) => {
-        if (this.envNameList.indexOf(env.environmentSpec.name) < 0) {
-          this.envNameList.push(env.environmentSpec.name);
-        }
-      });
-      this.indexOfDeaultEnv = this.envNameList.indexOf('notebook-env');
-    });
-  }
-
-  // Get all notebooks, then set default namespace.
-  fetchNotebookList(id: string) {
-    this.notebookService.fetchNotebookList(id).subscribe((list) => {
-      this.allNotebookList = list;
-      console.log(this.allNotebookList);
-    });
-  }
-
-  /* (Future work. If we need a api for get all namespaces.)
-  getAllNamespaces() {
-    this.allNotebookList.forEach((element) => {
-      if (this.allNamespaceList.indexOf(element.spec.meta.namespace) < 0) {
-        this.allNamespaceList.push(element.spec.meta.namespace);
-      }
-    });
-  }
-  */
-
-  // Future work. If we have a api for get all namespaces.
-  /*
-  setDefaultTable() {
-    this.currentNamespace = this.allNamespaceList[0];
-    this.notebookTable = [];
-    this.allNotebookList.forEach((item) => {
-      if (item.spec.meta.namespace == this.currentNamespace) {
-        this.notebookTable.push(item);
-      }
-    });
-  }
-  */
-
-  // Future work. If we have a api for get all namespaces.
-  switchNamespace(namespace: string) {
-    this.notebookTable = [];
-    this.allNotebookList.forEach((item) => {
-      if (item.spec.meta.namespace == namespace) {
-        this.notebookTable.push(item);
-      }
-    });
-    console.log(this.notebookTable);
-  }
-
-  deleteNotebook(id: string) {
-    this.notebookService.deleteNotebook(id).subscribe(
-      () => {
-        this.updateNotebookTable(this.userId);
-      },
-      (err) => {
-        this.nzMessageService.error(err.message);
-      }
-    );
-  }
-
-  // Create or Delete, then update Notebook Table
-  updateNotebookTable(id: string) {
-    this.notebookService.fetchNotebookList(id).subscribe((list) => {
-      this.allNotebookList = list;
-      this.notebookTable = [];
-      this.allNotebookList.forEach((item) => {
-        if (item.spec.meta.namespace == this.currentNamespace) {
-          this.notebookTable.push(item);
-        }
-      });
-    });
-  }
-
-  get notebookName() {
-    return this.notebookForm.get('notebookName');
-  }
-  get envName() {
-    return this.notebookForm.get('envName');
-  }
-  get envVars() {
-    return this.notebookForm.get('envVars') as FormArray;
-  }
-  get cpus() {
-    return this.notebookForm.get('cpus');
-  }
-  get gpus() {
-    return this.notebookForm.get('gpus');
-  }
-  get memoryNum() {
-    return this.notebookForm.get('memoryNum');
-  }
-  get unit() {
-    return this.notebookForm.get('unit');
-  }
-
-  // Init form when click create-btn
-  initNotebookStatus() {
-    this.isVisible = true;
-    this.notebookName.reset();
-    this.envName.reset(this.envNameList[this.indexOfDeaultEnv]);
-    this.envVars.clear();
-    this.cpus.reset(1);
-    this.gpus.reset(0);
-    this.memoryNum.reset();
-    this.unit.reset(this.MEMORY_UNITS[0]);
-  }
-
-  // Check form
-  checkStatus() {
-    return (
-      this.notebookName.invalid ||
-      this.envName.invalid ||
-      this.cpus.invalid ||
-      this.gpus.invalid ||
-      this.memoryNum.invalid ||
-      this.envVars.invalid
-    );
-  }
-
-  // Submmit
-  handleOk() {
-    this.createNotebookSpec();
-  }
-
-  // EnvVars Form
-  createEnvVar(defaultKey: string = '', defaultValue: string = '') {
-    // Create a new FormGroup
-    return new FormGroup(
-      {
-        key: new FormControl(defaultKey, [Validators.required]),
-        value: new FormControl(defaultValue, [Validators.required])
-      },
-      [this.experimentValidatorService.envValidator]
-    );
-  }
-
-  // EnvVars Form
-  onCreateEnvVar() {
-    const env = this.createEnvVar();
-    this.envVars.push(env);
-  }
-
-  // Delete item in EnvVars Form
-  deleteItem(arr: FormArray, index: number) {
-    arr.removeAt(index);
-  }
-
-  // Develope submmit spec
-  createNotebookSpec() {
-    // Check GPU, then develope resources spec
-    let resourceSpec;
-    if (this.notebookForm.get('gpus').value === 0 || 
this.notebookForm.get('gpus').value == null) {
-      resourceSpec = 
`cpu=${this.notebookForm.get('cpus').value},memory=${this.notebookForm.get('memoryNum').value}${
-        this.notebookForm.get('unit').value
-      }`;
-    } else {
-      resourceSpec = 
`cpu=${this.notebookForm.get('cpus').value},nvidia.com/gpu=${this.notebookForm.get('gpus').value},memory=${
-        this.notebookForm.get('memoryNum').value
-      }${this.notebookForm.get('unit').value}`;
-    }
-    // Develope submmit spec
-    const newNotebookSpec = {
-      meta: {
-        name: this.notebookForm.get('notebookName').value,
-        namespace: 'default',
-        ownerId: this.userId
-      },
-      environment: {
-        name: this.notebookForm.get('envName').value
-      },
-      spec: {
-        envVars: {},
-        resources: resourceSpec
-      }
-    };
-
-    for (const envVar of this.envVars.controls) {
-      if (envVar.get('key').value) {
-        newNotebookSpec.spec.envVars[envVar.get('key').value] = 
envVar.get('value').value;
-      }
-    }
-
-    //console.log(newNotebookSpec);
-
-    // Post
-    this.notebookService.createNotebook(newNotebookSpec).subscribe({
-      next: (result) => {
-        this.fetchNotebookList(this.userId);
-      },
-      error: (msg) => {
-        this.nzMessageService.error(`${msg}, please try again`, {
-          nzPauseOnHover: true
-        });
-      },
-      complete: () => {
-        this.isVisible = false;
-      }
-    });
-  }
-
-  showReason(reason: string) {
-    this.nzNotificationService.blank(
-      'Notebook Status',
-      reason
-      );
-  }
-
-  // TODO(kobe860219): Make a notebook run
-  runNotebook() {}
-
-  // TODO(kobe860219): Stop a running notebook
-  stopNotebook() {}
+  ngOnInit() {}
 }
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.module.ts
 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.module.ts
index 06996b9..9985e96 100644
--- 
a/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.module.ts
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/notebook/notebook.module.ts
@@ -19,14 +19,30 @@
 
 import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
-import { NotebookComponent } from './notebook.component';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { NgZorroAntdModule } from 'ng-zorro-antd';
+import { RouterModule } from '@angular/router';
 import { PipeSharedModule } from '@submarine/pipe/pipe-shared.module';
+import { NotebookService } from 
'@submarine/services/notebook-services/notebook.service';
+import { NgZorroAntdModule } from 'ng-zorro-antd';
+import { NotebookRoutingModule } from './notebook-routing.module';
+
+import { NotebookComponent } from './notebook.component';
+import { NotebookHomeComponent } from 
'./notebook-home/notebook-home.component';
+import { NotebookListComponent } from 
'./notebook-home/notebook-list/notebook-list.component';
+import { NotebookFormComponent } from 
'./notebook-home/notebook-form/notebook-form.component';
 
 @NgModule({
-  declarations: [NotebookComponent],
+  imports: [
+    CommonModule,
+    FormsModule,
+    ReactiveFormsModule,
+    RouterModule,
+    PipeSharedModule,
+    NgZorroAntdModule,
+    NotebookRoutingModule,
+  ],
+  providers: [NotebookService],
+  declarations: [NotebookComponent, NotebookHomeComponent, 
NotebookListComponent, NotebookFormComponent],
   exports: [NotebookComponent],
-  imports: [CommonModule, FormsModule, ReactiveFormsModule, NgZorroAntdModule, 
PipeSharedModule]
 })
 export class NotebookModule {}
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/workbench-routing.module.ts
 
b/submarine-workbench/workbench-web/src/app/pages/workbench/workbench-routing.module.ts
index bc838b1..a0aa0cd 100644
--- 
a/submarine-workbench/workbench-web/src/app/pages/workbench/workbench-routing.module.ts
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/workbench-routing.module.ts
@@ -25,7 +25,6 @@ import { DataComponent } from './data/data.component';
 import { HomeComponent } from './home/home.component';
 import { InterpreterComponent } from './interpreter/interpreter.component';
 import { ModelComponent } from './model/model.component';
-import { NotebookComponent } from './notebook/notebook.component';
 import { WorkspaceComponent } from './workspace/workspace.component';
 
 const routes: Routes = [
@@ -75,7 +74,7 @@ const routes: Routes = [
       },
       {
         path: 'notebook',
-        component: NotebookComponent,
+        loadChildren: () => import('./notebook/notebook.module').then((m) => 
m.NotebookModule),
         canActivate: ['canActivatePage'],
       },
       {
diff --git 
a/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.module.ts 
b/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.module.ts
index 908b48d..248eaef 100644
--- 
a/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.module.ts
+++ 
b/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.module.ts
@@ -24,17 +24,17 @@ import { RouterModule } from '@angular/router';
 import { WorkbenchRoutingModule } from 
'@submarine/pages/workbench/workbench-routing.module';
 import { PipeSharedModule } from '@submarine/pipe/pipe-shared.module';
 import { NgZorroAntdModule } from 'ng-zorro-antd';
-import { DataComponent } from './data/data.component';
+import { WorkspaceModule } from './workspace/workspace.module';
 import { ExperimentModule } from './experiment/experiment.module';
+import { InterpreterModule } from './interpreter/interpreter.module';
+import { NotebookModule } from './notebook/notebook.module';
 
 import { HomeComponent } from './home/home.component';
-import { InterpreterModule } from './interpreter/interpreter.module';
 import { ModelComponent } from './model/model.component';
 import { WorkbenchComponent } from './workbench.component';
 import { WorkspaceComponent } from './workspace/workspace.component';
-import { WorkspaceModule } from './workspace/workspace.module';
 import { EnvironmentComponent } from './environment/environment.component';
-import { NotebookComponent } from './notebook/notebook.component';
+import { DataComponent } from './data/data.component';
 
 @NgModule({
   declarations: [
@@ -43,8 +43,7 @@ import { NotebookComponent } from 
'./notebook/notebook.component';
     WorkspaceComponent,
     DataComponent,
     ModelComponent,
-    EnvironmentComponent,
-    NotebookComponent
+    EnvironmentComponent
   ],
   imports: [
     CommonModule,
@@ -56,7 +55,8 @@ import { NotebookComponent } from 
'./notebook/notebook.component';
     WorkspaceModule,
     ExperimentModule,
     InterpreterModule,
-    PipeSharedModule
+    PipeSharedModule,
+    NotebookModule
   ]
 })
 export class WorkbenchModule { }
diff --git 
a/submarine-workbench/workbench-web/src/app/services/notebook.service.ts 
b/submarine-workbench/workbench-web/src/app/services/notebook-services/notebook.service.ts
similarity index 80%
rename from 
submarine-workbench/workbench-web/src/app/services/notebook.service.ts
rename to 
submarine-workbench/workbench-web/src/app/services/notebook-services/notebook.service.ts
index 880b538..c273718 100644
--- a/submarine-workbench/workbench-web/src/app/services/notebook.service.ts
+++ 
b/submarine-workbench/workbench-web/src/app/services/notebook-services/notebook.service.ts
@@ -23,17 +23,18 @@ import { Rest } from '@submarine/interfaces';
 import { BaseApiService } from '@submarine/services/base-api.service';
 import { of, throwError, Observable } from 'rxjs';
 import { catchError, map, switchMap } from 'rxjs/operators';
-import { Notebook } from '@submarine/interfaces/notebook-info';
+import { NotebookInfo } from 
'@submarine/interfaces/notebook-interfaces/notebook-info';
+import { NotebookSpec } from 
'@submarine/interfaces/notebook-interfaces/notebook-spec';
 
 @Injectable({
-  providedIn: 'root'
+  providedIn: 'root',
 })
 export class NotebookService {
   constructor(private baseApi: BaseApiService, private httpClient: HttpClient) 
{}
 
-  fetchNotebookList(id: string) {
+  fetchNotebookList(id: string): Observable<NotebookInfo[]> {
     const apiUrl = this.baseApi.getRestApi('/v1/notebook?id=' + id);
-    return this.httpClient.get<Rest<Notebook>>(apiUrl).pipe(
+    return this.httpClient.get<Rest<NotebookInfo[]>>(apiUrl).pipe(
       switchMap((res) => {
         if (res.success) {
           return of(res.result);
@@ -44,9 +45,9 @@ export class NotebookService {
     );
   }
 
-  createNotebook(newNotebook: object): Observable<Notebook> {
+  createNotebook(notebookSpec: object): Observable<NotebookSpec> {
     const apiUrl = this.baseApi.getRestApi('/v1/notebook');
-    return this.httpClient.post<Rest<Notebook>>(apiUrl, newNotebook).pipe(
+    return this.httpClient.post<Rest<NotebookSpec>>(apiUrl, notebookSpec).pipe(
       map((res) => res.result), // return result directly if succeeding
       catchError((e) => {
         let message: string;
@@ -68,9 +69,9 @@ export class NotebookService {
     );
   }
 
-  deleteNotebook(id: string): Observable<Notebook> {
+  deleteNotebook(id: string): Observable<NotebookInfo> {
     const apiUrl = this.baseApi.getRestApi(`/v1/notebook/${id}`);
-    return this.httpClient.delete<Rest<Notebook>>(apiUrl).pipe(
+    return this.httpClient.delete<Rest<NotebookInfo>>(apiUrl).pipe(
       switchMap((res) => {
         if (res.success) {
           return of(res.result);
diff --git a/submarine-workbench/workbench-web/src/app/services/polling.ts 
b/submarine-workbench/workbench-web/src/app/services/polling.ts
deleted file mode 100644
index 1a9a4a4..0000000
--- a/submarine-workbench/workbench-web/src/app/services/polling.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
- import { Subscription, Subject, interval, timer } from "rxjs";
-
- export interface BackoffConfig {
-     retries?: number;
-     interval?: number;
-     maxInterval?: number;
- }
-
- const defaultConfig: BackoffConfig = {
-     retries: 1,
-     interval: 1000,
-     maxInterval: 16000
- }
-
- export class ExponentialBackoff {
-     private retries: number;
-     private interval: number;
-     private maxInterval: number;
-
-     private scheduler: Subscription;
-     private poller: Subject<number>;
-     private n: number;
-     
-     private remainingTries: number;
-     private currInterval: number;
-
-     constructor(config: BackoffConfig = defaultConfig) {
-         const conf = { ...defaultConfig, ...config };
-
-         this.retries = conf.retries;
-         this.interval = conf.interval;
-         this.maxInterval = conf.maxInterval;
-
-         this.poller = new Subject<number>();
-
-         this.n = 0;
-         this.remainingTries = this.retries + 1;
-         this.currInterval = this.interval;
-     }
-
-     public start() {
-         if(this.scheduler) {
-             this.scheduler.unsubscribe();
-         }
-
-         this.scheduler = timer(0, this.interval).subscribe(() => {
-             this.iterate();
-         });
-
-         return this.poller;
-     }
-
-     private iterate() {
-        this.n++;
-        this.poller.next(this.n);
-
-        this.scheduler.unsubscribe();
-        this.remainingTries--;
-        if (this.remainingTries === 0) {
-            this.remainingTries = this.retries;
-            this.currInterval = Math.min(this.currInterval * 2, 
this.maxInterval);
-        }
-
-        this.scheduler = interval(this.currInterval).subscribe(() => {
-            this.iterate();
-        });
-    }
-
-    public reset() {
-        this.n = 0;
-        this.currInterval = this.interval;
-        this.remainingTries = this.retries + 1;
-
-        this.start();
-    }
-
-    public stop() {
-        if (this.scheduler) {
-            this.scheduler.unsubscribe();
-        }
-    }
-
-    public getPoller() {
-        return this.poller;
-    }
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to