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/05/13 04:55:10 UTC
[submarine] branch master updated: SUBMARINE-495. [WEB] Submarine
experiment list/delete in workbench with Angular
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 b6aeed0 SUBMARINE-495. [WEB] Submarine experiment list/delete in workbench with Angular
b6aeed0 is described below
commit b6aeed05f235b44aca33d094ae3476ccc2f4842d
Author: pingsutw <pi...@gmail.com>
AuthorDate: Mon May 11 20:50:49 2020 +0800
SUBMARINE-495. [WEB] Submarine experiment list/delete in workbench with Angular
### What is this PR for?
Implement list/delete experiment in workbench with Angular.
will start working on submit/edit, after submarine experiment spec is refactored.
### What type of PR is it?
[Improvement]
### Todos
* [ ] - Task
### What is the Jira issue?
https://issues.apache.org/jira/browse/SUBMARINE-495
### How should this be tested?
https://travis-ci.org/github/pingsutw/hadoop-submarine/builds/685730718
### Screenshots (if appropriate)
![Untitled_-May-11_-2020-10_39-PM_1](https://user-images.githubusercontent.com/37936015/81586972-f4624c80-93e8-11ea-8a41-41e00cffe2a9.gif)
### Questions:
* Does the licenses files need update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? No
Author: pingsutw <pi...@gmail.com>
Closes #283 from pingsutw/SUBMARINE-495 and squashes the following commits:
90bde6f [pingsutw] SUBMARINE-495. [WEB] Submarine experiment list/delete in workbench with Angular
---
.../submarine/server/rest/JobManagerRestApi.java | 18 ++--
.../integration/{jobIT.java => experimentIT.java} | 21 ++--
.../apache/submarine/integration/sidebarIT.java | 6 +-
.../experiment-info.ts} | 20 ++--
.../experiment-spec.ts} | 10 +-
.../experiment.component.html} | 89 ++++++++++------
.../experiment.component.scss} | 4 +-
.../workbench/experiment/experiment.component.ts | 116 +++++++++++++++++++++
.../experiment.module.ts} | 2 +-
.../src/app/pages/workbench/job/job.component.ts | 103 ------------------
.../pages/workbench/workbench-routing.module.ts | 6 +-
.../src/app/pages/workbench/workbench.component.ts | 4 +-
.../src/app/pages/workbench/workbench.module.ts | 9 +-
.../src/app/services/experiment.service.ts | 87 ++++++++++++++++
14 files changed, 310 insertions(+), 185 deletions(-)
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/JobManagerRestApi.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/JobManagerRestApi.java
index f468717..ef26e40 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/JobManagerRestApi.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/rest/JobManagerRestApi.java
@@ -68,7 +68,7 @@ public class JobManagerRestApi {
public Response createJob(JobSpec spec) {
try {
Job job = jobManager.createJob(spec);
- return new JsonResponse.Builder<Job>(Response.Status.OK).result(job).build();
+ return new JsonResponse.Builder<Job>(Response.Status.OK).success(true).result(job).build();
} catch (SubmarineRuntimeException e) {
return parseJobServiceException(e);
}
@@ -82,7 +82,7 @@ public class JobManagerRestApi {
public Response listJob(@QueryParam("status") String status) {
try {
List<Job> jobList = jobManager.listJobsByStatus(status);
- return new JsonResponse.Builder<List<Job>>(Response.Status.OK).result(jobList).build();
+ return new JsonResponse.Builder<List<Job>>(Response.Status.OK).success(true).result(jobList).build();
} catch (SubmarineRuntimeException e) {
return parseJobServiceException(e);
}
@@ -98,7 +98,7 @@ public class JobManagerRestApi {
public Response getJob(@PathParam(RestConstants.JOB_ID) String id) {
try {
Job job = jobManager.getJob(id);
- return new JsonResponse.Builder<Job>(Response.Status.OK).result(job).build();
+ return new JsonResponse.Builder<Job>(Response.Status.OK).success(true).result(job).build();
} catch (SubmarineRuntimeException e) {
return parseJobServiceException(e);
}
@@ -127,20 +127,20 @@ public class JobManagerRestApi {
public Response deleteJob(@PathParam(RestConstants.JOB_ID) String id) {
try {
Job job = jobManager.deleteJob(id);
- return new JsonResponse.Builder<Job>(Response.Status.OK)
+ return new JsonResponse.Builder<Job>(Response.Status.OK).success(true)
.result(job).build();
} catch (SubmarineRuntimeException e) {
return parseJobServiceException(e);
}
}
-
+
@GET
@Path("/logs")
public Response listLog(@QueryParam("status") String status) {
try {
List<JobLog> jobLogList = jobManager.listJobLogsByStatus(status);
- return new JsonResponse.Builder<List<JobLog>>(Response.Status.OK).
- result(jobLogList).build();
+ return new JsonResponse.Builder<List<JobLog>>(Response.Status.OK).success(true)
+ .result(jobLogList).build();
} catch (SubmarineRuntimeException e) {
return parseJobServiceException(e);
@@ -152,8 +152,8 @@ public class JobManagerRestApi {
public Response getLog(@PathParam(RestConstants.JOB_ID) String id) {
try {
JobLog jobLog = jobManager.getJobLog(id);
- return new JsonResponse.Builder<JobLog>(Response.Status.OK).
- result(jobLog).build();
+ return new JsonResponse.Builder<JobLog>(Response.Status.OK).success(true)
+ .result(jobLog).build();
} catch (SubmarineRuntimeException e) {
return parseJobServiceException(e);
diff --git a/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/jobIT.java b/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/experimentIT.java
similarity index 73%
rename from submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/jobIT.java
rename to submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/experimentIT.java
index aebe245..c7d1509 100644
--- a/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/jobIT.java
+++ b/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/experimentIT.java
@@ -19,7 +19,6 @@ package org.apache.submarine.integration;
import org.apache.submarine.AbstractSubmarineIT;
import org.apache.submarine.WebDriverManager;
-import org.apache.submarine.SubmarineITUtils;
import org.openqa.selenium.By;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -28,9 +27,9 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.testng.Assert;
-public class jobIT extends AbstractSubmarineIT {
+public class experimentIT extends AbstractSubmarineIT {
- public final static Logger LOG = LoggerFactory.getLogger(jobIT.class);
+ public final static Logger LOG = LoggerFactory.getLogger(experimentIT.class);
@BeforeClass
public static void startUp(){
@@ -53,19 +52,19 @@ public class jobIT extends AbstractSubmarineIT {
pollingWait(By.cssSelector("a[routerlink='/workbench/dashboard']"), MAX_BROWSER_TIMEOUT_SEC);
// Routing to workspace
- pollingWait(By.xpath("//span[contains(text(), \"Job\")]"), MAX_BROWSER_TIMEOUT_SEC).click();
- Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8080/workbench/job");
+ pollingWait(By.xpath("//span[contains(text(), \"Experiment\")]"), MAX_BROWSER_TIMEOUT_SEC).click();
+ Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8080/workbench/experiment");
- // Test create new job
- pollingWait(By.xpath("//button[@id='openJob']"), MAX_BROWSER_TIMEOUT_SEC).click();
- Assert.assertEquals(pollingWait(By.xpath("//form"), MAX_BROWSER_TIMEOUT_SEC).isDisplayed(), true);
- pollingWait(By.xpath("//input[@id='jobname']"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("e2e test Job");
+ // Test create new experiment
+ pollingWait(By.xpath("//button[@id='openExperiment']"), MAX_BROWSER_TIMEOUT_SEC).click();
+ Assert.assertTrue(pollingWait(By.xpath("//form"), MAX_BROWSER_TIMEOUT_SEC).isDisplayed());
+ pollingWait(By.xpath("//input[@id='experimentName']"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("e2e test Experiment");
pollingWait(By.xpath("//textarea"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("e2e test Project description");
pollingWait(By.xpath("//button[@id='go']"), MAX_BROWSER_TIMEOUT_SEC).click();
//Next step
- Assert.assertEquals(pollingWait(By.xpath("//div[@id='page2']"), MAX_BROWSER_TIMEOUT_SEC).isDisplayed(), true);
+ Assert.assertTrue(pollingWait(By.xpath("//div[@id='page2']"), MAX_BROWSER_TIMEOUT_SEC).isDisplayed());
pollingWait(By.xpath("//button[@id='go']"), MAX_BROWSER_TIMEOUT_SEC).click();
- Assert.assertEquals(pollingWait(By.xpath("//label[@class='pg3-form-label']"), MAX_BROWSER_TIMEOUT_SEC).isDisplayed(), true);
+ Assert.assertTrue(pollingWait(By.xpath("//label[@class='pg3-form-label']"), MAX_BROWSER_TIMEOUT_SEC).isDisplayed());
pollingWait(By.xpath("//button[@id='go']"), MAX_BROWSER_TIMEOUT_SEC).click();
}
}
diff --git a/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/sidebarIT.java b/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/sidebarIT.java
index cfee7a2..796ab78 100644
--- a/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/sidebarIT.java
+++ b/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/sidebarIT.java
@@ -60,8 +60,8 @@ public class sidebarIT extends AbstractSubmarineIT {
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8080/workbench/workspace");
pollingWait(By.xpath("//span[contains(text(), \"Interpreter\")]"), MAX_BROWSER_TIMEOUT_SEC).click();
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8080/workbench/interpreter");
- pollingWait(By.xpath("//span[contains(text(), \"Job\")]"), MAX_BROWSER_TIMEOUT_SEC).click();
- Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8080/workbench/job");
+ pollingWait(By.xpath("//span[contains(text(), \"Experiment\")]"), MAX_BROWSER_TIMEOUT_SEC).click();
+ Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8080/workbench/experiment");
pollingWait(By.xpath("//span[contains(text(), \"Data\")]"), MAX_BROWSER_TIMEOUT_SEC).click();
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8080/workbench/data");
pollingWait(By.xpath("//span[contains(text(), \"Model\")]"), MAX_BROWSER_TIMEOUT_SEC).click();
@@ -78,6 +78,6 @@ public class sidebarIT extends AbstractSubmarineIT {
pollingWait(By.xpath("//a[@href='/workbench/manager/dataDict']"), MAX_BROWSER_TIMEOUT_SEC).click();
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8080/workbench/manager/dataDict");
pollingWait(By.xpath("//span[contains(text(), \"Home\")]"), MAX_BROWSER_TIMEOUT_SEC).click();
- Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8080/workbench/home");
+ Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8080/workbench/home");
}
}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.module.ts b/submarine-workbench/workbench-web-ng/src/app/interfaces/experiment-info.ts
similarity index 73%
copy from submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.module.ts
copy to submarine-workbench/workbench-web-ng/src/app/interfaces/experiment-info.ts
index 256726e..8f7227c 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.module.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/interfaces/experiment-info.ts
@@ -1,6 +1,3 @@
-import { NgModule } from "@angular/core";
-import { ReactiveFormsModule } from '@angular/forms';
-
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -20,7 +17,16 @@ import { ReactiveFormsModule } from '@angular/forms';
* under the License.
*/
-@NgModule({
- exports: [ReactiveFormsModule]
-})
-export class JobModule {}
+import { ExperimentSpec } from '@submarine/interfaces/experiment-spec';
+
+export class ExperimentInfo {
+ jobId: string;
+ name: string;
+ uid: string;
+ status: string;
+ acceptedTime: string;
+ createdTime: string;
+ runningTime: string;
+ finishedTime: string;
+ spec: ExperimentSpec;
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.module.ts b/submarine-workbench/workbench-web-ng/src/app/interfaces/experiment-spec.ts
similarity index 82%
copy from submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.module.ts
copy to submarine-workbench/workbench-web-ng/src/app/interfaces/experiment-spec.ts
index 256726e..1f239da 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.module.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/interfaces/experiment-spec.ts
@@ -1,6 +1,3 @@
-import { NgModule } from "@angular/core";
-import { ReactiveFormsModule } from '@angular/forms';
-
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -20,7 +17,6 @@ import { ReactiveFormsModule } from '@angular/forms';
* under the License.
*/
-@NgModule({
- exports: [ReactiveFormsModule]
-})
-export class JobModule {}
+export class ExperimentSpec {
+ // TODO(pingsutw): After refactor submarine experiment spec, we could start implementing it.
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.component.html b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/experiment/experiment.component.html
similarity index 64%
rename from submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.component.html
rename to submarine-workbench/workbench-web-ng/src/app/pages/workbench/experiment/experiment.component.html
index cf3594f..82fc8d1 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.component.html
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/experiment/experiment.component.html
@@ -19,22 +19,22 @@
<nz-layout style="margin: -24px -24px 16px;">
<nz-layout class="inner-layout">
- <div id="jobOuter">
+ <div id="experimentOuter">
<nz-breadcrumb>
<nz-breadcrumb-item>
<a [routerLink]="['/', 'workbench', 'home']">Home</a>
</nz-breadcrumb-item>
- <nz-breadcrumb-item>Job</nz-breadcrumb-item>
+ <nz-breadcrumb-item>experiment</nz-breadcrumb-item>
</nz-breadcrumb>
<br/>
- <h2>Job</h2>
- <nz-content>A job is a way of running a notebook or on a scheduled basis.</nz-content>
+ <h2>Experiment</h2>
+ <nz-content>A experiment is a way of running a adhoc, pre-defined or pipeline on a scheduled basis.</nz-content>
<br/>
</div>
</nz-layout>
- <div id="jobData">
+ <div id="experimentData">
<div align="right">
- <nz-radio-group [(ngModel)]="showJob" (ngModelChange)="showChange()">
+ <nz-radio-group [(ngModel)]="showExperiment" (ngModelChange)="showChange()">
<label nz-radio-button nzValue="All">All</label>
<label nz-radio-button nzValue="Own">Owned By Me</label>
<label nz-radio-button nzValue="Access">Accessable By Me</label>
@@ -45,45 +45,68 @@
<ng-template #suffixIconButton>
<button nz-button nzType="primary" nzSearch><i nz-icon nzType="search"></i></button>
</ng-template>
-
- <button nz-button id="openJob" nzType="primary" style="margin-right: 30px;margin-bottom: 15px;margin-top: 15px;" (click)="isVisible=true;"><i nz-icon nzType="plus"></i>New Job</button>
- </div>
- <nz-table id="releaseTable" nzBordered #basicTable [nzData]="joblist" [nzNoResult]="'No data'">
+
+ <button nz-button id="openExperiment" nzType="primary" style="margin-right: 30px;margin-bottom: 15px;margin-top: 15px;" (click)="isVisible=true;"><i nz-icon nzType="plus"></i>New Experiment</button>
+ </div>
+ <nz-table id="releaseTable" nzBordered #basicTable [nzData]="experimentList" [nzNoResult]="'No data'">
<thead>
<tr>
- <th nzWidth="60px">Job Name</th>
- <th nzWidth="20px">Job ID</th>
- <th nzWidth="40px">Owner</th>
- <th nzWidth="60px">Actuator</th>
- <th nzWidth="60px">Status</th>
- <th nzWidth="60px">Progress</th>
- <th nzWidth="60px">Last Run</th>
- <th nzWidth="60px">Action</th>
+ <th>Experiment Name</th>
+ <th>Experiment ID</th>
+ <th>Created Time</th>
+ <th>Running Time</th>
+ <th>Finished Time</th>
+ <th>Status</th>
+ <th>Progress</th>
+ <th nzMinWidth="40px">Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<td>{{ data.name }}</td>
- <td>{{ data.id }}</td>
- <td>{{ data.owner }}</td>
- <td>{{ data.actuator }}</td>
+ <td>{{ data.jobId }}</td>
+ <td>{{ data.createdTime }}</td>
+ <td>{{ data.runningTime }}</td>
+ <td>{{ data.finishedTime }}</td>
<td>{{ data.status }}</td>
- <td><nz-progress nzStrokeLinecap="round" [nzPercent]="data.progress"></nz-progress></td>
- <td>{{ data.lastRun }}</td>
- <td><button nz-button nzType="link" (click)="startJob(data)" style="padding-left: 2px;padding-right: 5px;">Start</button>|<button nz-button nzType="link" (click)="editJob(data)" style="padding-left: 2px;padding-right: 5px;">Edit</button></td>
+ <td *ngIf="data.status === 'Succeeded'"><nz-progress nzStrokeLinecap="round" [nzPercent]="100"></nz-progress></td>
+ <td *ngIf="data.status !== 'Succeeded'"><nz-progress nzStrokeLinecap="round" [nzPercent]="50"></nz-progress></td>
+ <td class="td-action" nzRight="0px">
+ <a (click)="startExperiment(data)">Start</a>
+ <a nz-dropdown [nzDropdownMenu]="more">
+ More
+ <i nz-icon nzType="down"></i>
+ </a>
+ <nz-dropdown-menu #more="nzDropdownMenu">
+ <ul nz-menu nzSelectable>
+ <li nz-menu-item (click)="editExperiment(data)">Edit</li>
+ <li
+ nz-menu-item
+ nz-popconfirm
+ nzPlacement="left"
+ nzTitle="Confirm to delete?"
+ nzCancelText="Cancel"
+ nzOkText="Ok"
+ (nzOnConfirm)="onDeleteExperiment(data)"
+ >
+ Delete
+ </li>
+ </ul>
+ </nz-dropdown-menu>
+ </td>
</tr>
</tbody>
</nz-table>
</div>
<nz-modal
[(nzVisible)]="isVisible"
- nzTitle="Create Job"
+ nzTitle="Create Experiment"
[(nzOkText)]="okText"
[nzOkLoading]="isOkLoading"
(nzOnCancel)="isVisible=false;"
[nzWidth]="740"
>
- <div >
+ <div>
<nz-steps [nzCurrent]="current">
<nz-step nzTitle="Basic Information"></nz-step>
<nz-step nzTitle="Configuration"></nz-step>
@@ -91,17 +114,17 @@
</nz-steps>
</div>
<div>
- <form [formGroup]="createJob">
+ <form [formGroup]="createExperiment">
<div *nzModalFooter>
<button nz-button nzType="default" (click)="isVisible=false;"> Cancel </button>
- <button id="go" nz-button nzType="primary" [disabled]="!(createJob.get('jobName').valid && createJob.get('description').valid)" (click)="handleOk()">{{okText}}</button>
+ <button id="go" nz-button nzType="primary" [disabled]="!(createExperiment.get('experimentName').valid && createExperiment.get('description').valid)" (click)="handleOk()">{{okText}}</button>
<button *ngIf="current>0" nz-button nzType="default" style="float: left;" (click)="current=current-1;okText = 'Next Step';">Prev Step</button>
</div>
<div [ngSwitch]="current" style="margin-top: 30px;">
<div *ngSwitchCase="0">
<div>
- <label class="form-label"><span class="red-star">* </span> Job Name:</label>
- <input type="text" id="jobname" style="margin-top: 32px;width: 350px;" class="form-control" formControlName="jobName">
+ <label class="form-label"><span class="red-star">* </span> Experiment Name:</label>
+ <input type="text" id="experimentName" style="margin-top: 32px;width: 350px;" class="form-control" formControlName="experimentName">
</div>
<div>
<label class="form-label"><span class="red-star">* </span>Description:</label>
@@ -110,9 +133,9 @@
</div>
<div *ngSwitchCase="1" id="page2">
<div>
- <label class="form-label"><span class="red-star">* </span> Monitor Object:</label>
- <nz-select formControlName="monitorObject" nzPlaceHolder="Choose" style="width: 350px;margin-top: 30px;">
- <nz-option *ngFor="let monitorObject of monitorObjects" [nzValue]="monitorObject" [nzLabel]="monitorObject"></nz-option>
+ <label class="form-label"><span class="red-star">* </span> Experiment Spec:</label>
+ <nz-select formControlName="experimentSpec" nzPlaceHolder="Choose" style="width: 350px;margin-top: 30px;">
+ <nz-option *ngFor="let experimentSpec of ExperimentSpecs" [nzValue]="experimentSpec" [nzLabel]="experimentSpec"></nz-option>
</nz-select>
</div>
<div>
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.component.scss b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/experiment/experiment.component.scss
similarity index 97%
rename from submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.component.scss
rename to submarine-workbench/workbench-web-ng/src/app/pages/workbench/experiment/experiment.component.scss
index 64d6f27..3838a1b 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.component.scss
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/experiment/experiment.component.scss
@@ -17,13 +17,13 @@
* under the License.
*/
- #jobOuter{
+ #experimentOuter{
background-color: white;
padding-left: 30px;
padding-top: 20px;
}
- #jobData{
+ #experimentData{
margin-top: 16px;
margin-left: 25px;
margin-right: 25px;
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/experiment/experiment.component.ts b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/experiment/experiment.component.ts
new file mode 100644
index 0000000..3935628
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/experiment/experiment.component.ts
@@ -0,0 +1,116 @@
+/*!
+ * 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 } from '@angular/core';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { ExperimentInfo } from '@submarine/interfaces/experiment-info';
+import { ExperimentService } from '@submarine/services/experiment.service';
+import { NzMessageService } from 'ng-zorro-antd';
+
+@Component({
+ selector: 'submarine-experiment',
+ templateUrl: './experiment.component.html',
+ styleUrls: ['./experiment.component.scss']
+})
+export class ExperimentComponent implements OnInit {
+
+ experimentList: ExperimentInfo[] = [];
+ // About show existing experiments
+ showExperiment = 'All';
+ searchText = '';
+
+ // About new experiment
+ createExperiment: FormGroup;
+ current = 0;
+ okText = 'Next Step';
+ isVisible = false;
+
+ ExperimentSpecs = ['Adhoc', 'Predefined'];
+ ruleTemplates = ['Template1', 'Template2'];
+ ruleTypes = ['Strong', 'Weak'];
+ scheduleCycles = ['Month', 'Week'];
+
+ constructor(
+ private experimentService: ExperimentService,
+ private nzMessageService: NzMessageService
+ ) { }
+
+ ngOnInit() {
+ this.createExperiment = new FormGroup({
+ 'experimentName': new FormControl(null, Validators.required),
+ 'description': new FormControl(null, [Validators.required]),
+ 'experimentSpec': new FormControl('Adhoc'),
+ 'ruleTemplate': new FormControl('Template1'),
+ 'ruleType': new FormControl('Strong'),
+ 'startDate': new FormControl(new Date()),
+ 'scheduleCycle': new FormControl('Month')
+ });
+ this.fetchExperimentList();
+ }
+
+ handleOk() {
+ if (this.current === 1) {
+ this.okText = 'Submit';
+ this.current++;
+ } else if (this.current === 2) {
+ this.okText = 'Next Step';
+ this.current = 0;
+ this.isVisible = false;
+ // TODO(jasoonn): Create Real experiment
+ console.log(this.createExperiment);
+ } else {
+ this.current++;
+ }
+ }
+
+ fetchExperimentList() {
+ this.experimentService
+ .fetchExperimentList()
+ .subscribe(( list ) => {
+ this.experimentList = list;
+ });
+ }
+ onDeleteExperiment(data: ExperimentInfo) {
+ this.experimentService.deleteExperiment(data.jobId).subscribe(
+ () => {
+ this.nzMessageService.success('Delete user success!');
+ this.fetchExperimentList();
+ }, err => {
+ this.nzMessageService.success(err.message);
+ }
+ );
+ }
+
+ // TODO(jasoonn): Filter experiment list
+ filter(event) {
+ console.log(this.searchText + event.key);
+ }
+ // TODO(jasoonn): Perform part of list
+ showChange() {
+ console.log("Change to " + this.showExperiment);
+ }
+ // TODO(jasoonn): Start experiment
+ startExperiment(Experiment) {
+ console.log(Experiment);
+ }
+ // TODO(jasoonn): Edit experiment
+ editExperiment(Experiment) {
+ console.log(Experiment);
+ }
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.module.ts b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/experiment/experiment.module.ts
similarity index 96%
rename from submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.module.ts
rename to submarine-workbench/workbench-web-ng/src/app/pages/workbench/experiment/experiment.module.ts
index 256726e..042d3c9 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.module.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/experiment/experiment.module.ts
@@ -23,4 +23,4 @@ import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
exports: [ReactiveFormsModule]
})
-export class JobModule {}
+export class ExperimentModule {}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.component.ts b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.component.ts
deleted file mode 100644
index 0c2e1b4..0000000
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.component.ts
+++ /dev/null
@@ -1,103 +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 { Component, OnInit } from '@angular/core';
-import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
-
-@Component({
- selector: 'submarine-job',
- templateUrl: './job.component.html',
- styleUrls: ['./job.component.scss']
-})
-export class JobComponent implements OnInit {
-
- //About show existing jobs
- showJob = 'All';
- searchText = '';
- joblist=[
- {
- name: 'Spark actuator',
- id: 1,
- owner: 'Frank',
- actuator: 'Spark Actuator',
- status: 'Running',
- progress: 85,
- lastRun: '2009-09-24 20:38:24'
- }
- ]
- //About new Job
- createJob: FormGroup;
- current = 0;
- okText = 'Next Step';
- isVisible = false;
-
- monitorObjects = ['Table1', 'Table2'];
- ruleTemplates = ['Template1', 'Template2'];
- ruleTypes = ['Strong', 'Weak'];
-
- scheduleCycles = ['Month', 'Week'];
-
- constructor() { }
-
- ngOnInit() {
- this.createJob = new FormGroup({
- 'jobName': new FormControl(null, Validators.required),
- 'description': new FormControl(null, [Validators.required]),
- 'monitorObject': new FormControl('Table1'),
- 'ruleTemplate': new FormControl('Template1'),
- 'ruleType': new FormControl('Strong'),
- 'startDate': new FormControl(new Date()),
- 'scheduleCycle': new FormControl('Month')
- });
- }
-
- handleOk(){
- if (this.current === 1){
- this.okText = 'Complete';
- this.current++;
- }
- else if (this.current === 2){
- this.okText = 'Next Step';
- this.current = 0;
- this.isVisible = false;
- //TODO(jasoonn): Create Real Job
- console.log(this.createJob);
- }
- else {
- this.current++;
- }
- }
-
- //TODO(jasoonn): Filter Job list
- filter(event){
- console.log(this.searchText+event.key);
- }
- //TODO(jasoonn): Perfrom part of list
- showChange(){
- console.log("Change to " + this.showJob);
- }
- //TODO(jasoonn): Start Job
- startJob(job){
- console.log(job);
- }
- //TODO(jasoonn): Edit job
- editJob(job){
- console.log(job);
- }
-}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/workbench-routing.module.ts b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/workbench-routing.module.ts
index c9a5579..a4d6326 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/workbench-routing.module.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/workbench-routing.module.ts
@@ -19,11 +19,11 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
+import { ExperimentComponent } from '@submarine/pages/workbench/experiment/experiment.component';
import { WorkbenchComponent } from '@submarine/pages/workbench/workbench.component';
import { DataComponent } from './data/data.component';
import { HomeComponent } from './home/home.component';
import { InterpreterComponent } from './interpreter/interpreter.component';
-import { JobComponent } from './job/job.component';
import { ModelComponent } from './model/model.component';
import { WorkspaceComponent } from './workspace/workspace.component';
@@ -50,8 +50,8 @@ const routes: Routes = [
component: InterpreterComponent
},
{
- path: 'job',
- component: JobComponent
+ path: 'experiment',
+ component: ExperimentComponent
},
{
path: 'data',
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/workbench.component.ts b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/workbench.component.ts
index fd452ab..0f5ab4b 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/workbench.component.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/workbench.component.ts
@@ -60,9 +60,9 @@ export class WorkbenchComponent implements OnInit {
routerLink: '/workbench/interpreter'
},
{
- title: 'Job',
+ title: 'Experiment',
iconType: 'cluster',
- routerLink: '/workbench/job'
+ routerLink: '/workbench/experiment'
},
{
title: 'Data',
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/workbench.module.ts b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/workbench.module.ts
index 3d85b23..2573f12 100644
--- a/submarine-workbench/workbench-web-ng/src/app/pages/workbench/workbench.module.ts
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/workbench.module.ts
@@ -24,10 +24,11 @@ import { RouterModule } from '@angular/router';
import { WorkbenchRoutingModule } from '@submarine/pages/workbench/workbench-routing.module';
import { NgZorroAntdModule } from 'ng-zorro-antd';
import { DataComponent } from './data/data.component';
+import { ExperimentComponent } from './experiment/experiment.component';
+import { ExperimentModule } from './experiment/experiment.module';
+
import { HomeComponent } from './home/home.component';
import { InterpreterModule } from './interpreter/interpreter.module';
-import { JobComponent } from './job/job.component';
-import { JobModule } from './job/job.module';
import { ModelComponent } from './model/model.component';
import { WorkbenchComponent } from './workbench.component';
import { WorkspaceComponent } from './workspace/workspace.component';
@@ -38,7 +39,7 @@ import { WorkspaceModule } from './workspace/workspace.module';
WorkbenchComponent,
HomeComponent,
WorkspaceComponent,
- JobComponent,
+ ExperimentComponent,
DataComponent,
ModelComponent
],
@@ -49,7 +50,7 @@ import { WorkspaceModule } from './workspace/workspace.module';
RouterModule,
FormsModule,
WorkspaceModule,
- JobModule,
+ ExperimentModule,
InterpreterModule
]
})
diff --git a/submarine-workbench/workbench-web-ng/src/app/services/experiment.service.ts b/submarine-workbench/workbench-web-ng/src/app/services/experiment.service.ts
new file mode 100644
index 0000000..beb972f
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/services/experiment.service.ts
@@ -0,0 +1,87 @@
+/*
+ * 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 { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Rest } from '@submarine/interfaces';
+import { ExperimentInfo } from '@submarine/interfaces/experiment-info';
+import { BaseApiService } from '@submarine/services/base-api.service';
+import { of, Observable } from 'rxjs';
+import { switchMap } from 'rxjs/operators';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ExperimentService {
+ constructor(private baseApi: BaseApiService, private httpClient: HttpClient) {
+ }
+
+ fetchExperimentList(): Observable<ExperimentInfo[]> {
+ const apiUrl = this.baseApi.getRestApi('/v1/jobs');
+ return this.httpClient.get<Rest<ExperimentInfo[]>>(apiUrl).pipe(
+ switchMap(res => {
+ if (res.success) {
+ console.log(res.result);
+ return of(res.result);
+ } else {
+ throw this.baseApi.createRequestError(res.message, res.code, apiUrl, 'get');
+ }
+ })
+ );
+ }
+
+ createExperiment(experimentSpec): Observable<ExperimentInfo> {
+ const apiUrl = this.baseApi.getRestApi('/v1/jobs');
+ return this.httpClient.post<Rest<ExperimentInfo>>(apiUrl, experimentSpec).pipe(
+ switchMap(res => {
+ if (res.success) {
+ return of(res.result);
+ } else {
+ throw this.baseApi.createRequestError(res.message, res.code, apiUrl, 'post', experimentSpec);
+ }
+ })
+ );
+ }
+
+ editExperiment(experimentSpec): Observable<ExperimentInfo> {
+ const apiUrl = this.baseApi.getRestApi('/v1/jobs');
+ return this.httpClient.patch<Rest<ExperimentInfo>>(apiUrl, experimentSpec).pipe(
+ switchMap(res => {
+ if (res.success) {
+ return of(res.result);
+ } else {
+ throw this.baseApi.createRequestError(res.message, res.code, apiUrl, 'patch', experimentSpec);
+ }
+ })
+ );
+ }
+
+ deleteExperiment(id: string): Observable<ExperimentInfo> {
+ const apiUrl = this.baseApi.getRestApi('/v1/jobs/' + id);
+ return this.httpClient.delete<Rest<any>>(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