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/11 10:11:07 UTC
[submarine] branch master updated: SUBMARINE-607. [WEB] Create and
Delete of notebook instances
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 e73377d SUBMARINE-607. [WEB] Create and Delete of notebook instances
e73377d is described below
commit e73377d149754729e9613bab7d1f43cbd74cc2a1
Author: kobe860219 <ko...@gmail.com>
AuthorDate: Thu Sep 10 15:25:11 2020 +0800
SUBMARINE-607. [WEB] Create and Delete of notebook instances
### What is this PR for?
Make WEB UI support create/delete notebook instances.
### What type of PR is it?
[ Feature]
### Todos
### What is the Jira issue?
https://issues.apache.org/jira/browse/SUBMARINE-607
### How should this be tested?
https://travis-ci.org/github/kobe860219/submarine/builds/724836645
### Screenshots (if appropriate)
![螢幕錄製 2020-09-07 下午4](https://user-images.githubusercontent.com/48027290/92365878-04840180-f127-11ea-9395-5c8f4e2369b7.gif)
![螢幕錄製 2020-09-10 下午3](https://user-images.githubusercontent.com/48027290/92694709-0560a180-f37a-11ea-9c21-462189be9545.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 #395 from kobe860219/SUBMARINE-607 and squashes the following commits:
666e7ec [kobe860219] SUBMARINE-607. [WEB] Create and Delete of notebook instances
1e14996 [kobe860219] [WEB] Create and Delete of notebook instances
dc8a3b1 [kobe860219] [WEB] Create and Delete of notebook instances
4f6ba3d [kobe860219] [WEB] Create and Delete of notebook instances
43dd052 [kobe860219] [WEB] Create and Delete of notebook instances
e4805b6 [kobe860219] Delete Done
---
.../src/app/interfaces/notebook-spec.ts | 12 +-
.../workbench/notebook/notebook.component.html | 121 +++++----
.../workbench/notebook/notebook.component.scss | 20 +-
.../pages/workbench/notebook/notebook.component.ts | 279 +++++++++++++++++----
.../pages/workbench/notebook/notebook.module.ts | 4 +-
.../src/app/services/notebook.service.ts | 37 +++
6 files changed, 368 insertions(+), 105 deletions(-)
diff --git a/submarine-workbench/workbench-web-ng/src/app/interfaces/notebook-spec.ts b/submarine-workbench/workbench-web-ng/src/app/interfaces/notebook-spec.ts
index 1648d2d..261e604 100644
--- a/submarine-workbench/workbench-web-ng/src/app/interfaces/notebook-spec.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/interfaces/notebook-spec.ts
@@ -31,14 +31,18 @@ export class Meta {
export class Environment {
name: string;
dockerImage: string;
- kernelSpec: string;
- description: string;
+ kernelSpec: {
+ name: string;
+ channels: string[];
+ dependencies: string[];
+ };
+ description?: string;
image: string;
}
export class Spec {
- envVars: {
- TEST_ENV: string;
+ envVars?: {
+ [key: string]: string;
};
resources: string;
}
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 cce4926..cdd0ed9 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
@@ -40,12 +40,8 @@
<div nz-row>
<div nz-col nzSpan="12">
<label style="font-size: large; color: black;">Namespaces :</label>
- <nz-select
- style="margin-left: 5px; width: 240px;"
- [(ngModel)]="currentNamespace"
- (ngModelChange)="switchNamespace($event)"
- >
- <nz-option *ngFor="let namespace of namespacesList" [nzValue]="namespace" [nzLabel]="namespace"></nz-option>
+ <nz-select 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">
@@ -55,37 +51,33 @@
<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)="isVisible = true">
+ <button
+ id="btnNewNotebook"
+ nz-button
+ nzType="primary"
+ style="margin-right: 5px;"
+ (click)="initNotebookStatus()"
+ >
<i nz-icon nzType="plus"></i>
New Notebook
</button>
- <button id="btnDelNotebook" nz-button nzType="primary">
- <i nz-icon nzType="delete"></i>
- Delete
- </button>
</div>
</div>
<div>
<nz-table style="padding-top: 5px;" #basicTable [nzData]="notebookTable">
<thead>
<tr>
- <th>
- <label nz-checkbox [(ngModel)]="checked" (ngModelChange)="selectAllNotebook()"></label>
- </th>
<th>Name</th>
<th>Environment</th>
<th>Docker Image</th>
<th>Resources</th>
<th>Status</th>
- <th>Environment</th>
+ <th>Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data; let i = index">
<td>
- <label nz-checkbox [(ngModel)]="checkedList[i]"></label>
- </td>
- <td>
<a>{{ data.name }}</a>
</td>
<td>{{ data.spec.environment.name }}</td>
@@ -94,7 +86,7 @@
{{ data.spec.spec.resources }}
</td>
<td>{{ data.status }}</td>
- <td>{{ data.spec.environment.name }}</td>
+ <td><a (click)="deleteNotebook(data.notebookId)">Delete</a></td>
</tr>
</tbody>
</nz-table>
@@ -105,57 +97,100 @@
<nz-modal
[(nzVisible)]="isVisible"
nzTitle="Create Notebook"
- [(nzCancelText)]="cancelText"
[(nzOkText)]="okText"
- [nzOkLoading]="isOkLoading"
(nzOnCancel)="isVisible = false"
- (nzOnOk)="isVisible = false"
[nzWidth]="700"
>
- <div>
- <form [formGroup]="notebookForm">
+ <form [formGroup]="notebookForm">
+ <div *nzModalFooter>
+ <button nz-button nzType="default" (click)="isVisible = false">Cancel</button>
+ <button id="go" nz-button nzType="primary" [disabled]="checkStatus()" (click)="handleOk()">
+ Create
+ </button>
+ </div>
+ <div style="margin-top: 30px;">
<div class="newNotebookForm">
<label for="notebookName">
<span class="red-star">*</span>
- Notebook Name :
+ Notebook Name
</label>
- <input nz-input type="text" name="notebookName" id="notebookName" formControlName="notebookName" required />
+ <input nz-input required type="text" name="notebookName" id="notebookName" formControlName="notebookName" />
</div>
<div class="newNotebookForm">
- <label for="namespaces">
+ <label for="namespace">
<span class="red-star">*</span>
- Namespaces :
+ Namespace
</label>
- <input nz-input type="text" name="namespaces" id="namespaces" formControlName="namespaces" />
+ <input
+ nz-input
+ [(ngModel)]="currentNamespace"
+ disabled="disabled"
+ name="namespace"
+ id="namespace"
+ formControlName="namespace"
+ />
</div>
<div class="newNotebookForm">
<label for="environment">
<span class="red-star">*</span>
- Environment :
+ Environment
</label>
- <input nz-input type="text" name="environment" id="environment" formControlName="environment" />
+ <nz-select required name="select-envName" formControlName="envName">
+ <nz-option *ngFor="let env of envNameList" [nzValue]="env" [nzLabel]="env"></nz-option>
+ </nz-select>
</div>
<div class="newNotebookForm">
- <label for="cpu">
+ <label for="cpus">
<span class="red-star">*</span>
- CPU :
+ CPU
</label>
- <input nz-input type="text" name="cpu" id="cpu" formControlName="cpu" />
+ <input nz-input required type="number" name="cpus" id="cpus" formControlName="cpus" />
</div>
<div class="newNotebookForm">
- <label for="gpu">
- <span class="red-star">*</span>
- GPU :
+ <label for="gpus">
+ GPU
</label>
- <input nz-input type="text" name="gpu" id="gpu" formControlName="gpu" />
+ <input nz-input type="number" name="gpus" id="gpus" formControlName="gpus" />
</div>
<div class="newNotebookForm">
- <label for="memory">
+ <label for="memoryNum">
<span class="red-star">*</span>
- Memory :
+ Memory
</label>
- <input nz-input type="text" name="memory" id="memory" formControlName="memory" />
+ <div class="memory-input-group">
+ <input nz-input required name="memoryNum" formControlName="memoryNum" />
+ <nz-select formControlName="unit">
+ <nz-option *ngFor="let unit of MEMORY_UNITS" [nzValue]="unit" [nzLabel]="unit"></nz-option>
+ </nz-select>
+ </div>
</div>
- </form>
- </div>
+ <div formArrayName="envVars">
+ <ng-container *ngFor="let envVar of envVars.controls; index as i">
+ <div [formGroupName]="i" class="newNotebookForm">
+ <label for="envVar{{ i }}">EnvVar {{ i + 1 }}</label>
+ <div>
+ <input style="width: 30%;" nz-input name="key{{ i }}" placeholder="Key" formControlName="key" />
+ <input
+ style="width: 50%; margin-left: 10px;"
+ nz-input
+ 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>
+ </ng-container>
+ </div>
+ </div>
+ <button nz-button style="display: block; margin: auto;" id="envVar-btn" type="default" (click)="onCreateEnvVar()">
+ Add new env
+ </button>
+ </form>
</nz-modal>
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.component.scss b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.component.scss
index 201a781..68e727f 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.component.scss
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.component.scss
@@ -29,12 +29,13 @@
padding: 10px;
overflow: auto;
}
+
.red-star {
color: red;
}
.newNotebookForm {
- display: flex;
+ display: flex;
align-items: center;
margin-bottom: 1.5rem;
& label {
@@ -48,4 +49,19 @@
& input {
flex: 0 0 48%;
}
- }
\ No newline at end of file
+
+ & nz-select {
+ flex: 0 0 48%;
+ }
+ }
+
+ .memory-input-group {
+ display: flex;
+ & input {
+ width: 70%;
+ }
+
+ & > * {
+ width: 30%;
+ }
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.component.ts b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.component.ts
index c427ff1..6c4d5ca 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.component.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.component.ts
@@ -18,8 +18,11 @@
*/
import { Component, OnInit } from '@angular/core';
-import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { FormArray, FormControl, FormGroup, Validators } 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';
@Component({
selector: 'submarine-notebook',
@@ -27,79 +30,101 @@ import { NotebookService } from '@submarine/services/notebook.service';
styleUrls: ['./notebook.component.scss']
})
export class NotebookComponent implements OnInit {
- // Checkbox
- checkedList: boolean[] = [];
- checked: boolean = false;
-
- // New notebook modal
- cancelText = 'Cancel';
- okText = 'Create';
- isVisible = false;
-
- // New notebook(form)
- notebookForm: FormGroup;
+ // Environment
+ envList;
+ envNameList = [];
// Namesapces
- namespacesList = [];
+ allNamespaceList = [];
currentNamespace;
// Notebook list
- notebookList;
+ allNotebookList;
notebookTable;
- constructor(private notebookService: NotebookService) {}
+ // New Notebook Form
+ notebookForm: FormGroup;
+ isVisible = false;
+ MEMORY_UNITS = ['M', 'Gi'];
- statusColor: { [key: string]: string } = {
- Running: 'green',
- Stop: 'blue'
- };
+ constructor(
+ private notebookService: NotebookService,
+ private nzMessageService: NzMessageService,
+ private environmentService: EnvironmentService,
+ private experimentValidatorService: ExperimentValidatorService
+ ) {}
ngOnInit() {
this.notebookForm = new FormGroup({
- notebookName: new FormControl(null, [Validators.required]),
- namespaces: new FormControl(this.currentNamespace, [Validators.required]),
- environment: new FormControl('env1', [Validators.required]),
- cpu: new FormControl(null, [Validators.required]),
- gpu: new FormControl(null, [Validators.required]),
- memory: new FormControl(null, [Validators.required])
+ notebookName: new FormControl(null, Validators.required),
+ namespace: new FormControl(this.currentNamespace),
+ envName: new FormControl(null, Validators.required), // Environment
+ envVars: new FormArray([], [this.experimentValidatorService.nameValidatorFactory('key')]),
+ cpus: new FormControl(null, [Validators.min(1), Validators.required]),
+ gpus: new FormControl(null),
+ memoryNum: new FormControl(null, [Validators.required]),
+ unit: new FormControl(this.MEMORY_UNITS[0], [Validators.required])
});
-
this.fetchNotebookList();
+ this.fetchEnvList();
}
- fetchNotebookList() {
- this.notebookService.fetchNotebookList().subscribe((list) => {
- this.notebookList = list;
- this.checkedList = [];
- for (let i = 0; i < this.notebookList.length; i++) {
- this.checkedList.push(false);
- }
- // Get namespaces
- this.notebookList.forEach((element) => {
- if (this.namespacesList.indexOf(element.spec.meta.namespace) < 0) {
- this.namespacesList.push(element.spec.meta.namespace);
+ // 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);
}
});
- // Set default namespace and table
- this.currentNamespace = this.namespacesList[0];
+ });
+ }
+
+ // Get all notebooks, then set default namespace.
+ fetchNotebookList() {
+ this.notebookService.fetchNotebookList().subscribe((list) => {
+ this.allNotebookList = list;
+ this.currentNamespace = 'default';
this.notebookTable = [];
- this.notebookList.forEach((item) => {
+ this.allNotebookList.forEach((item) => {
if (item.spec.meta.namespace == this.currentNamespace) {
this.notebookTable.push(item);
}
});
+
+ // Get namespaces
+ //this.getAllNamespaces();
+
+ // Set default namespace and table
+ //this.setDefaultTable();
});
}
- selectAllNotebook() {
- for (let i = 0; i < this.checkedList.length; i++) {
- this.checkedList[i] = this.checked;
- }
+ // 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.notebookList.forEach((item) => {
+ this.allNotebookList.forEach((item) => {
if (item.spec.meta.namespace == namespace) {
this.notebookTable.push(item);
}
@@ -107,19 +132,163 @@ export class NotebookComponent implements OnInit {
console.log(this.notebookTable);
}
- // TODO(kobe860219): Make a notebook run
- runNotebook(data) {
- data.status = 'Running';
+ deleteNotebook(id: string) {
+ this.notebookService.deleteNotebook(id).subscribe(
+ () => {
+ this.nzMessageService.success('Delete Notebook Successfully!');
+ this.updateNotebookTable();
+ },
+ (err) => {
+ this.nzMessageService.error(err.message);
+ }
+ );
}
- // TODO(kobe860219): Stop a running notebook
- stopNotebook(data) {
- data.status = 'Stop';
+ // Create or Delete, then update Notebook Table
+ updateNotebookTable() {
+ this.notebookService.fetchNotebookList().subscribe((list) => {
+ this.allNotebookList = list;
+ this.notebookTable = [];
+ this.allNotebookList.forEach((item) => {
+ if (item.spec.meta.namespace == this.currentNamespace) {
+ this.notebookTable.push(item);
+ }
+ });
+ });
}
- // TODO(kobe860219): Create new notebook
- createNotebook() {}
+ get notebookName() {
+ return this.notebookForm.get('notebookName');
+ }
+ get namespace() {
+ return this.notebookForm.get('namespace');
+ }
+ 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[0]);
+ 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]
+ );
+ }
- // TODO(kobe860219): Delete notebook
- deleteNotebook() {}
+ // 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) {
+ 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},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: this.notebookForm.get('namespace').value
+ },
+ 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;
+ }
+ }
+
+ // Post
+ this.notebookService.createNotebook(newNotebookSpec).subscribe({
+ next: (result) => {
+ this.updateNotebookTable();
+ },
+ error: (msg) => {
+ this.nzMessageService.error(`${msg}, please try again`, {
+ nzPauseOnHover: true
+ });
+ },
+ complete: () => {
+ this.nzMessageService.success('Notebook creation succeeds');
+ this.isVisible = false;
+ }
+ });
+ }
+
+ // TODO(kobe860219): Make a notebook run
+ runNotebook() {}
+
+ // TODO(kobe860219): Stop a running notebook
+ stopNotebook() {}
}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.module.ts b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.module.ts
index 6f2c732..9a99d23 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.module.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/notebook/notebook.module.ts
@@ -23,9 +23,11 @@ import { NotebookComponent } from './notebook.component';
import { NotebookRoutingModule } from './notebook-routing.module';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NgZorroAntdModule } from 'ng-zorro-antd';
+import { PipeSharedModule } from '@submarine/pipe/pipe-shared.module';
@NgModule({
+ exports: [ReactiveFormsModule],
declarations: [NotebookComponent],
- imports: [CommonModule, NotebookRoutingModule, FormsModule, ReactiveFormsModule, NgZorroAntdModule]
+ imports: [CommonModule, NotebookRoutingModule, FormsModule, ReactiveFormsModule, NgZorroAntdModule, PipeSharedModule]
})
export class NotebookModule {}
diff --git a/submarine-workbench/workbench-web-ng/src/app/services/notebook.service.ts b/submarine-workbench/workbench-web-ng/src/app/services/notebook.service.ts
index 3b54db9..1c7f409 100644
--- a/submarine-workbench/workbench-web-ng/src/app/services/notebook.service.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/services/notebook.service.ts
@@ -44,4 +44,41 @@ export class NotebookService {
})
);
}
+
+ createNotebook(newNotebook: object): Observable<Notebook> {
+ const apiUrl = this.baseApi.getRestApi('/v1/notebook');
+ return this.httpClient.post<Rest<Notebook>>(apiUrl, newNotebook).pipe(
+ map((res) => res.result), // return result directly if succeeding
+ catchError((e) => {
+ let message: string;
+ if (e.error instanceof ErrorEvent) {
+ // client side error
+ message = 'Something went wrong with network or workbench';
+ } else {
+ console.log(e);
+ if (e.status === 409) {
+ message = 'You might have a duplicate notebook name';
+ } else if (e.status >= 500) {
+ message = `${e.message}`;
+ } else {
+ message = e.error.message;
+ }
+ }
+ return throwError(message);
+ })
+ );
+ }
+
+ deleteNotebook(id: string): Observable<Notebook> {
+ const apiUrl = this.baseApi.getRestApi(`/v1/notebook/${id}`);
+ return this.httpClient.delete<Rest<Notebook>>(apiUrl).pipe(
+ switchMap((res) => {
+ if (res.success) {
+ return of(res.result);
+ } else {
+ throw this.baseApi.createRequestError(res.message, res.code, apiUrl, 'delete', id);
+ }
+ })
+ );
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@submarine.apache.org
For additional commands, e-mail: dev-help@submarine.apache.org