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/03/08 09:48:41 UTC

[submarine] branch master updated: SUBMARINE-397. [WEB]Implement the job page 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 6c68fa6  SUBMARINE-397. [WEB]Implement the job page in workbench with Angular
6c68fa6 is described below

commit 6c68fa6dbe9356e9bd6e51b6faa2b36f177137c1
Author: jasoonn <b0...@ntu.edu.tw>
AuthorDate: Sun Mar 8 09:32:57 2020 +0800

    SUBMARINE-397. [WEB]Implement the job page in workbench with Angular
    
    ### What is this PR for?
    Implement the job page in workbench with Angular.
    
    ### What type of PR is it?
    [Feature]
    
    ### Todos
    * [ ] - Task
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/browse/SUBMARINE-397
    
    ### How should this be tested?
    https://travis-ci.org/apache/submarine/builds/659683029?utm_source=github_status&utm_medium=notification
    
    ### Screenshots
    ![](https://i.imgur.com/faii8qm.gif)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: jasoonn <b0...@ntu.edu.tw>
    
    Closes #206 from jasoonn/SUBMARINE-397 and squashes the following commits:
    
    c1a192c [jasoonn] update jobIT
    cf4dda4 [jasoonn] update jobIT.java position
    37d830f [jasoonn] update
    94f1675 [jasoonn] update all
---
 .../org/apache/submarine/integration/jobIT.java    |  71 ++++++++++++
 .../src/app/pages/workbench/job/job.component.html | 128 ++++++++++++++++++++-
 .../src/app/pages/workbench/job/job.component.scss |  50 ++++++++
 .../src/app/pages/workbench/job/job.component.ts   |  69 +++++++++++
 .../job/{job.component.scss => job.module.ts}      |  10 +-
 .../src/app/pages/workbench/workbench.module.ts    |   5 +-
 6 files changed, 330 insertions(+), 3 deletions(-)

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/jobIT.java
new file mode 100644
index 0000000..aebe245
--- /dev/null
+++ b/submarine-test/test-e2e/src/test/java/org/apache/submarine/integration/jobIT.java
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+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;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+public class jobIT extends AbstractSubmarineIT {
+
+  public final static Logger LOG = LoggerFactory.getLogger(jobIT.class);
+
+  @BeforeClass
+  public static void startUp(){
+    LOG.info("[Testcase]: jobIT");
+    driver =  WebDriverManager.getWebDriver();
+  }
+
+  @AfterClass
+  public static void tearDown(){
+    driver.quit();
+  }
+
+  @Test
+  public void workspaceNavigation() throws Exception {
+    // Login
+    LOG.info("Login");
+    pollingWait(By.cssSelector("input[ng-reflect-name='userName']"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("admin");
+    pollingWait(By.cssSelector("input[ng-reflect-name='password']"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("admin");
+    clickAndWait(By.cssSelector("button[class='login-form-button ant-btn ant-btn-primary']"));
+    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");
+
+    // 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");
+    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);
+    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);
+    pollingWait(By.xpath("//button[@id='go']"), MAX_BROWSER_TIMEOUT_SEC).click();
+  }
+}
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/job/job.component.html
index fcc2676..f46c164 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/job/job.component.html
@@ -17,4 +17,130 @@
   ~ under the License.
   -->
 
-<p>job works!</p>
+<nz-layout style="margin: -24px -24px 16px;">
+  <nz-layout class="inner-layout">
+    <div id="jobOuter">
+      <nz-breadcrumb>
+        <nz-breadcrumb-item>
+          <a [routerLink]="['/', 'workbench', 'home']">Home</a>
+        </nz-breadcrumb-item>
+        <nz-breadcrumb-item>Job</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>
+      <br/>
+    </div>
+  </nz-layout>
+  <div id="jobData">
+    <div align="right">
+      <nz-radio-group [(ngModel)]="showJob" (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>
+      </nz-radio-group>
+      <nz-input-group  style="width:300px;margin-top: 15px;margin-left:10px;margin-right:5px;" [nzSuffix]="suffixIconSearch">
+        <input type="text" nz-input [(ngModel)]="searchText" (keydown)="filter($event)" placeholder="input search text" />
+      </nz-input-group>
+      <ng-template #suffixIconSearch>
+          <i nz-icon nzType="search"></i>
+      </ng-template>
+      <button nz-button id="openJob" nzType="primary" style="margin-right: 30px;margin-bottom: 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'">
+      <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>
+        </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.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>
+        </tr>
+      </tbody>
+    </nz-table>
+  </div>
+  <nz-modal
+      [(nzVisible)]="isVisible"
+      nzTitle="Create Job"
+      [(nzOkText)]="okText"
+      [nzOkLoading]="isOkLoading"
+      (nzOnCancel)="isVisible=false;"
+      [nzWidth]="740"
+  >
+    <div >
+      <nz-steps [nzCurrent]="current">
+        <nz-step nzTitle="Basic Information"></nz-step>
+        <nz-step nzTitle="Configuration"></nz-step>
+        <nz-step nzTitle="Scheduling Cycle"></nz-step>
+      </nz-steps>
+    </div>
+    <div>
+      <form [formGroup]="createJob">
+        <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 *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">
+            </div>
+            <div>
+              <label class="form-label"><span class="red-star">* </span>Description:</label>
+              <textarea rows="6" class="form-control" style="margin-top: 32px;width: 350px;" formControlName="description"></textarea>
+            </div>
+          </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>
+              </nz-select>
+            </div>
+            <div>
+              <label class="form-label"><span class="red-star">* </span> Rule Template:</label>
+              <nz-select formControlName="ruleTemplate" nzPlaceHolder="Choose" style="width: 350px;margin-top: 30px;">
+                <nz-option *ngFor="let ruleTemplate of ruleTemplates" [nzValue]="ruleTemplate" [nzLabel]="ruleTemplate"></nz-option>
+              </nz-select>
+            </div>
+            <div>
+              <label class="form-label"><span class="red-star">* </span> Rule Type:</label>
+              <nz-radio-group formControlName="ruleType" style="width: 350px;margin-top: 30px;margin-bottom: 30px;">
+                <label *ngFor="let ruletype of ruleTypes" nz-radio [nzValue]="ruletype">{{ ruletype }}</label>
+              </nz-radio-group>
+            </div>
+          </div>
+          <div *ngSwitchCase="2">
+            <div>
+              <label class="pg3-form-label"><span class="red-star">* </span> Start Date:</label>
+              <nz-date-picker [nzFormat]="'yyyy/MM/dd'" formControlName="startDate" style="width: 350px;margin-top: 30px;"></nz-date-picker>
+            </div>
+            <div>
+              <label class="pg3-form-label"><span class="red-star">* </span> Schedule Cycle:</label>
+              <nz-select formControlName="scheduleCycle" nzPlaceHolder="Choose" style="width: 195px;margin-top: 30px;margin-bottom: 30px;">
+                <nz-option *ngFor="let scheduleCycle of scheduleCycles" [nzValue]="scheduleCycle" [nzLabel]="scheduleCycle"></nz-option>
+              </nz-select>
+            </div>
+          </div>
+        </div>
+      </form>
+    </div>
+  </nz-modal>
+</nz-layout>
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/job/job.component.scss
index 3d56d22..88ee4fc 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/job/job.component.scss
@@ -16,3 +16,53 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
+ #jobOuter{
+    background-color: white;
+    padding-left: 30px;
+    padding-top: 20px;
+ }
+
+ #jobData{
+    margin-top: 25px;
+    margin-left: 20px;
+    margin-right: 20px;
+    background-color:white;
+    padding-left: 10px;
+    padding-right: 10px;
+ }
+
+ input.ng-invalid.ng-touched {
+   border: 1px solid red;
+ }
+
+ textarea.ng-invalid.ng-touched {
+   border: 1px solid red;
+}
+
+.red-star {
+   margin-top: 20px;
+   color: red;
+}
+
+.form-label {
+   float:left;
+   width:200px;
+   text-align: right;
+   padding-right: 12px;
+   margin-top: 32px;
+   margin-left: 10px;
+   clear: left;
+   color: black;
+}
+
+.pg3-form-label {
+   float:left;
+   width:200px;
+   text-align: right;
+   padding-right: 12px;
+   margin-top: 32px;
+   margin-left: 100px;
+   clear: left;
+   color: black;
+}
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
index 985fece..0c2e1b4 100644
--- 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
@@ -18,6 +18,7 @@
  */
 
 import { Component, OnInit } from '@angular/core';
+import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
 
 @Component({
   selector: 'submarine-job',
@@ -26,9 +27,77 @@ import { Component, OnInit } from '@angular/core';
 })
 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/job/job.component.scss b/submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.module.ts
similarity index 81%
copy from submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.component.scss
copy to submarine-workbench/workbench-web-ng/src/app/pages/workbench/job/job.module.ts
index 3d56d22..01a9df3 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/job/job.module.ts
@@ -1,4 +1,7 @@
-/*!
+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
  * distributed with this work for additional information
@@ -16,3 +19,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
+ @NgModule({
+    exports: [ReactiveFormsModule]
+ })
+ export class jobModule {}
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 25609cd..6346b80 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
@@ -31,6 +31,8 @@ import { WorkbenchComponent } from './workbench.component';
 import { WorkspaceComponent } from './workspace/workspace.component';
 import { FormsModule } from '@angular/forms';
 import { WorkspaceModule } from './workspace/workspace.module';
+import { jobModule } from './job/job.module';
+
 
 
 @NgModule({
@@ -49,7 +51,8 @@ import { WorkspaceModule } from './workspace/workspace.module';
     NgZorroAntdModule,
     RouterModule,
     FormsModule,
-    WorkspaceModule
+    WorkspaceModule,
+    jobModule
   ]
 })
 export class WorkbenchModule {


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