You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@griffin.apache.org by gu...@apache.org on 2018/08/03 07:35:50 UTC

[1/2] incubator-griffin git commit: [GRIFFIN-164][GRIFFIN-186][GRIFFIN-187] Profiling Re-factor + Regex/Empty String Support

Repository: incubator-griffin
Updated Branches:
  refs/heads/master 1c39b8369 -> d58bd194f


http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.ts b/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.ts
new file mode 100644
index 0000000..94e1d37
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.ts
@@ -0,0 +1,236 @@
+/*
+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, Input, Output, EventEmitter } from "@angular/core";
+import { ServiceService } from "../../../../service/service.service";
+import { TREE_ACTIONS, ITreeOptions } from "angular-tree-component";
+import { HttpClient } from "@angular/common/http";
+import { AfterViewChecked, ElementRef } from "@angular/core";
+import { ProfilingStep1 } from "../pr.component";
+
+export class node {
+  name: string;
+  id: number;
+  children: object[];
+  isExpanded: boolean;
+  cols: Col[];
+  parent: string;
+  location: string;
+}
+
+export class Rule {
+  type: string;
+}
+
+export class Col {
+  name: string;
+  type: string;
+  comment: string;
+  selected: boolean;
+  isNum: boolean;
+  isExpanded: boolean;
+  groupby: string;
+  RE: string;
+  rules: any;
+  newRules: Rule[];
+  constructor(name: string, type: string, comment: string, selected: boolean) {
+    this.name = name;
+    this.type = type;
+    this.comment = comment;
+    this.selected = false;
+    this.isExpanded = false;
+    this.groupby = "";
+    this.rules = [];
+    this.RE = "";
+    this.newRules = [];
+
+    var patt = new RegExp("int|double|float/i");
+    if (patt.test(this.type)) {
+      this.isNum = true;
+    }
+  }
+}
+
+@Component({
+  selector: "app-pr-step-1",
+  templateUrl: "./step1.component.html",
+  providers: [ServiceService],
+  styleUrls: ["./step1.component.css"]
+})
+
+export class PrStep1Component implements AfterViewChecked, OnInit {
+  selectedAll = false;
+
+  @Input() step1: ProfilingStep1;
+  @Output() nextStep: EventEmitter<Object> = new EventEmitter<Object>();
+
+  options: ITreeOptions = {
+    displayField: "name",
+    isExpandedField: "expanded",
+    idField: "id",
+    actionMapping: {
+      mouse: {
+        click: (tree, node, $event) => {
+          if (node.hasChildren) {
+            this.step1.currentDB = node.data.name;
+            this.step1.currentDBStr = this.step1.currentDB + ".";
+            this.step1.currentTable = "";
+            this.step1.schemaCollection = [];
+            this.selectedAll = false;
+            TREE_ACTIONS.TOGGLE_EXPANDED(tree, node, $event);
+          } else if (node.data.cols) {
+            this.step1.currentTable = node.data.name;
+            this.step1.currentDB = node.data.parent;
+            this.step1.schemaCollection = node.data.cols;
+            this.step1.srcname = "source" + new Date().getTime();
+            this.step1.srclocation = node.data.location;
+            this.selectedAll = false;
+            this.step1.selection = [];
+            for (let row of this.step1.schemaCollection) {
+              row.selected = false;
+            }
+          }
+        }
+      }
+    },
+    animateExpand: true,
+    animateSpeed: 30,
+    animateAcceleration: 1.2
+  };
+
+  public visible = false;
+  public visibleAnimate = false;
+
+  toggleSelection(row) {
+    row.selected = !row.selected;
+    var idx = this.step1.selection.indexOf(row);
+    // is currently selected
+    if (idx > -1) {
+      this.step1.selection.splice(idx, 1);
+      this.selectedAll = false;
+      for (let key in this.step1.selectedItems) {
+        if (key === row.name) {
+          delete this.step1.selectedItems[key];
+        }
+      }
+    } else {
+      // is newly selected
+      this.step1.selection.push(row);
+    }
+    if (this.step1.selection.length == 3) {
+      this.selectedAll = true;
+    } else {
+      this.selectedAll = false;
+    }
+    this.setDropdownList();
+  }
+
+  setDropdownList() {
+    if (this.step1.selection) {
+      for (let item of this.step1.selection) {
+        if (item.isNum == true) {
+          this.step1.dropdownList[item.name] = [
+            { id: 1, itemName: "Null Count", category: "Simple Statistics" },
+            { id: 2, itemName: "Distinct Count", category: "Simple Statistics" },
+            { id: 3, itemName: "Total Count", category: "Summary Statistics" },
+            { id: 4, itemName: "Maximum", category: "Summary Statistics" },
+            { id: 5, itemName: "Minimum", category: "Summary Statistics" },
+            { id: 6, itemName: "Average", category: "Summary Statistics" },
+            // {"id":7,"itemName":"Median","category": "Summary Statistics"},
+            // {"id":8,"itemName":"Rule Detection Count","category": "Advanced Statistics"},
+            { id: 9, itemName: "Enum Detection Top5 Count", category: "Advanced Statistics" }
+          ];
+        } else {
+          this.step1.dropdownList[item.name] = [
+            { id: 1, itemName: "Null Count", category: "Simple Statistics" },
+            { id: 2, itemName: "Distinct Count", category: "Simple Statistics" },
+            { id: 3, itemName: "Total Count", category: "Summary Statistics" },
+            // {"id":8,"itemName":"Rule Detection Count","category": "Advanced Statistics"},
+            { id: 9, itemName: "Enum Detection Top5 Count", category: "Advanced Statistics" },
+            { id: 10, itemName:"Regular Expression Detection Count", regex: "", category: "Advanced Statistics"},
+            { id: 11, itemName: "Empty Count", category: "Simple Statistics" }
+          ];
+        }
+      }
+    }
+  }
+
+  toggleAll() {
+    this.selectedAll = !this.selectedAll;
+    this.step1.selection = [];
+
+    for (var i = 0; i < this.step1.schemaCollection.length; i++) {
+      this.step1.schemaCollection[i].selected = this.selectedAll;
+      if (this.selectedAll) {
+        this.step1.selection.push(this.step1.schemaCollection[i]);
+      }
+    }
+    this.setDropdownList();
+  }
+
+  constructor(
+    private elementRef: ElementRef,
+    private http: HttpClient,
+    public serviceService: ServiceService
+  ) {}
+
+  ngOnInit() {
+    if (this.step1.nodeList.length !== 0) return;
+
+    let allDataassets = this.serviceService.config.uri.dataassetlist;
+
+    this.http.get(allDataassets).subscribe(data => {
+      this.step1.nodeList = new Array();
+      let i = 1;
+      this.step1.data = data;
+      for (let db in this.step1.data) {
+        let new_node = new node();
+        new_node.name = db;
+        new_node.id = i;
+        new_node.isExpanded = true;
+        i++;
+        new_node.children = new Array();
+        for (let i = 0; i < this.step1.data[db].length; i++) {
+          let new_child = new node();
+          new_child.name = this.step1.data[db][i]["tableName"];
+          new_node.children.push(new_child);
+          new_child.isExpanded = false;
+          new_child.location = this.step1.data[db][i]["sd"]["location"];
+          new_child.parent = db;
+          new_child.cols = Array<Col>();
+          for (let j = 0; j < this.step1.data[db][i]["sd"]["cols"].length; j++) {
+            let new_col = new Col(
+              this.step1.data[db][i]["sd"]["cols"][j].name,
+              this.step1.data[db][i]["sd"]["cols"][j].type,
+              this.step1.data[db][i]["sd"]["cols"][j].comment,
+              false
+            );
+            new_child.cols.push(new_col);
+          }
+        }
+        this.step1.nodeList.push(new_node);
+      }
+    });
+  }
+
+  nextChildStep() {
+    this.nextStep.emit(this.step1);
+  }
+
+  ngAfterViewChecked() {}
+}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.css b/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.css
new file mode 100644
index 0000000..af2cf72
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.css
@@ -0,0 +1,55 @@
+/*
+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 url('../../../../../../node_modules/angular2-toaster/toaster.css');
+@import url('../../../measure.component.css');
+
+fieldset {
+  height: 60vh;
+}
+
+label.stepDesc {
+  padding-left: 30px;
+  padding-right: 30px;
+}
+
+div.btn-container {
+  width: 100%;
+  padding-left: 15px;
+  padding-right: 15px;
+  clear: both;
+}
+
+div.btn-container > button.prev-step {
+  float: left;
+}
+
+div.btn-container > button.next-step {
+  float: right;
+}
+
+div.block {
+  margin: 20px 10px;
+  height: 26px;
+}
+
+div.block input {
+  width: 50%;
+  display: inline-block;
+}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.html
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.html b/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.html
new file mode 100644
index 0000000..2be8e20
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.html
@@ -0,0 +1,80 @@
+<!--
+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 class="container-fluid">
+  <label class="stepDesc">Please choose one of the profiling models provided below:</label>
+  <div class="container-fluid" id="notshowrule">
+    <div class="col-md-12 col-lg-12 col-sm-12">
+      <fieldset>
+        <div class="y-scrollable">
+          <div style="display:block">
+            <label style="margin-left:15px">View schema:</label> <i style="color:#fff;font-weight: bold;">{{step1.currentDB}}.{{step1.currentTable}}</i>
+          </div>
+          <div class="col-md-12 col-lg-12 col-sm-12" style="z-index:100;margin-top:5px;">
+            <table class="table table-striped" [mfData]="results" #mf="mfDataTable">
+              <thead>
+              <tr style="background-color:#7D95CC">
+                <th>Column Name</th>
+                <th>Data Type</th>
+                <th>Rule&nbsp;&nbsp;&nbsp;&nbsp;<i style="color:#b2c831;" class="fa fa-question-circle fa-lg"></i><i style="font-family: 'Open Sans', sans-serif;">Click <a (click)="showRule()" class="bark-link po">here</a> to view the rule definition</i></th>
+              </tr>
+              </thead>
+              <tbody>
+              <tr *ngFor="let item of step1.selection">
+                <td class="middle">{{item.name}}</td>
+                <td class="middle">{{item.type}}</td>
+                <td class="col-md-5 middle">
+                  <angular2-multiselect [data]="step1.dropdownList[item.name]" name="rules-{{item.name}}" [(ngModel)]="step2.selectedItems[item.name]" [settings]="dropdownSettings"></angular2-multiselect>
+                  <div *ngIf="containsRegex(step2.selectedItems[item.name])" class="block">
+                    <label class="regex-label">
+                      Regular Expression:
+                    </label>
+                    <input type="text" [(ngModel)]="step2.selectedItems[item.name].regex" class="form-control">
+                  </div>
+                </td>
+              </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+      </fieldset>
+    </div>
+    <div class="form-group btn-container">
+      <button class="btn btn-primary btn-o back-step btn-wide pull-left" (click)="prevChildStep()">
+        <i class="fa fa-arrow-circle-left"></i> Back
+      </button>
+      <button class="btn btn-primary btn-o next-step btn-wide pull-right" (click)="nextChildStep()">
+        Next <i class="fa fa-arrow-circle-right"></i>
+      </button>
+    </div>
+  </div>
+
+  <div class="container-fluid formStep" id="showrule" style="display:none;">
+    <div class="col-md-12 col-lg-12 col-sm-12">
+      <fieldset>
+        <app-rule></app-rule>
+      </fieldset>
+    </div>
+    <div class="form-group btn-container">
+      <button class="btn btn-primary btn-o back-step btn-wide pull-left" (click)="back()">
+        <i class="fa fa-arrow-circle-left"></i> Back
+      </button>
+    </div>
+  </div>
+
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.spec.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.spec.ts b/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.spec.ts
new file mode 100644
index 0000000..ca2149a
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.spec.ts
@@ -0,0 +1,43 @@
+/*
+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 { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PrStep2Component } from './step2.component';
+
+describe('PrStep2Component', () => {
+  let component: PrStep2Component;
+  let fixture: ComponentFixture<PrStep2Component>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ PrStep2Component ]
+    })
+      .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PrStep2Component);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should be created', () => {
+    expect(component).toBeTruthy();
+  });
+});

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.ts b/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.ts
new file mode 100644
index 0000000..cd5314a
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step2/step2.component.ts
@@ -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.
+*/
+import {Component, EventEmitter, Input, OnInit, Output} from "@angular/core";
+import { AfterViewChecked } from "@angular/core";
+import { AngularMultiSelectModule } from "angular2-multiselect-dropdown/angular2-multiselect-dropdown";
+import { ProfilingStep1, ProfilingStep2 } from './../pr.component'
+
+
+@Component({
+  selector: "app-pr-step-2",
+  templateUrl: "./step2.component.html",
+  styleUrls: ["./step2.component.css"]
+})
+export class PrStep2Component implements AfterViewChecked, OnInit {
+  dropdownSettings = {};
+
+  @Input() step1: ProfilingStep1[];
+  @Input() step2: ProfilingStep2[];
+  @Output() prevStep: EventEmitter<Object> = new EventEmitter<Object>();
+  @Output() nextStep: EventEmitter<Object> = new EventEmitter<Object>();
+
+  constructor() {}
+
+  showRule() {
+    document.getElementById("showrule").style.display = "";
+    document.getElementById("notshowrule").style.display = "none";
+  }
+
+  back() {
+    document.getElementById("showrule").style.display = "none";
+    document.getElementById("notshowrule").style.display = "";
+  }
+
+  nextChildStep() {
+    this.nextStep.emit(this.step2);
+  }
+
+  prevChildStep() {
+    this.prevStep.emit(this.step2);
+  }
+
+  containsRegex(obj){
+    if (!obj) return false;
+    return obj.some(rule =>
+      rule.itemName == 'Regular Expression Detection Count'
+    )
+  }
+
+  ngOnInit() {
+    this.dropdownSettings = {
+      singleSelection: false,
+      text: "Select Rule",
+      enableCheckAll: false,
+      enableSearchFilter: true,
+      classes: "myclass",
+      groupBy: "category"
+    };
+  }
+
+  ngAfterViewChecked() {}
+}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.css b/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.css
new file mode 100644
index 0000000..be33bcc
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.css
@@ -0,0 +1,37 @@
+/*
+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 url('../../../../../../node_modules/angular2-toaster/toaster.css');
+@import url('../../../measure.component.css');
+
+fieldset {
+  height: 60vh;
+}
+
+label.stepDesc {
+  padding-left: 30px;
+  padding-right: 30px;
+}
+
+div.btn-container {
+  width: 100%;
+  padding-left: 15px;
+  padding-right: 15px;
+  clear: both;
+}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.html
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.html b/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.html
new file mode 100644
index 0000000..b2ed563
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.html
@@ -0,0 +1,48 @@
+<!--
+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 class="container-fluid">
+  <label class="stepDesc">Please complete the partition configuration for {{step1.currentTable}}</label>
+  <div class="container-fluid">
+    <div class="col-md-12 col-lg-12 col-sm-12">
+      <fieldset>
+        <legend>
+          Required Information
+        </legend>
+        <div class="y-scrollable">
+            <div class="form-group" style="text-align:center">
+              Data Source:{{step1.currentDB}}.{{step1.currentTable}}
+            </div>
+            <app-configuration [data]="step3.config" [location]="srclocation" (event)="getData($event)"></app-configuration>
+        </div>
+      </fieldset>
+    </div>
+    <div class="form-group btn-container">
+      <button class="btn btn-primary btn-o back-step btn-wide pull-left" (click)="prevChildStep()">
+        <i class="fa fa-arrow-circle-left"></i> Back
+      </button>
+      <toaster-container></toaster-container>
+      <button class="btn btn-primary btn-o next-step btn-wide pull-right" (click)="nextChildStep()">
+        Next <i class="fa fa-arrow-circle-right"></i>
+      </button>
+    </div>
+  </div>
+</div>
+
+
+

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.spec.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.spec.ts b/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.spec.ts
new file mode 100644
index 0000000..da5ab2e
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.spec.ts
@@ -0,0 +1,43 @@
+/*
+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 { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PrStep3Component } from './step3.component';
+
+describe('PrStep3Component', () => {
+  let component: PrStep3Component;
+  let fixture: ComponentFixture<PrStep3Component>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ PrStep3Component ]
+    })
+      .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PrStep3Component);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should be created', () => {
+    expect(component).toBeTruthy();
+  });
+});

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.ts b/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.ts
new file mode 100644
index 0000000..79bf2d9
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step3/step3.component.ts
@@ -0,0 +1,57 @@
+/*
+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 { AfterViewChecked } from "@angular/core";
+import { ProfilingStep1, ProfilingStep2, ProfilingStep3 } from './../pr.component'
+
+@Component({
+  selector: "app-pr-step-3",
+  templateUrl: "./step3.component.html",
+  styleUrls: ["./step3.component.css"]
+})
+export class PrStep3Component implements AfterViewChecked, OnInit {
+  @Input() step1: ProfilingStep1;
+  @Input() step2: ProfilingStep2;
+  @Input() step3: ProfilingStep3;
+
+  @Output() prevStep: EventEmitter<Object> = new EventEmitter<Object>();
+  @Output() nextStep: EventEmitter<Object> = new EventEmitter<Object>();
+
+  constructor() {}
+
+  getData(evt) {
+    this.step3.config = evt;
+    this.step3.timezone = evt.timezone;
+    this.step3.where = evt.where;
+    this.step3.size = evt.num + evt.timetype;
+    this.step3.needpath = evt.needpath;
+    this.step3.path = evt.path;
+  }
+
+  nextChildStep() {
+    this.nextStep.emit(this.step3);
+  }
+
+  prevChildStep() {
+    this.prevStep.emit(this.step3);
+  }
+
+  ngOnInit() {}
+  ngAfterViewChecked() {}
+}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.css b/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.css
new file mode 100644
index 0000000..60d6e32
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.css
@@ -0,0 +1,42 @@
+/*
+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 url('../../../../../../node_modules/angular2-toaster/toaster.css');
+@import url('../../../measure.component.css');
+
+label.control-label {
+  margin-top: 7px;
+}
+
+fieldset {
+  height: 60vh;
+}
+
+label.stepDesc {
+  padding-left: 30px;
+  padding-right: 30px;
+}
+
+div.btn-container {
+  width: 100%;
+  padding-left: 15px;
+  padding-right: 15px;
+  clear: both;
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.html
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.html b/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.html
new file mode 100644
index 0000000..0efec50
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.html
@@ -0,0 +1,103 @@
+<!--
+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 class="container-fluid">
+  <label class="stepDesc">Please enter the required information for the measure!</label>
+  <div class="container-fluid">
+    <div class="col-md-12 col-lg-12 col-sm-12">
+      <fieldset>
+        <legend>
+          Required Information
+        </legend>
+        <div class="y-scrollable">
+          <div class="col-md-12 col-lg-12 col-sm-12" style="margin-top:55px;">
+            <div class="form-group" [ngClass]="{'has-error':prName.dirty&&prName.invalid, 'has-success':prName.valid}">
+              <label class="col-md-2 col-lg-2 col-sm-2 control-label">
+                Measure Name<span class="symbol required"></span>:
+              </label>
+              <div class="col-md-10 col-lg-10 col-sm-10 ">
+                <input type="text" class="form-control" [(ngModel)]="step4.prName" #prName="ngModel" placeholder="Please input the measure name" required pattern="^[a-zA-Z0-9_-]*$">
+                <span class="error text-small block " *ngIf="prName.dirty && (prName.errors?.required)">Measure Name is required</span>
+                <span class="error text-small block " *ngIf="prName.dirty && (prName.errors?.pattern)">Only letter, number, "-" and "_" are allowed</span>
+              </div>
+            </div>
+          </div>
+          <div class="col-md-12 col-lg-12 col-sm-12" style="margin-top:10px;">
+            <div class="form-group">
+              <label class="col-md-2 col-lg-2 col-sm-2 control-label">
+                Measure Description:
+              </label>
+              <div class="col-md-10 col-lg-10 col-sm-10">
+                <input type="text" class="form-control" [(ngModel)]="step4.desc" placeholder="Please input detailed description of your measure" name="desc">
+              </div>
+            </div>
+          </div>
+          <div class="col-md-12 col-lg-12 col-sm-12" style="margin-top:10px;">
+            <div class="form-group">
+              <label for="typeSelector" class="col-md-2 col-lg-2 col-sm-2 control-label">
+                Measure Type:
+              </label>
+              <div class="col-md-10 col-lg-10 col-sm-10">
+                <select id="typeSelector" class="form-control" [(ngModel)]="step4.type" disabled required name="type">
+                  <option>{{step4.type}}</option>
+                </select>
+              </div>
+            </div>
+          </div>
+          <div class="col-md-12 col-lg-12 col-sm-12" style="margin-top:10px;">
+            <div class="form-group">
+              <label class="col-md-2 col-lg-2 col-sm-2 control-label">
+                DataSource:
+              </label>
+              <div class="col-md-10 col-lg-10 col-sm-10">
+                <input type="text" class="form-control" name="DataAsset" value="{{step1.currentTable}}" disabled>
+              </div>
+            </div>
+          </div>
+          <div class="col-md-12 col-lg-12 col-sm-12" style="margin-top:10px;">
+            <div class="form-group">
+              <label class="col-md-2 col-lg-2 col-sm-2 control-label">
+                Owner:
+              </label>
+              <div class="col-md-10 col-lg-10 col-sm-10">
+                <input type="text" class="form-control" name="owner" disabled [(ngModel)]="step4.owner">
+              </div>
+            </div>
+          </div>
+        </div>
+        <div style="color:#b2c831">
+          <p>
+            <i class="fa fa-info-circle"></i> After submitted, please go to "<a class="bark-link" routerLink="/measures">Measures</a>" to check the measure status
+          </p>
+        </div>
+      </fieldset>
+    </div>
+    <div class="form-group btn-container">
+      <button class="btn btn-primary btn-o back-step btn-wide pull-left" (click)="prevChildStep()">
+        <i class="fa fa-arrow-circle-left"></i> Back
+      </button>
+      <toaster-container></toaster-container>
+      <button type="submit" (click)="submit()" class="btn btn-primary btn-o next-step btn-wide pull-right">
+        Submit
+      </button>
+    </div>
+  </div>
+</div>
+
+
+

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.spec.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.spec.ts b/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.spec.ts
new file mode 100644
index 0000000..c0ba718
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.spec.ts
@@ -0,0 +1,43 @@
+/*
+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 { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PrStep4Component } from './step4.component';
+
+describe('PrStep4Component', () => {
+  let component: PrStep4Component;
+  let fixture: ComponentFixture<PrStep4Component>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ PrStep4Component ]
+    })
+      .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PrStep4Component);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should be created', () => {
+    expect(component).toBeTruthy();
+  });
+});

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.ts b/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.ts
new file mode 100644
index 0000000..f3178af
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step4/step4.component.ts
@@ -0,0 +1,59 @@
+/*
+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, ChangeDetectorRef, AfterViewInit} from "@angular/core";
+import { FormControl } from "@angular/forms";
+import { FormsModule } from "@angular/forms";
+import { AfterViewChecked, ElementRef } from "@angular/core";
+import {ProfilingStep1, ProfilingStep2, ProfilingStep3, ProfilingStep4} from "../pr.component";
+
+@Component({
+  selector: "app-pr-step-4",
+  templateUrl: "./step4.component.html",
+  providers: [],
+  styleUrls: ["./step4.component.css"]
+})
+export class PrStep4Component implements AfterViewChecked, OnInit, AfterViewInit {
+
+  @Input() step1: ProfilingStep1;
+  @Input() step2: ProfilingStep2;
+  @Input() step3: ProfilingStep3;
+  @Input() step4: ProfilingStep4;
+
+  @Output() prevStep: EventEmitter<Object> = new EventEmitter<Object>();
+  @Output() submitMeasure: EventEmitter<Object> = new EventEmitter<Object>();
+
+  constructor(private cdr: ChangeDetectorRef) {}
+
+  prevChildStep() {
+    this.prevStep.emit(this.step4);
+    console.log(this.step4);
+  }
+
+  submit() {
+    this.submitMeasure.emit(this.step4);
+  }
+
+  ngOnInit() {}
+
+  ngAfterViewInit() {
+    this.cdr.detectChanges();
+  }
+
+  ngAfterViewChecked() {}
+}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pub/pub.component.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pub/pub.component.css b/ui/angular/src/app/measure/create-measure/pub/pub.component.css
index 5af6bbe..194a251 100644
--- a/ui/angular/src/app/measure/create-measure/pub/pub.component.css
+++ b/ui/angular/src/app/measure/create-measure/pub/pub.component.css
@@ -201,7 +201,6 @@ under the License.
   background-color: #000000;
   border-radius: 5px;
   padding: 10px;
-  max-height: 600px;
   /*height:800px;*/
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/measure.component.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/measure.component.css b/ui/angular/src/app/measure/measure.component.css
index ba60eab..0483912 100644
--- a/ui/angular/src/app/measure/measure.component.css
+++ b/ui/angular/src/app/measure/measure.component.css
@@ -55,10 +55,9 @@ under the License.
 .swMain>ul {
   display: table;
   list-style: none;
-  margin: 0 0 20px;
+  margin: 0 30px 20px 30px;
   padding: 10px 0;
   position: relative;
-  width: 100%;
   background: #f7f7f8;
   border-radius: 5px
 }
@@ -67,7 +66,6 @@ under the License.
   background-color: #000000;
   border-radius: 5px;
   padding: 10px;
-  max-height: 600px;
   /*height:800px;*/
 }
 
@@ -192,7 +190,6 @@ under the License.
 .swMain .y-scrollable {
   overflow-y: auto;
   overflow-x: hidden;
-  max-height: 600px;
 }
 
 fieldset {
@@ -397,4 +394,4 @@ a {
 }
 .swMain>ul li>div.selected1child .stepNumber {
   border-color: #007AFF
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/styles.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/styles.css b/ui/angular/src/styles.css
index 0ce15db..3f9f559 100644
--- a/ui/angular/src/styles.css
+++ b/ui/angular/src/styles.css
@@ -891,7 +891,7 @@ a:hover {
     }
 }
 
-@media (max-width: 991px) { 
+@media (max-width: 991px) {
     #footerwrap {
       width: 100%
     }
@@ -1074,7 +1074,7 @@ tbody {
 
 .normal{
   background-color: #00C853;
-  border-radius: 5px; 
+  border-radius: 5px;
   padding:3px 4px;
   display: inline-block;
   width: 70px;
@@ -1083,7 +1083,7 @@ tbody {
 
 .unnormal{
   background-color: #EF5350;
-  border-radius: 5px; 
+  border-radius: 5px;
   padding:3px 4px;
   display: inline-block;
   width: 70px;
@@ -1094,7 +1094,7 @@ tbody {
   position: absolute;
   z-index:1;
   height:100px;
-  background-color:white; 
+  background-color:white;
   /*width:80%;*/
   text-align: center;
   border: 5px solid #c5c5c5;
@@ -1112,7 +1112,7 @@ tbody {
   width:20%;
   height:100%;
   display: inline-block;
-  
+
 }
 
 
@@ -1120,7 +1120,7 @@ tbody {
   width:20%;
   height:100%;
   display: inline-block;
-  
+
 }
 
 #pmam{
@@ -1155,7 +1155,7 @@ tbody {
 }
 
 .myclass * div.selected-list .c-btn , .myclass * ul ,.myclass * div.list-area, .list-filter input{
-  background: #dcdad6; 
+  background: #dcdad6;
 }
 
 .myclass * div.arrow-up{
@@ -1195,4 +1195,5 @@ input{
 .y-scrollable {
   overflow-y: auto;
   overflow-x: hidden;
-}
\ No newline at end of file
+  height: 100%;
+}



[2/2] incubator-griffin git commit: [GRIFFIN-164][GRIFFIN-186][GRIFFIN-187] Profiling Re-factor + Regex/Empty String Support

Posted by gu...@apache.org.
[GRIFFIN-164][GRIFFIN-186][GRIFFIN-187] Profiling Re-factor + Regex/Empty String Support

We've been working away on Griffin here at Credit Karma, and we'd love to contribute back!

This PR tackles three separate tasks:

- [GRIFFIN-164](https://issues.apache.org/jira/browse/GRIFFIN-164): Regex Support
- [GRIFFIN-186](https://issues.apache.org/jira/browse/GRIFFIN-186): Create Profiling Measure Re-Factor
- [GRIFFIN-187](https://issues.apache.org/jira/browse/GRIFFIN-187): Empty String Support

The details for each of these tasks can be found in the JIRA tickets linked above!

Author: Spencer Hivert <sp...@creditkarma.com>

Closes #381 from spencer-hivert-ck/shivert/profiling-refactor-and-regex-support.


Project: http://git-wip-us.apache.org/repos/asf/incubator-griffin/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-griffin/commit/d58bd194
Tree: http://git-wip-us.apache.org/repos/asf/incubator-griffin/tree/d58bd194
Diff: http://git-wip-us.apache.org/repos/asf/incubator-griffin/diff/d58bd194

Branch: refs/heads/master
Commit: d58bd194f646e2f0ef3a5c4259b0195a759909f5
Parents: 1c39b83
Author: Spencer Hivert <sp...@creditkarma.com>
Authored: Fri Aug 3 15:35:41 2018 +0800
Committer: William Guo <gu...@apache.org>
Committed: Fri Aug 3 15:35:41 2018 +0800

----------------------------------------------------------------------
 .../step/builder/dsl/expr/LogicalExpr.scala     |  19 +
 .../step/builder/dsl/parser/BasicParser.scala   |   8 +-
 ui/angular/src/app/app.module.ts                |  10 +
 .../measure/create-measure/ac/ac.component.css  |  12 +-
 .../configuration/configuration.component.css   |   4 +
 .../configuration/configuration.component.html  |   6 +-
 .../pr/confirmModal/confirmModal.component.css  |  24 +
 .../pr/confirmModal/confirmModal.component.html | 128 +++
 .../confirmModal/confirmModal.component.spec.ts |  43 +
 .../pr/confirmModal/confirmModal.component.ts   |  46 ++
 .../measure/create-measure/pr/pr.component.css  | 137 +---
 .../measure/create-measure/pr/pr.component.html | 366 +--------
 .../measure/create-measure/pr/pr.component.ts   | 792 +++++++------------
 .../create-measure/pr/step1/step1.component.css | 141 ++++
 .../pr/step1/step1.component.html               |  78 ++
 .../pr/step1/step1.component.spec.ts            |  43 +
 .../create-measure/pr/step1/step1.component.ts  | 236 ++++++
 .../create-measure/pr/step2/step2.component.css |  55 ++
 .../pr/step2/step2.component.html               |  80 ++
 .../pr/step2/step2.component.spec.ts            |  43 +
 .../create-measure/pr/step2/step2.component.ts  |  77 ++
 .../create-measure/pr/step3/step3.component.css |  37 +
 .../pr/step3/step3.component.html               |  48 ++
 .../pr/step3/step3.component.spec.ts            |  43 +
 .../create-measure/pr/step3/step3.component.ts  |  57 ++
 .../create-measure/pr/step4/step4.component.css |  42 +
 .../pr/step4/step4.component.html               | 103 +++
 .../pr/step4/step4.component.spec.ts            |  43 +
 .../create-measure/pr/step4/step4.component.ts  |  59 ++
 .../create-measure/pub/pub.component.css        |   1 -
 .../src/app/measure/measure.component.css       |   7 +-
 ui/angular/src/styles.css                       |  17 +-
 32 files changed, 1796 insertions(+), 1009 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/measure/src/main/scala/org/apache/griffin/measure/step/builder/dsl/expr/LogicalExpr.scala
----------------------------------------------------------------------
diff --git a/measure/src/main/scala/org/apache/griffin/measure/step/builder/dsl/expr/LogicalExpr.scala b/measure/src/main/scala/org/apache/griffin/measure/step/builder/dsl/expr/LogicalExpr.scala
index af1223f..13317bb 100644
--- a/measure/src/main/scala/org/apache/griffin/measure/step/builder/dsl/expr/LogicalExpr.scala
+++ b/measure/src/main/scala/org/apache/griffin/measure/step/builder/dsl/expr/LogicalExpr.scala
@@ -86,6 +86,25 @@ case class LikeExpr(head: Expr, is: Boolean, value: Expr) extends LogicalExpr {
   }
 }
 
+case class RLikeExpr(head: Expr, is: Boolean, value: Expr) extends LogicalExpr {
+
+  addChildren(head :: value :: Nil)
+
+  def desc: String = {
+    val notStr = if (is) "" else " NOT"
+    s"${head.desc}${notStr} RLIKE ${value.desc}"
+  }
+  def coalesceDesc: String = {
+    val notStr = if (is) "" else " NOT"
+    s"${head.coalesceDesc}${notStr} RLIKE ${value.coalesceDesc}"
+  }
+
+  override def map(func: (Expr) => Expr): RLikeExpr = {
+    RLikeExpr(func(head), is, func(value))
+  }
+}
+
+
 case class IsNullExpr(head: Expr, is: Boolean) extends LogicalExpr {
 
   addChild(head)

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/measure/src/main/scala/org/apache/griffin/measure/step/builder/dsl/parser/BasicParser.scala
----------------------------------------------------------------------
diff --git a/measure/src/main/scala/org/apache/griffin/measure/step/builder/dsl/parser/BasicParser.scala b/measure/src/main/scala/org/apache/griffin/measure/step/builder/dsl/parser/BasicParser.scala
index ba6ac2c..18f7754 100644
--- a/measure/src/main/scala/org/apache/griffin/measure/step/builder/dsl/parser/BasicParser.scala
+++ b/measure/src/main/scala/org/apache/griffin/measure/step/builder/dsl/parser/BasicParser.scala
@@ -72,6 +72,7 @@ trait BasicParser extends JavaTokenParsers with Serializable {
     * <between-expr> ::= <math-expr> [<not>]? <between> (<math-expr> <and> <math-expr> | <range-expr>)
     * <range-expr> ::= "(" [<math-expr>]? [, <math-expr>]+ ")"
     * <like-expr> ::= <math-expr> [<not>]? <like> <math-expr>
+    * <rlike-expr> ::= <math-expr> [<not>]? <rlike> <math-expr>
     * <is-null-expr> ::= <math-expr> <is> [<not>]? <null>
     * <is-nan-expr> ::= <math-expr> <is> [<not>]? <nan>
     *
@@ -131,6 +132,7 @@ trait BasicParser extends JavaTokenParsers with Serializable {
     val AND_ONLY: Parser[String] = """(?i)and\s""".r
     val IS: Parser[String] = """(?i)is\s""".r
     val LIKE: Parser[String] = """(?i)like\s""".r
+    val RLIKE: Parser[String] = """(?i)rlike\s""".r
     val COMPARE: Parser[String] = "=" | "!=" | "<>" | "<=" | ">=" | "<" | ">"
     val LOGICAL_UNARY: Parser[String] = NOT
     val LOGICAL_BINARIES: Seq[Parser[String]] = Seq((COMPARE), (AND), (OR))
@@ -276,6 +278,7 @@ trait BasicParser extends JavaTokenParsers with Serializable {
     * <between-expr> ::= <math-expr> [<not>]? <between> (<math-expr> <and> <math-expr> | <range-expr>)
     * <range-expr> ::= "(" [<math-expr>]? [, <math-expr>]+ ")"
     * <like-expr> ::= <math-expr> [<not>]? <like> <math-expr>
+    * <rlike-expr> ::= <math-expr> [<not>]? <rlike> <math-expr>
     * <is-null-expr> ::= <math-expr> <is> [<not>]? <null>
     * <is-nan-expr> ::= <math-expr> <is> [<not>]? <nan>
     *
@@ -296,6 +299,9 @@ trait BasicParser extends JavaTokenParsers with Serializable {
   def likeExpr: Parser[LogicalExpr] = mathExpression ~ opt(NOT) ~ LIKE ~ mathExpression ^^ {
     case head ~ notOpt ~ _ ~ value => LikeExpr(head, notOpt.isEmpty, value)
   }
+  def rlikeExpr: Parser[LogicalExpr] = mathExpression ~ opt(NOT) ~ RLIKE ~ mathExpression ^^ {
+    case head ~ notOpt ~ _ ~ value => RLikeExpr(head, notOpt.isEmpty, value)
+  }
   def isNullExpr: Parser[LogicalExpr] = mathExpression ~ IS ~ opt(NOT) ~ NULL ^^ {
     case head ~ _ ~ notOpt ~ _ => IsNullExpr(head, notOpt.isEmpty)
   }
@@ -303,7 +309,7 @@ trait BasicParser extends JavaTokenParsers with Serializable {
     case head ~ _ ~ notOpt ~ _ => IsNanExpr(head, notOpt.isEmpty)
   }
 
-  def logicalFactor: Parser[LogicalExpr] = (inExpr | betweenExpr | likeExpr | isNullExpr | isNanExpr | mathExpression) ^^ {
+  def logicalFactor: Parser[LogicalExpr] = (inExpr | betweenExpr | likeExpr | rlikeExpr | isNullExpr | isNanExpr | mathExpression) ^^ {
     LogicalFactorExpr(_, false, None)
   } | LBR ~ logicalExpression ~ RBR ~ opt(asAlias) ^^ {
     case _ ~ expr ~ _ ~ aliasOpt => LogicalFactorExpr(expr, true, aliasOpt)

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/app.module.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/app.module.ts b/ui/angular/src/app/app.module.ts
index 8adb212..2c769f3 100644
--- a/ui/angular/src/app/app.module.ts
+++ b/ui/angular/src/app/app.module.ts
@@ -42,6 +42,11 @@ import { DataassetComponent } from './dataasset/dataasset.component';
 import { BatchComponent } from './job/create-job/batch/batch.component';
 import { AcComponent} from './measure/create-measure/ac/ac.component';
 import { PrComponent } from './measure/create-measure/pr/pr.component';
+import { PrStep1Component } from './measure/create-measure/pr/step1/step1.component';
+import { PrStep2Component } from './measure/create-measure/pr/step2/step2.component';
+import { PrStep3Component } from './measure/create-measure/pr/step3/step3.component';
+import { PrStep4Component } from './measure/create-measure/pr/step4/step4.component';
+import { PrConfirmModal } from './measure/create-measure/pr/confirmModal/confirmModal.component';
 import { PubComponent } from './measure/create-measure/pub/pub.component';
 import { LoginComponent } from './login/login.component';
 import { AngularMultiSelectModule } from 'angular2-multiselect-dropdown/angular2-multiselect-dropdown';
@@ -151,6 +156,11 @@ const appRoutes: Routes = [
     BatchComponent,
     AcComponent,
     PrComponent,
+    PrStep1Component,
+    PrStep2Component,
+    PrStep3Component,
+    PrStep4Component,
+    PrConfirmModal,
     PubComponent,
     LoginComponent,
     RuleComponent,

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/ac/ac.component.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/ac/ac.component.css b/ui/angular/src/app/measure/create-measure/ac/ac.component.css
index 80b9b91..83562af 100644
--- a/ui/angular/src/app/measure/create-measure/ac/ac.component.css
+++ b/ui/angular/src/app/measure/create-measure/ac/ac.component.css
@@ -20,6 +20,16 @@ under the License.
 @import url('../../../../../node_modules/angular2-toaster/toaster.css');
 @import url('../../measure.component.css');
 
+div.formStep {
+  min-height: 65vh;
+  margin-left: 30px;
+  margin-right: 30px;
+}
+
+h5.over-title {
+  margin-left: 30px;
+}
+
 div.tree div.tree-children::before,
 div.tree::before {
   content: "";
@@ -117,4 +127,4 @@ div.tree>treenode>div::before {
 
 div.tree>treenode>div>.node-wrapper>treenodeexpander>.toggle-children-wrapper {
   left: 22px
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/configuration/configuration.component.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/configuration/configuration.component.css b/ui/angular/src/app/measure/create-measure/configuration/configuration.component.css
index e884cdd..32f3d25 100644
--- a/ui/angular/src/app/measure/create-measure/configuration/configuration.component.css
+++ b/ui/angular/src/app/measure/create-measure/configuration/configuration.component.css
@@ -16,3 +16,7 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
+
+label.control-label {
+  margin-top: 7px;
+}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/configuration/configuration.component.html
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/configuration/configuration.component.html b/ui/angular/src/app/measure/create-measure/configuration/configuration.component.html
index ae2a1e3..9f4a926 100644
--- a/ui/angular/src/app/measure/create-measure/configuration/configuration.component.html
+++ b/ui/angular/src/app/measure/create-measure/configuration/configuration.component.html
@@ -26,7 +26,7 @@ under the License.
     </div>
   </div>
 </div>
-<div class="col-md-12 col-lg-12 col-sm-12">
+<div class="col-md-12 col-lg-12 col-sm-12" style="margin-top:10px;">
   <div class="form-group">
     <label class="col-md-2 col-lg-2 col-sm-2 control-label" title="Your minimum partition size">
       Partition Size:
@@ -41,7 +41,7 @@ under the License.
     </div>
   </div>
 </div>
-<div class="col-md-12 col-lg-12 col-sm-12">
+<div class="col-md-12 col-lg-12 col-sm-12" style="margin-top:10px;">
   <div class="form-group">
     <label class="col-md-2 col-lg-2 col-sm-2 control-label">
       Time Zone:
@@ -53,7 +53,7 @@ under the License.
     </div>
   </div>
 </div>
-<div class="col-md-12 col-lg-12 col-sm-12" style="height: 30px;">
+<div class="col-md-12 col-lg-12 col-sm-12" style="margin-top: 30px; height: 30px;">
   <div class="form-group">
     <input style="margin-left:15px" type="checkbox" [checked]="needpath" (change)="needpath=!needpath;upward()">
     <label>

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.css b/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.css
new file mode 100644
index 0000000..e52c8ac
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.css
@@ -0,0 +1,24 @@
+/*
+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.
+*/
+
+.viewrule-content {
+  border: 1px solid #fff;
+  border-radius: 4px;
+  padding: 10px;
+}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.html
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.html b/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.html
new file mode 100644
index 0000000..92a3afc
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.html
@@ -0,0 +1,128 @@
+<!--
+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 class="modal-dialog modal-xg modal-lg">
+  <div class="modal-content">
+    <div class="modal-header">
+      <button type="button" class="close" (click)="hideModal()">&times;</button>
+      <h4 class="modal-title">Create measure with the below information?</h4>
+    </div>
+    <div class="modal-body">
+      <div class="container-fluid" id="viewruleContent" style="overflow:auto;">
+        <div class="row">
+          <h5 class="over-title margin-bottom-15">Basic information</h5>
+        </div>
+        <div class="row">
+          <div class="col-lg-12 col-md-12 col-sm-12">
+            <div id="viewrule-definition" class="viewrule-content">
+              <div class="row">
+                <label class="col-md-4 col-lg-4 col-sm-4">
+                  Measure Name:
+                </label>
+                <div class="col-md-8 col-lg-8 col-sm-8 ">
+                  {{step4.prName}}
+                </div>
+              </div>
+              <div class="row">
+                <label class="col-md-4 col-lg-4 col-sm-4">
+                  Measure Description:
+                </label>
+                <div class="col-md-8 col-lg-8 col-sm-8 ">
+                  {{step4.desc}}
+                </div>
+              </div>
+              <div class="row">
+                <label class="col-md-4 col-lg-4 col-sm-4">
+                  Measure Type:
+                </label>
+                <div class="col-md-8 col-lg-8 col-sm-8 ">
+                  {{step4.type}}
+                </div>
+              </div>
+              <div class="row">
+                <label class="col-md-4 col-lg-4 col-sm-4">
+                  DataSource:
+                </label>
+                <div class="col-md-8 col-lg-8 col-sm-8">
+                  {{step1.currentDB}}.{{step1.currentTable}}
+                </div>
+              </div>
+              <div class="row" *ngIf="step3.size">
+                <label class="col-md-4 col-lg-4 col-sm-4">
+                  Source Partition Size:
+                </label>
+                <div class="col-md-8 col-lg-8 col-sm-8">
+                  {{step3.size}}
+                </div>
+              </div>
+              <div class="row">
+                <label class="col-md-4 col-lg-4 col-sm-4">
+                  Source Time Zone:
+                </label>
+                <div class="col-md-8 col-lg-8 col-sm-8">
+                  {{step3.timezone}}
+                </div>
+              </div>
+              <div class="row" *ngIf="step3.config['where']">
+                <label class="col-md-4 col-lg-4 col-sm-4">
+                  Source Where (Parititon):
+                </label>
+                <div class="col-md-8 col-lg-8 col-sm-8">
+                  {{step3.config['where']}}
+                </div>
+              </div>
+              <div class="row" *ngIf="step3.config['whereCriteria']">
+                <label class="col-md-4 col-lg-4 col-sm-4">
+                  Source Where (Criteria):
+                </label>
+                <div class="col-md-8 col-lg-8 col-sm-8">
+                  {{step3.config['whereCriteria']}}
+                </div>
+              </div>
+              <div class="row" *ngIf="step3.needpath && step3.path">
+                <label class="col-md-4 col-lg-4 col-sm-4">
+                  Source Path:
+                </label>
+                <div class="col-md-8 col-lg-8 col-sm-8">
+                  {{step3.path}}
+                </div>
+              </div>
+              <div class="row">
+                <label class="col-md-4 col-lg-4 col-sm-4">
+                  Owner:
+                </label>
+                <div class="col-md-8 col-lg-8 col-sm-8">
+                  {{step4.owner}}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <h5 class="row">Rules</h5>
+        <div class="row" *ngFor="let index of step4.noderule;">
+          &nbsp;&nbsp;&nbsp;&nbsp;{{index.name}}&nbsp;:&nbsp;{{index.infos}}
+        </div>
+        <br/>
+      </div>
+    </div>
+    <div class="modal-footer">
+      <button type="button" class="btn btn-default" (click)="hideModal()">Cancel</button>
+      <button type="button" id="save" class="btn btn-primary" (click)="saveModal()">Save</button>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.spec.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.spec.ts b/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.spec.ts
new file mode 100644
index 0000000..dddc650
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.spec.ts
@@ -0,0 +1,43 @@
+/*
+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 { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PrConfirmModal } from './confirmModal.component';
+
+describe('PrConfirmModalComponent', () => {
+  let component: PrConfirmModal;
+  let fixture: ComponentFixture<PrConfirmModal>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ PrConfirmModal ]
+    })
+      .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PrConfirmModal);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should be created', () => {
+    expect(component).toBeTruthy();
+  });
+});

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.ts b/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.ts
new file mode 100644
index 0000000..d19022c
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/confirmModal/confirmModal.component.ts
@@ -0,0 +1,46 @@
+/*
+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, Output} from "@angular/core";
+import {ProfilingStep1, ProfilingStep2, ProfilingStep3, ProfilingStep4} from "../pr.component";
+
+@Component({
+  selector: "app-pr-confirm-modal",
+  templateUrl: "./confirmModal.component.html",
+  styleUrls: ["./confirmModal.component.css"]
+})
+export class PrConfirmModal {
+
+  @Input() step1: ProfilingStep1;
+  @Input() step2: ProfilingStep2;
+  @Input() step3: ProfilingStep3;
+  @Input() step4: ProfilingStep4;
+
+  @Output() hide: EventEmitter<Object> = new EventEmitter<Object>();
+  @Output() saveMeasure: EventEmitter<Object> = new EventEmitter<Object>();
+
+  constructor() {}
+
+  hideModal() {
+    this.hide.emit();
+  }
+
+  saveModal() {
+    this.saveMeasure.emit()
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/pr.component.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/pr.component.css b/ui/angular/src/app/measure/create-measure/pr/pr.component.css
index 512868c..8217c9c 100644
--- a/ui/angular/src/app/measure/create-measure/pr/pr.component.css
+++ b/ui/angular/src/app/measure/create-measure/pr/pr.component.css
@@ -20,107 +20,14 @@ under the License.
 @import url('../../../../../node_modules/angular2-toaster/toaster.css');
 @import url('../../measure.component.css');
 
-.selected-list .c-list .c-token {
-  background: #6faece;
+div.formStep {
+  min-height: 65vh;
+  margin-left: 30px;
+  margin-right: 30px;
 }
 
-div.tree div.tree-children::before,
-div.tree::before {
-  content: "";
-  position: absolute;
-  border-left: 1px dotted #23527c;
-  height: 100%;
-  top: -14px;
-  left: 12px
-}
-
-tree-root {
-  color: #999;
-}
-
-div.tree {
-  padding-left: 0;
-  margin-left: -5px
-}
-
-div.tree div.tree-children {
-  position: relative;
-  padding-left: 0;
-  margin-left: 16px
-}
-
-div.tree div.tree-children::before {
-  left: 5px
-}
-
-div.tree treenode>div>.node-wrapper {
-  margin-left: 24px
-}
-
-div.tree treenode>div>.node-wrapper>.node-content-wrapper {
-  margin-left: 4px
-}
-
-div.tree treenode>div.tree-node-leaf>.node-wrapper {
-  margin-left: 0
-}
-
-div.tree treenode>div::before {
-  content: "";
-  position: absolute;
-  border-bottom: 1px dotted #23527c;
-  width: 7px;
-  margin-top: 12px;
-  left: 7px
-}
-
-div.tree treenode>div .toggle-children-wrapper {
-  width: 13px;
-  height: 13px;
-  border: 1px solid #23527c;
-  position: absolute;
-  left: 15px;
-  margin-top: 5px;
-  margin-left: 0;
-  display: inline-block;
-  background-color: #fff;
-  z-index: 1
-}
-
-div.tree treenode>div .toggle-children-wrapper::before {
-  content: "";
-  display: inline-block;
-  width: 7px;
-  border-top: 1px solid #23527c;
-  position: absolute;
-  top: 5px;
-  left: 2px
-}
-
-div.tree treenode>div .toggle-children-wrapper.toggle-children-wrapper-collapsed::after {
-  content: "";
-  display: inline-block;
-  height: 7px;
-  border-left: 1px solid #23527c;
-  position: absolute;
-  top: 2px;
-  left: 5px
-}
-
-div.tree treenode>div .toggle-children-wrapper .toggle-children {
-  display: none
-}
-
-div.tree treenode>div .node-content-wrapper {
-  margin-left: 4px
-}
-
-div.tree>treenode>div::before {
-  left: 14px
-}
-
-div.tree>treenode>div>.node-wrapper>treenodeexpander>.toggle-children-wrapper {
-  left: 22px
+h5.over-title {
+  margin-left: 30px;
 }
 
 label {
@@ -131,35 +38,3 @@ label {
   max-height: 40vh;
   overflow-y: scroll;
 }
-
-.badgebox {
-  opacity: 0;
-}
-
-.badgebox+.badge {
-  /* Move the check mark away when unchecked */
-  text-indent: -999999px;
-  /* Makes the badge's width stay the same checked and unchecked */
-  width: 27px;
-}
-
-.badgebox:focus+.badge {
-  /* Set something to make the badge looks focused */
-  /* This really depends on the application, in my case it was: */
-  /* Adding a light border */
-  box-shadow: inset 0px 0px 5px;
-  /* Taking the difference out of the padding */
-}
-
-.badgebox:checked+.badge {
-  /* Move the check mark back when checked */
-  text-indent: 0;
-}
-
-.middle {
-  vertical-align: middle;
-}
-
-.no-border {
-  border: 1px solid transparent !important;
-}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/pr.component.html
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/pr.component.html b/ui/angular/src/app/measure/create-measure/pr/pr.component.html
index 1767845..22b1f4d 100644
--- a/ui/angular/src/app/measure/create-measure/pr/pr.component.html
+++ b/ui/angular/src/app/measure/create-measure/pr/pr.component.html
@@ -16,378 +16,60 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 -->
-<div class="container-fluid" (window:resize)="onResize($event)">
+<div class="container-fluid">
   <div class="row">
     <h5 class="over-title margin-bottom-15">Create Measure</h5>
+    <toaster-container></toaster-container>
   </div>
   <div class="row">
     <form name="Form" id="form" #prForm="ngForm" novalidate>
       <div id="wizard" class="swMain">
         <ul>
-          <li (click)="goTo(1)">
+          <li>
             <a [ngClass]="{'selected' : currentStep >= 1, 'done' : currentStep > 1}" class="selected">
-              <div class="stepNumber">
-                1
-              </div>
-              <span class="stepDesc text-small"> Choose Source </span>
+              <div class="stepNumber">1</div>
+              <span class="stepDesc text-small">Choose Source</span>
             </a>
           </li>
-          <li (click)="goTo(2)">
+          <li>
             <a [ngClass]="{'selected' : currentStep >= 2, 'done' : currentStep > 2}" class="" style="">
-              <div class="stepNumber">
-                2
-              </div>
-              <span class="stepDesc text-small"> Select Models </span>
+              <div class="stepNumber">2</div>
+              <span class="stepDesc text-small">Select Models</span>
             </a>
           </li>
-          <li (click)="goTo(3)">
+          <li>
             <a [ngClass]="{'selected' : currentStep >= 3, 'done' : currentStep > 3}">
-              <div class="stepNumber">
-                3
-              </div>
-              <span class="stepDesc text-small">Partition Configuration </span>
+              <div class="stepNumber">3</div>
+              <span class="stepDesc text-small">Partition Configuration</span>
             </a>
           </li>
-          <li (click)="goTo(4)">
+          <li>
             <a [ngClass]="{'selected' : currentStep >= 4, 'done' : currentStep > 4}">
-              <div class="stepNumber">
-                4
-              </div>
-              <span class="stepDesc text-small"> Configuration </span>
+              <div class="stepNumber">4</div>
+              <span class="stepDesc text-small">Configuration</span>
             </a>
           </li>
         </ul>
       </div>
+
       <div id="step-1" *ngIf="currentStep == 1" class="formStep">
-        <label class="stepDesc">This step let you choose the single source of truth for data quality comparision with target. Currently you can only select the attributes from one schema</label>
-        <div class="container-fluid">
-          <div class="col-md-4 col-lg-4 col-sm-4">
-            <fieldset>
-              <legend>Please select schema</legend>
-              <tree-root [nodes]="nodeList" [options]="options"></tree-root>
-            </fieldset>
-          </div>
-          <div class="col-md-8 col-lg-8 col-sm-8">
-            <fieldset>
-              <legend>
-                Select attributes
-              </legend>
-              <div class="y-scrollable">
-                <div style="margin-top:10px;">
-                  <label>View schema:</label>
-                  <i style="color:#fff;font-weight: bold;">{{currentDBstr}}{{currentTable}}
-                    </i>
-                </div>
-                <div style="margin-top:5px;">
-                  <table class="table table-striped no-border">
-                    <thead>
-                      <tr style="background-color:#7D95CC">
-                        <th>
-                          <input type="checkbox" (click)="toggleAll()" [checked]="selectedAll" />
-                        </th>
-                        <th>Column Name</th>
-                        <th>Type</th>
-                        <th>Comment</th>
-                      </tr>
-                    </thead>
-                    <tbody>
-                      <tr *ngIf="!schemaCollection || schemaCollection.length == 0">
-                        <td colspan="5" style="text-align:center;"><span class="highlight">Please select a schema from the left tree first</span></td>
-                      </tr>
-                      <tr *ngFor="let row of schemaCollection">
-                        <td>
-                          <input type="checkbox" (click)='toggleSelection(row)' [checked]="row.selected" value={{row.name}} />
-                        </td>
-                        <td>{{row.name}}</td>
-                        <td>{{row.type}}</td>
-                        <td>{{row.comment}}</td>
-                      </tr>
-                    </tbody>
-                  </table>
-                </div>
-              </div>
-            </fieldset>
-          </div>
-          <div class="form-group btn-container">
-            <toaster-container></toaster-container>
-            <button class="btn btn-primary btn-o next-step btn-wide pull-right" (click)="next(Form)">
-              Next <i class="fa fa-arrow-circle-right"></i>
-            </button>
-          </div>
-        </div>
+        <app-pr-step-1 [step1]='step1' (nextStep)='updateStep1($event)'></app-pr-step-1>
       </div>
+
       <div id="step-2" *ngIf="currentStep == 2" class="formStep">
-        <label class="stepDesc">Please choose one of the profiling models provided below:</label>
-        <div class="container-fluid" id="notshowrule">
-          <div class="col-md-12 col-lg-12 col-sm-12">
-            <!-- <fieldset style="max-height:400px;overflow-y:scroll;"> -->
-            <fieldset>
-              <div class="y-scrollable">
-                <div style="display:block">
-                  <label style="margin-left:15px">View schema:</label> <i style="color:#fff;font-weight: bold;">{{currentDB}}.{{currentTable}}</i>
-                </div>
-                <div class="col-md-12 col-lg-12 col-sm-12" style="z-index:100;margin-top:5px;">
-                  <table class="table table-striped" [mfData]="results" #mf="mfDataTable">
-                    <thead>
-                      <tr style="background-color:#7D95CC">
-                        <th>Column Name</th>
-                        <th>Data Type</th>
-                        <th>Rule&nbsp;&nbsp;&nbsp;&nbsp;<i style="color:#b2c831;" class="fa fa-question-circle fa-lg"></i><i style="font-family: 'Open Sans', sans-serif;">Click <a (click)="showRule()" class="bark-link po">here</a> to view the rule definition</i></th>
-                      </tr>
-                    </thead>
-                    <tbody>
-                      <tr *ngFor="let item of selection">
-                        <td class="middle">{{item.name}}</td>
-                        <td class="middle">{{item.type}}</td>
-                        <td class="col-md-5 middle">
-                          <angular2-multiselect [data]="dropdownList[item.name]" name="rules-{{item.name}}" [(ngModel)]="selectedItems[item.name]" [settings]="dropdownSettings"></angular2-multiselect>
-                        </td>
-                      </tr>
-                    </tbody>
-                  </table>
-                </div>
-                <!-- <div *ngFor="let index of transrule">&nbsp;&nbsp;&nbsp;&nbsp;{{index}}</div> -->
-              </div>
-            </fieldset>
-          </div>
-          <div class="form-group btn-container">
-            <button class="btn btn-primary btn-o back-step btn-wide pull-left" (click)="prev(Form)">
-              <i class="fa fa-arrow-circle-left"></i> Back
-            </button>
-            <toaster-container></toaster-container>
-            <button class="btn btn-primary btn-o next-step btn-wide pull-right" (click)="next(Form)">
-              Next <i class="fa fa-arrow-circle-right"></i>
-            </button>
-          </div>
-        </div>
-        <div class="container-fluid formStep" id="showrule" style="display:none;">
-          <div class="col-md-12 col-lg-12 col-sm-12">
-            <fieldset>
-              <app-rule></app-rule>
-            </fieldset>
-          </div>
-          <div class="form-group btn-container">
-            <button class="btn btn-primary btn-o back-step btn-wide pull-left" (click)="back()">
-              <i class="fa fa-arrow-circle-left"></i> Back
-            </button>
-          </div>
-        </div>
+        <app-pr-step-2 [step1]='step1' [step2]='step2' (prevStep)='prev($event)' (nextStep)='updateStep2($event)'></app-pr-step-2>
       </div>
+
       <div id="step-3" *ngIf="currentStep == 3" class="formStep">
-        <label class="stepDesc">Please complete the partition configuration for {{currentTable}}</label>
-        <div class="container-fluid">
-          <div class="col-md-12 col-lg-12 col-sm-12">
-            <fieldset>
-              <legend>
-                Required Information
-              </legend>
-              <div class="y-scrollable">
-                <div class="col-md-12 col-lg-12 col-sm-12">
-                  <div class="form-group" style="text-align:center">
-                    Data Source:{{currentDB}}.{{currentTable}}
-                  </div>
-                  <app-configuration [data]="config" [location]="srclocation" (event)="getData($event)"></app-configuration>
-                </div>
-              </div>
-            </fieldset>
-          </div>
-          <div class="form-group btn-container">
-            <button class="btn btn-primary btn-o back-step btn-wide pull-left" (click)="prev(Form)">
-              <i class="fa fa-arrow-circle-left"></i> Back
-            </button>
-            <toaster-container></toaster-container>
-            <button class="btn btn-primary btn-o next-step btn-wide pull-right" (click)="next(Form)">
-              Next <i class="fa fa-arrow-circle-right"></i>
-            </button>
-          </div>
-        </div>
+        <app-pr-step-3 [step1]='step1' [step2]='step2' [step3]='step3' (prevStep)='prev($event)' (nextStep)='updateStep3($event)'></app-pr-step-3>
       </div>
+
       <div id="step-4" *ngIf="currentStep == 4" class="formStep">
-        <label class="stepDesc">Please setup the measure required information</label>
-        <div class="container-fluid">
-          <div class="col-md-12 col-lg-12 col-sm-12">
-            <fieldset>
-              <legend>
-                Required Information
-              </legend>
-              <div class="y-scrollable">
-                <div class="col-md-12 col-lg-12 col-sm-12" style="margin-top:30px;">
-                  <div class="form-group" [ngClass]="{'has-error':prName.dirty&&prName.invalid, 'has-success':prName.valid}">
-                    <label class="col-md-2 col-lg-2 col-sm-2 control-label">
-                      Measure Name<span class="symbol required"></span>:
-                    </label>
-                    <div class="col-md-10 col-lg-10 col-sm-10 ">
-                      <input type="text" class="form-control" [(ngModel)]="name" #prName="ngModel" name="prName" placeholder="Please input the measure name" required pattern="^[a-zA-Z0-9_-]*$">
-                      <span class="error text-small block " *ngIf="prName.dirty && (prName.errors?.required)">Measure Name is required</span>
-                      <span class="error text-small block " *ngIf="prName.dirty && (prName.errors?.pattern)">Only letter, number, "-" and "_" are allowed</span>
-                    </div>
-                  </div>
-                </div>
-                <div class="col-md-12 col-lg-12 col-sm-12">
-                  <div class="form-group">
-                    <label class="col-md-2 col-lg-2 col-sm-2 control-label">
-                      Measure Description:
-                    </label>
-                    <div class="col-md-10 col-lg-10 col-sm-10 ">
-                      <input type="text" class="form-control" [(ngModel)]="desc" placeholder="Please input detailed description of your measure" name="desc">
-                    </div>
-                  </div>
-                </div>
-                <div class="col-md-12 col-lg-12 col-sm-12">
-                  <div class="form-group">
-                    <label for="typeSelector" class="col-md-2 col-lg-2 col-sm-2 control-label">
-                      Measure Type:<span class="symbol required"></span>:
-                    </label>
-                    <div class="col-md-10 col-lg-10 col-sm-10 ">
-                      <select id="typeSelector" class="form-control" [(ngModel)]="type" disabled required name="type">
-                        <option>{{type}}</option>
-                      </select>
-                    </div>
-                  </div>
-                </div>
-                <div class="col-md-12 col-lg-12 col-sm-12">
-                  <div class="form-group">
-                    <label class="col-md-2 col-lg-2 col-sm-2 control-label">
-                      DataSource:<span class="symbol required"></span>:
-                    </label>
-                    <div class="col-md-10 col-lg-10 col-sm-10">
-                       <input type="text" class="form-control" [(ngModel)]="currentTable" #prDataSource="ngModel" name="prDataSource" [readonly]="true" required   >
-                       <span class="error text-small block " *ngIf="prDataSource.dirty && (prDataSource.errors?.required)">Data source is required</span>
-                    </div>
-                  </div>
-                </div>
-                <div class="col-md-12 col-lg-12 col-sm-12">
-                  <div class="form-group">
-                    <label class="col-md-2 col-lg-2 col-sm-2 control-label">
-                      Owner:
-                    </label>
-                    <div class="col-md-10 col-lg-10 col-sm-10">
-                      <input type="text" class="form-control" name="owner" disabled [(ngModel)]="owner">
-                    </div>
-                  </div>
-                </div>
-              </div>
-              <div style="color:#b2c831">
-                <p>
-                  <i class="fa fa-info-circle"></i> After submitted, please go to "<a class="bark-link" routerLink="/measures">Measures</a>" to check the measure status
-                </p>
-              </div>
-            </fieldset>
-          </div>
-          <div class="form-group btn-container">
-            <button class="btn btn-primary btn-o back-step btn-wide pull-left" (click)="prev(Form)">
-              <i class="fa fa-arrow-circle-left"></i> Back
-            </button>
-            <toaster-container></toaster-container>
-            <button type="submit" (click)="submit(prForm)" class="btn btn-primary btn-o next-step btn-wide pull-right">
-              Submit
-            </button>
-          </div>
-        </div>
+        <app-pr-step-4 [step1]='step1' [step2]='step2' [step3]='step3' [step4]='step4' (prevStep)='prev($event)' (submitMeasure)='submit($event)'></app-pr-step-4>
       </div>
+
       <div class="modal fade" id="confirm" role="dialog" #modal tabindex="-1" [ngClass]="{'in': visibleAnimate}" [ngStyle]="{'display': visible ? 'block' : 'none', 'opacity': visibleAnimate ? 1 : 0}" (click)="onContainerClicked($event)">
-        <div class="modal-dialog modal-xg modal-lg">
-          <div class="modal-content">
-            <div class="modal-header">
-              <button type="button" class="close" (click)="hide()">&times;</button>
-              <h4 class="modal-title">Save the measure with the below information?</h4>
-            </div>
-            <div class="modal-body">
-              <div class="container-fluid" id="viewruleContent" style="overflow:auto;">
-                <div class="row">
-                  <h5 class="over-title margin-bottom-15">Basic information</h5>
-                </div>
-                <div class="row">
-                  <div class="col-lg-12 col-md-12 col-sm-12">
-                    <div id="viewrule-definition" class="viewrule-content">
-                      <div class="row">
-                        <label class="col-md-4 col-lg-4 col-sm-4">
-                          Measure Name:
-                        </label>
-                        <div class="col-md-8 col-lg-8 col-sm-8 ">
-                          {{name}}
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-md-4 col-lg-4 col-sm-4">
-                          Measure Description:
-                        </label>
-                        <div class="col-md-8 col-lg-8 col-sm-8 ">
-                          {{desc}}
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-md-4 col-lg-4 col-sm-4">
-                          Measure Type:
-                        </label>
-                        <div class="col-md-8 col-lg-8 col-sm-8 ">
-                          {{type}}
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-md-4 col-lg-4 col-sm-4">
-                          DataSource:
-                        </label>
-                        <div class="col-md-8 col-lg-8 col-sm-8"  *ngIf="this.currentTable">
-                          {{currentDB}}.{{currentTable}}
-                        </div>
-                      </div>
-                      <div class="row" *ngIf="this.size">
-                        <label class="col-md-4 col-lg-4 col-sm-4">
-                          Source Partition Size:
-                        </label>
-                        <div class="col-md-8 col-lg-8 col-sm-8">
-                          {{this.size}}
-                        </div>
-                      </div>
-                      <div class="row" *ngIf="this.size">
-                        <label class="col-md-4 col-lg-4 col-sm-4">
-                          Source Time Zone:
-                        </label>
-                        <div class="col-md-8 col-lg-8 col-sm-8">
-                          {{this.timezone}}
-                        </div>
-                      </div>
-                      <div class="row" *ngIf="this.where">
-                        <label class="col-md-4 col-lg-4 col-sm-4">
-                          Source Where:
-                        </label>
-                        <div class="col-md-8 col-lg-8 col-sm-8">
-                          {{this.where}}
-                        </div>
-                      </div>
-                      <div class="row" *ngIf="this.needpath && this.path">
-                        <label class="col-md-4 col-lg-4 col-sm-4">
-                          Source Path:
-                        </label>
-                        <div class="col-md-8 col-lg-8 col-sm-8">
-                          {{this.path}}
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-md-4 col-lg-4 col-sm-4">
-                          Owner:
-                        </label>
-                        <div class="col-md-8 col-lg-8 col-sm-8">
-                          {{owner}}
-                        </div>
-                      </div>
-                    </div>
-                  </div>
-                </div>
-                <h5 class="row">Rules</h5>
-                <div class="row" *ngFor="let index of noderule;">
-                  &nbsp;&nbsp;&nbsp;&nbsp;{{index.name}}&nbsp;:&nbsp;{{index.infos}}
-                </div>
-                <br/>
-              </div>
-            </div>
-            <div class="modal-footer">
-              <button type="button" class="btn btn-default" (click)="hide()">Cancel</button>
-              <button type="button" id="save" class="btn btn-primary" (click)="save()">Save</button>
-            </div>
-          </div>
-        </div>
+        <app-pr-confirm-modal [step1]='step1' [step2]='step2' [step3]='step3' [step4]='step4' (hide)='hide($event)' (saveMeasure)='save($event)'></app-pr-confirm-modal>
       </div>
     </form>
   </div>

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/pr.component.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/pr.component.ts b/ui/angular/src/app/measure/create-measure/pr/pr.component.ts
index b36af39..4b4b747 100644
--- a/ui/angular/src/app/measure/create-measure/pr/pr.component.ts
+++ b/ui/angular/src/app/measure/create-measure/pr/pr.component.ts
@@ -17,64 +17,54 @@ specific language governing permissions and limitations
 under the License.
 */
 import { Component, OnInit } from "@angular/core";
-import { FormControl } from "@angular/forms";
-import { FormsModule } from "@angular/forms";
 import { ServiceService } from "../../../service/service.service";
-import { TREE_ACTIONS, KEYS, IActionMapping, ITreeOptions } from "angular-tree-component";
-import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
 import { ToasterModule, ToasterService, ToasterContainerComponent } from "angular2-toaster";
-import * as $ from "jquery";
 import { HttpClient } from "@angular/common/http";
 import { Router } from "@angular/router";
-import { DataTableModule } from "angular2-datatable";
 import { AfterViewChecked, ElementRef } from "@angular/core";
-import { AngularMultiSelectModule } from "angular2-multiselect-dropdown/angular2-multiselect-dropdown";
-import { ConfigurationComponent } from "../configuration/configuration.component";
-
-class node {
-  name: string;
-  id: number;
-  children: object[];
-  isExpanded: boolean;
-  cols: Col[];
-  parent: string;
-  location: string;
+import { Col } from './step1/step1.component'
+import * as $ from "jquery";
+
+export class ProfilingStep1 {
+  data: any;
+  schemaCollection: Col[] = [];
+  nodeList: object[] = [];
+  selection: Col[];
+  dropdownList: object = {};
+  currentDB: string;
+  currentDBStr: string;
+  currentTable: string;
+  srcname: string;
+  srclocation: string;
+  selectedItems: object = {};
 }
 
-class Rule {
-  type: string;
+export class ProfilingStep2 {
+  selectedItems: object = {};
 }
 
-class Col {
-  name: string;
-  type: string;
-  comment: string;
-  selected: boolean;
-  isNum: boolean;
-  isExpanded: boolean;
-  // rules:string[];
-  groupby: string;
-  RE: string;
-  rules: any;
-  newRules: Rule[];
-  ruleLength = 0;
-  constructor(name: string, type: string, comment: string, selected: boolean) {
-    this.name = name;
-    this.type = type;
-    this.comment = comment;
-    this.selected = false;
-    this.isExpanded = false;
-    this.groupby = "";
-    this.rules = [];
-    this.RE = "";
-    this.newRules = [];
-
-    var patt = new RegExp("int|double|float/i");
-    if (patt.test(this.type)) {
-      this.isNum = true;
-    }
-    // this.rules = [];
-  }
+export class ProfilingStep3 {
+  config: object = {
+    where: "",
+    timezone: "UTC(WET,GMT)",
+    num: 1,
+    timetype: "day",
+    needpath: false,
+    path: ""
+  };
+  timezone: string = "UTC(WET,GMT)";
+  where: string = "";
+  size: string = "1day";
+  needpath: boolean = false;
+  path: string;
+}
+
+export class ProfilingStep4 {
+  prName: string = "";
+  desc: string;
+  type: string = "profiling";
+  owner: string = "test";
+  noderule: object[] = [];
 }
 
 @Component({
@@ -84,338 +74,306 @@ class Col {
   styleUrls: ["./pr.component.css"]
 })
 export class PrComponent implements AfterViewChecked, OnInit {
-  noderule = [];
+  currentStep = 1;
+
+  step1: ProfilingStep1;
+  step2: ProfilingStep2;
+  step3: ProfilingStep3;
+  step4: ProfilingStep4;
+
   transrule = [];
   transenumrule = [];
   transnullrule = [];
-  showrule = false;
-  dropdownList = {};
-  selectedItems = {};
-  allRules = {};
-  dropdownSettings = {};
-  currentStep = 1;
-  firstCond = false;
-  mouseover = false;
-  selection: Col[];
-  selectedAll = false;
-  currentDB = "";
-  currentTable = "";
-  schemaCollection: Col[];
-  totallen = 0;
-  type = "profiling";
-  data: any;
-  desc: string;
-  owner = "test";
-  currentDBstr: string;
-  timezone = "";
-  ruledesc = "";
-  newMeasure = {
-    name: "",
-    "measure.type": "griffin",
-    "dq.type": "PROFILING",
-    "process.type": "BATCH",
-    owner: "",
-    description: "",
-    "rule.description": {
-      details:[]
-      },
-    // "group":[],
-    "data.sources": [
-      {
-        name: "source",
-        connectors: [
-          {
-            name: "",
-            type: "HIVE",
-            version: "1.2",
-            "data.unit": "",
-            "data.time.zone": "",
-            config: {
-              database: "",
-              "table.name": "",
-              where: ""
-            },
-            predicates: [
-              {
-                type: "file.exist",
-                config: {
-                  "root.path": '',
-                  path: ""
-                }
-              }
-            ]
-          }
-        ]
-      }
-    ],
-    "evaluate.rule": {
-      rules: [
-        // {
-        //   "dsl.type": "griffin-dsl",
-        //   "dq.type": "profiling",
-        //   rule: "",
-        //   name: "",
-        // }
-      ]
-    }
-  };
-  name: "";
+  transregexrule = [];
+  newMeasure = {};
   createResult: any;
-  newCond: any;
-  srclocation: string;
-  srcname: string;
-  config = {
-    where: "",
-    timezone: "",
-    num: 1,
-    timetype: "day",
-    needpath: false,
-    path: ""
-  };
-  where: string;
-  size: string;
-  path: string;
-  location: string;
-  needpath: boolean;
 
-  private toasterService: ToasterService;
   public visible = false;
   public visibleAnimate = false;
+  private toasterService: ToasterService;
 
-  public hide(): void {
-    this.visibleAnimate = false;
-    setTimeout(() => (this.visible = false), 300);
-    this.transrule = [];
-    this.transenumrule = [];
-    this.transnullrule = [];
-    this.noderule = [];
-    $("#save").removeAttr("disabled");
+  next() {
+    if (this.formValidation(this.currentStep)) {
+      this.currentStep++;
+    } else {
+      this.toasterService.pop(
+        "error",
+        "Error!",
+        "Please select at least one attribute!"
+      );
+      return false;
+    }
   }
 
-  public onContainerClicked(event: MouseEvent): void {
-    if ((<HTMLElement>event.target).classList.contains("modal")) {
-      this.hide();
-    }
+  prev() {
+    this.currentStep--;
   }
 
-  onResize(event) {
-    this.resizeWindow();
+  updateStep1(body:ProfilingStep1) {
+    this.step1 = body;
+    this.next();
   }
 
-  resizeWindow() {
-    var stepSelection = ".formStep";
-    $(stepSelection).css({
-      // height: window.innerHeight - $(stepSelection).offset().top - $('#footerwrap').outerHeight()
-      height: window.innerHeight - $(stepSelection).offset().top
-    });
-    $("fieldset").height(
-      $(stepSelection).height() -
-        $(stepSelection + ">.stepDesc").height() -
-        $(".btn-container").height() -
-        130
-    );
-    $(".y-scrollable").css({
-      // 'max-height': $('fieldset').height()- $('.add-dataset').outerHeight()
-      height: $("fieldset").height()
-    });
+  updateStep2(body:ProfilingStep2) {
+    this.step2 = body;
+    this.next();
   }
 
-  setDropdownList() {
-    if (this.selection) {
-      for (let item of this.selection) {
-        if (item.isNum == true) {
-          this.dropdownList[item.name] = [
-            { id: 1, itemName: "Null Count", category: "Simple Statistics" },
-            { id: 2, itemName: "Distinct Count", category: "Simple Statistics" },
-            { id: 3, itemName: "Total Count", category: "Summary Statistics" },
-            { id: 4, itemName: "Maximum", category: "Summary Statistics" },
-            { id: 5, itemName: "Minimum", category: "Summary Statistics" },
-            { id: 6, itemName: "Average", category: "Summary Statistics" },
-            // {"id":7,"itemName":"Median","category": "Summary Statistics"},
-            // {"id":8,"itemName":"Rule Detection Count","category": "Advanced Statistics"},
-            { id: 9, itemName: "Enum Detection Top5 Count", category: "Advanced Statistics" }
-          ];
-        } else {
-          this.dropdownList[item.name] = [
-            { id: 1, itemName: "Null Count", category: "Simple Statistics" },
-            { id: 2, itemName: "Distinct Count", category: "Simple Statistics" },
-            { id: 3, itemName: "Total Count", category: "Summary Statistics" },
-            // {"id":8,"itemName":"Rule Detection Count","category": "Advanced Statistics"},
-            { id: 9, itemName: "Enum Detection Top5 Count", category: "Advanced Statistics" }
-            // {"id":10,"itemName":"Regular Expression Detection Count","category": "Advanced Statistics"}
-          ];
+  updateStep3(body:ProfilingStep3) {
+    this.step3 = body;
+    this.next();
+  }
+
+  formValidation = (step) => {
+    if (step == undefined) step = this.currentStep;
+    if (step == 1) {
+      return this.step1.selection && this.step1.selection.length > 0;
+    } else if (step == 2) {
+      let len = 0;
+      let selectedlen = 0;
+      for (let key in this.step2.selectedItems) {
+        selectedlen++;
+        len = this.step2.selectedItems[key].length;
+        if (len == 0) {
+          return false;
         }
       }
+      return this.step1.selection.length == selectedlen;
+    } else if (step == 3) {
+      return true;
+    } else if (step == 4) {
+      return /^[a-zA-Z0-9_-]+$/.test(this.step4.prName);
     }
+    return false;
+  };
+
+  constructor(
+    private elementRef: ElementRef,
+    toasterService: ToasterService,
+    private http: HttpClient,
+    private router: Router,
+    public serviceService: ServiceService
+  ) {
+    this.toasterService = toasterService;
   }
 
-  toggleSelection(row) {
-    row.selected = !row.selected;
-    var idx = this.selection.indexOf(row);
-    // is currently selected
-    if (idx > -1) {
-      this.selection.splice(idx, 1);
-      this.selectedAll = false;
-      for (let key in this.selectedItems) {
-        if (key === row.name) {
-          delete this.selectedItems[key];
+  getGrouprule() {
+    var selected = { name: "" };
+    var value = "";
+    var nullvalue = "";
+    var nullname = "";
+    var enmvalue = ""
+    var regexvalue = "";
+    var regexname = "";
+    var grpname = "";
+
+    for (let key in this.step2.selectedItems) {
+      selected.name = key;
+      let info = "";
+      let otherinfo = "";
+      for (let i = 0; i < this.step2.selectedItems[key].length; i++) {
+        var originrule = this.step2.selectedItems[key][i].itemName;
+        info = info + originrule + ",";
+
+        if (originrule == "Enum Detection Top5 Count") {
+
+          enmvalue = this.transferRule(originrule, selected);
+          grpname = `${selected.name}_grp`;
+          this.transenumrule.push(enmvalue);
+          this.pushEnmRule(enmvalue, grpname);
+
+        } else if (originrule == "Null Count") {
+
+          nullvalue = this.transferRule(originrule, selected);
+          nullname = `${selected.name}_nullcount`;
+          this.transnullrule.push(nullvalue);
+          this.pushNullRule(nullvalue, nullname);
+
+        } else if (originrule == "Empty Count") {
+
+          nullvalue = this.transferRule(originrule, selected);
+          nullname = `${selected.name}_emptycount`;
+          this.transnullrule.push(nullvalue);
+          this.pushNullRule(nullvalue, nullname);
+
+        } else if (originrule == "Regular Expression Detection Count") {
+
+          selected['regex'] = this.step2.selectedItems[key].regex;
+          regexvalue = this.transferRule(originrule, selected);
+          regexname = `${selected.name}_regexcount`;
+          this.transregexrule.push(regexvalue);
+          this.pushRegexRule(regexvalue, regexname);
+
+        } else {
+
+          otherinfo = otherinfo + originrule + ",";
+          value = this.transferRule(originrule, selected);
+          this.transrule.push(value);
+
         }
       }
-    } else {
-      // is newly selected
-      this.selection.push(row);
+
+      info = info.substring(0, info.lastIndexOf(","));
+      otherinfo = otherinfo.substring(0, otherinfo.lastIndexOf(","));
+      this.step4.noderule.push({
+        name: key,
+        infos: info
+      });
     }
-    if (this.selection.length == 3) {
-      this.selectedAll = true;
-    } else {
-      this.selectedAll = false;
+    if (this.transrule.length != 0) {
+      this.getRule(this.transrule);
     }
-    this.setDropdownList();
   }
 
-  toggleAll() {
-    this.selectedAll = !this.selectedAll;
-    this.selection = [];
-    for (var i = 0; i < this.schemaCollection.length; i++) {
-      this.schemaCollection[i].selected = this.selectedAll;
-      if (this.selectedAll) {
-        this.selection.push(this.schemaCollection[i]);
-      }
+  getRule(trans) {
+    var rule = "";
+    for (let i of trans) {
+      rule = rule + i + ",";
     }
-    this.setDropdownList();
+    rule = rule.substring(0, rule.lastIndexOf(","));
+    this.pushRule(rule);
+  }
+
+  pushEnmRule(rule, grpname) {
+    this.newMeasure["evaluate.rule"].rules.push({
+      "dsl.type": "griffin-dsl",
+      "dq.type": "PROFILING",
+      rule: rule,
+      name: grpname,
+      metric: {
+        "collect.type": "array"
+      }
+    });
+  }
+
+  pushNullRule(rule, nullname) {
+    this.newMeasure["evaluate.rule"].rules.push({
+      "dsl.type": "griffin-dsl",
+      "dq.type": "PROFILING",
+      rule: rule,
+      name: nullname
+    });
+  }
+
+  pushRegexRule(rule, nullname) {
+    this.newMeasure["evaluate.rule"].rules.push({
+      "dsl.type": "griffin-dsl",
+      "dq.type": "PROFILING",
+      rule: rule,
+      name: nullname
+    });
+  }
+
+  pushRule(rule) {
+    this.newMeasure["evaluate.rule"].rules.push({
+      "dsl.type": "griffin-dsl",
+      "dq.type": "PROFILING",
+      rule: rule,
+      name: "profiling"
+    });
   }
 
   transferRule(rule, col) {
     switch (rule) {
       case "Total Count":
-        return "count(source.`" + col.name + "`) AS `" + col.name + "-count`";
+        return (
+          `count(source.${col.name}) AS \`${col.name}_count\``
+        );
       case "Distinct Count":
         return (
-          "approx_count_distinct(source.`" +
-          col.name +
-          "`) AS `" +
-          col.name +
-          "-distcount`"
+          `approx_count_distinct(source.${col.name}) AS \`${col.name}_distcount\``
         );
       case "Null Count":
         return (
-          "count(source.`" +
-          col.name +
-          "`) AS `" +
-          col.name +
-          "-nullcount" +
-          "` WHERE source.`" +
-          col.name +
-          "` IS NULL"
+          `count(source.${col.name}) AS \`${col.name}_nullcount\` WHERE source.${col.name} IS NULL`
         );
-      // case 'Regular Expression Detection Count':
-      //   return 'count(source.`'+col.name+'`) where source.`'+col.name+'` LIKE ';
-      // case 'Rule Detection Count':
-      //   return 'count(source.`'+col.name+'`) where source.`'+col.name+'` LIKE ';
       case "Maximum":
-        return "max(source.`" + col.name + "`) AS `" + col.name + "-max`";
+        return (
+          `max(source.${col.name}) AS \`${col.name}_max\``
+        );
       case "Minimum":
-        return "min(source.`" + col.name + "`) AS `" + col.name + "-min`";
-      // case 'Median':
-      //   return 'median(source.`'+col.name+'`) ';
+        return (
+          `min(source.${col.name}) AS \`${col.name}_min\``
+        );
       case "Average":
-        return "avg(source.`" + col.name + "`) AS `" + col.name + "-average`";
+        return (
+          `avg(source.${col.name}) AS \`${col.name}_average\``
+        );
+      case "Empty Count":
+        return (
+          `count(source.${col.name}) AS \`${col.name}_emptycount\` WHERE source.${col.name} = ''`
+        );
+      case "Regular Expression Detection Count":
+        return (
+          `count(source.${col.name} RLIKE '${col.regex}') AS \`${col.name}_regexcount\``
+        );
       case "Enum Detection Top5 Count":
         return (
-          "source.`" +
-          col.name +
-          "`,count(*) AS `" +
-          "count` GROUP BY source.`" +
-          col.name +
-          "` ORDER BY `count` DESC LIMIT 5"
+          `source.${col.name}, ${col.name}, count(*) AS count GROUP BY source.${col.name} ORDER BY count DESC LIMIT 5`
         );
     }
   }
 
-  next(form) {
-    if (this.formValidation(this.currentStep)) {
-      this.currentStep++;
-    } else {
-      this.toasterService.pop(
-        "error",
-        "Error!",
-        "Please select at least one attribute!"
-      );
-      return false;
-    }
+  public hide(): void {
+    this.visibleAnimate = false;
+    setTimeout(() => (this.visible = false), 300);
+    this.transrule = [];
+    this.transenumrule = [];
+    this.transnullrule = [];
+    this.transregexrule = [];
+    this.step4.noderule = [];
+    $("#save").removeAttr("disabled");
   }
 
-  formValidation = function(step) {
-    if (step == undefined) {
-      step = this.currentStep;
-    }
-    if (step == 1) {
-      return this.selection && this.selection.length > 0;
-    } else if (step == 2) {
-      var len = 0;
-      var selectedlen = 0;
-      for (let key in this.selectedItems) {
-        selectedlen++;
-        len = this.selectedItems[key].length;
-        if (len == 0) {
-          return false;
-        }
-      }
-      return this.selection.length == selectedlen ? true : false;
-    } else if (step == 3) {
-      return true;
-    } else if (step == 4) {
+  public onContainerClicked(event: MouseEvent): void {
+    if ((<HTMLElement>event.target).classList.contains("modal")) {
+      this.hide();
     }
-    return false;
-  };
-
-  prev(form) {
-    this.currentStep--;
-  }
-  goTo(i) {
-    this.currentStep = i;
   }
-  submit(form) {
-    if (!form.valid) {
+
+  submit(body:ProfilingStep4) {
+    this.step4 = body;
+
+    if (!this.formValidation(this.currentStep)) {
       this.toasterService.pop(
         "error",
         "Error!",
-        "please complete the form in this step before proceeding"
+        "Please complete the form in this step before proceeding!"
       );
       return false;
     }
+
     this.newMeasure = {
-      name: this.name,
+      name: this.step4.prName,
       "measure.type": "griffin",
       "dq.type": "PROFILING",
       "rule.description": {
-        details:this.noderule
+        details: this.step4.noderule
       },
       "process.type": "BATCH",
-      owner: this.owner,
-      description: this.desc,
-      // "group":this.finalgrp,
+      owner: this.step4.owner,
+      description: this.step4.desc,
       "data.sources": [
         {
           name: "source",
           connectors: [
             {
-              name: this.srcname,
+              name: this.step1.srcname,
               type: "HIVE",
               version: "1.2",
-              "data.unit": this.size,
-              "data.time.zone": this.timezone,
+              "data.unit": this.step3.size,
+              "data.time.zone": this.step3.timezone,
               config: {
-                database: this.currentDB,
-                "table.name": this.currentTable,
-                where: this.where
+                database: this.step1.currentDB,
+                "table.name": this.step1.currentTable,
+                where: this.step3.config['where']
               },
               predicates: [
                 {
                   type: "file.exist",
                   config: {
-                    "root.path": this.srclocation,
-                    path: this.path
+                    "root.path": this.step1.srclocation,
+                    path: this.step3.path
                   }
                 }
               ]
@@ -424,72 +382,26 @@ export class PrComponent implements AfterViewChecked, OnInit {
         }
       ],
       "evaluate.rule": {
-        rules: [
-          // {
-          //   "dsl.type": "griffin-dsl",
-          //   "dq.type": "profiling",
-          //   "rule": "",
-          //   "details": {}
-          // }
-        ]
+        rules: []
       }
     };
+
     this.getGrouprule();
-    if (this.size.indexOf("0") == 0) {
+    if (this.step3.size.indexOf("0") == 0) {
       delete this.newMeasure["data.sources"][0]["connectors"][0]["data.unit"];
     }
-    if (!this.needpath || this.path == "") {
+    if (!this.step3.needpath || this.step3.path == "") {
       delete this.newMeasure["data.sources"][0]["connectors"][0]["predicates"];
     }
     this.visible = true;
     setTimeout(() => (this.visibleAnimate = true), 100);
   }
 
-  getRule(trans) {
-    var rule = "";
-    for (let i of trans) {
-      rule = rule + i + ",";
-    }
-    rule = rule.substring(0, rule.lastIndexOf(","));
-    this.pushRule(rule);
-  }
-
-  pushEnmRule(rule, grpname) {
-    var self = this;
-    self.newMeasure["evaluate.rule"].rules.push({
-      "dsl.type": "griffin-dsl",
-      "dq.type": "PROFILING",
-      rule: rule,
-      name: grpname,
-      metric: {
-        "collect.type": "array"
-      }
-    });
-  }
-
-  pushNullRule(rule, nullname) {
-    var self = this;
-    self.newMeasure["evaluate.rule"].rules.push({
-      "dsl.type": "griffin-dsl",
-      "dq.type": "PROFILING",
-      rule: rule,
-      name: nullname
-    });
-  }
-
-  pushRule(rule) {
-    var self = this;
-    self.newMeasure["evaluate.rule"].rules.push({
-      "dsl.type": "griffin-dsl",
-      "dq.type": "PROFILING",
-      rule: rule,
-      name: "profiling"
-    });
-  }
-
   save() {
-    var addModels = this.serviceService.config.uri.addModels;
+    let addModels = this.serviceService.config.uri.addModels;
+
     $("#save").attr("disabled", "true");
+
     this.http.post(addModels, this.newMeasure).subscribe(
       data => {
         this.createResult = data;
@@ -508,166 +420,12 @@ export class PrComponent implements AfterViewChecked, OnInit {
     );
   }
 
-  options: ITreeOptions = {
-    displayField: "name",
-    isExpandedField: "expanded",
-    idField: "id",
-    actionMapping: {
-      mouse: {
-        click: (tree, node, $event) => {
-          if (node.hasChildren) {
-            this.currentDB = node.data.name;
-            this.currentDBstr = this.currentDB + ".";
-            this.currentTable = "";
-            this.schemaCollection = [];
-            this.selectedAll = false;
-            TREE_ACTIONS.TOGGLE_EXPANDED(tree, node, $event);
-          } else if (node.data.cols) {
-            this.currentTable = node.data.name;
-            this.currentDB = node.data.parent;
-            this.schemaCollection = node.data.cols;
-            this.srcname = "source" + new Date().getTime();
-            this.srclocation = node.data.location;
-            this.selectedAll = false;
-            this.selection = [];
-            for (let row of this.schemaCollection) {
-              row.selected = false;
-            }
-          }
-        }
-      }
-    },
-    animateExpand: true,
-    animateSpeed: 30,
-    animateAcceleration: 1.2
-  };
-
-  nodeList: object[];
-  nodeListTarget: object[];
-
-  constructor(
-    private elementRef: ElementRef,
-    toasterService: ToasterService,
-    private http: HttpClient,
-    private router: Router,
-    public serviceService: ServiceService
-  ) {
-    this.toasterService = toasterService;
-    this.selection = [];
-  }
-
-  getGrouprule() {
-    var selected = { name: "" };
-    var value = "";
-    var nullvalue = "";
-    var nullname = "";
-    var enmvalue = "";
-    var grpname = "";
-    for (let key in this.selectedItems) {
-      selected.name = key;
-      var info = "";
-      var otherinfo = "";
-      for (let i = 0; i < this.selectedItems[key].length; i++) {
-        var originrule = this.selectedItems[key][i].itemName;
-        info = info + originrule + ",";
-        if (originrule == "Enum Detection Top5 Count") {
-          enmvalue = this.transferRule(originrule, selected);
-          grpname = selected.name + "-grp";
-          this.transenumrule.push(enmvalue);
-          this.pushEnmRule(enmvalue, grpname);
-        } else if (originrule == "Null Count") {
-          nullvalue = this.transferRule(originrule, selected);
-          nullname = selected.name + "-nullct";
-          this.transnullrule.push(nullvalue);
-          this.pushNullRule(nullvalue, nullname);
-        } else {
-          otherinfo = otherinfo + originrule + ",";
-          value = this.transferRule(originrule, selected);
-          this.transrule.push(value);
-        }
-      }
-      info = info.substring(0, info.lastIndexOf(","));
-      otherinfo = otherinfo.substring(0, otherinfo.lastIndexOf(","));
-      this.noderule.push({
-        name: key,
-        infos: info
-      });
-    }
-    if (this.transrule.length != 0) {
-      this.getRule(this.transrule);
-    }
-    this.ruledesc = JSON.stringify(this.noderule);
-  }
-
-  confirmAdd() {
-    document.getElementById("rule").style.display = "none";
-  }
-
-  showRule() {
-    document.getElementById("showrule").style.display = "";
-    document.getElementById("notshowrule").style.display = "none";
-  }
-
-  back() {
-    document.getElementById("showrule").style.display = "none";
-    document.getElementById("notshowrule").style.display = "";
-  }
-
-  getData(evt) {
-    this.config = evt;
-    this.timezone = evt.timezone;
-    this.where = evt.where;
-    this.size = evt.num + evt.timetype;
-    this.needpath = evt.needpath;
-    this.path = evt.path;
-  }
-
   ngOnInit() {
-    var allDataassets = this.serviceService.config.uri.dataassetlist;
-    this.http.get(allDataassets).subscribe(data => {
-      this.nodeList = new Array();
-      let i = 1;
-      this.data = data;
-      for (let db in this.data) {
-        let new_node = new node();
-        new_node.name = db;
-        new_node.id = i;
-        new_node.isExpanded = true;
-        i++;
-        new_node.children = new Array();
-        for (let i = 0; i < this.data[db].length; i++) {
-          let new_child = new node();
-          new_child.name = this.data[db][i]["tableName"];
-          new_node.children.push(new_child);
-          new_child.isExpanded = false;
-          new_child.location = this.data[db][i]["sd"]["location"];
-          new_child.parent = db;
-          new_child.cols = Array<Col>();
-          for (let j = 0; j < this.data[db][i]["sd"]["cols"].length; j++) {
-            let new_col = new Col(
-              this.data[db][i]["sd"]["cols"][j].name,
-              this.data[db][i]["sd"]["cols"][j].type,
-              this.data[db][i]["sd"]["cols"][j].comment,
-              false
-            );
-            new_child.cols.push(new_col);
-          }
-        }
-        this.nodeList.push(new_node);
-      }
-      this.nodeListTarget = JSON.parse(JSON.stringify(this.nodeList));
-    });
-    this.dropdownSettings = {
-      singleSelection: false,
-      text: "Select Rule",
-      enableCheckAll: false,
-      enableSearchFilter: true,
-      classes: "myclass",
-      groupBy: "category"
-    };
-    this.size = "1day";
-  }
-  ngAfterViewChecked() {
-    this.resizeWindow();
+    this.step1 = new ProfilingStep1();
+    this.step2 = new ProfilingStep2();
+    this.step3 = new ProfilingStep3();
+    this.step4 = new ProfilingStep4();
   }
+
+  ngAfterViewChecked() {}
 }

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.css b/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.css
new file mode 100644
index 0000000..fd725f8
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.css
@@ -0,0 +1,141 @@
+/*
+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 url('../../../../../../node_modules/angular2-toaster/toaster.css');
+@import url('../../../measure.component.css');
+
+fieldset {
+  height: 60vh;
+}
+
+label.stepDesc {
+  padding-left: 30px;
+  padding-right: 30px;
+}
+
+div.btn-container {
+  width: 100%;
+  padding-left: 30px;
+  padding-right: 30px;
+  clear: both;
+}
+
+div.tree div.tree-children::before,
+div.tree::before {
+  content: "";
+  position: absolute;
+  border-left: 1px dotted #23527c;
+  height: 100%;
+  top: -14px;
+  left: 12px
+}
+
+tree-root {
+  color: #999;
+}
+
+div.tree {
+  padding-left: 0;
+  margin-left: -5px
+}
+
+div.tree div.tree-children {
+  position: relative;
+  padding-left: 0;
+  margin-left: 16px
+}
+
+div.tree div.tree-children::before {
+  left: 5px
+}
+
+div.tree treenode>div>.node-wrapper {
+  margin-left: 24px
+}
+
+div.tree treenode>div>.node-wrapper>.node-content-wrapper {
+  margin-left: 4px
+}
+
+div.tree treenode>div.tree-node-leaf>.node-wrapper {
+  margin-left: 0
+}
+
+div.tree treenode>div::before {
+  content: "";
+  position: absolute;
+  border-bottom: 1px dotted #23527c;
+  width: 7px;
+  margin-top: 12px;
+  left: 7px
+}
+
+div.tree treenode>div .toggle-children-wrapper {
+  width: 13px;
+  height: 13px;
+  border: 1px solid #23527c;
+  position: absolute;
+  left: 15px;
+  margin-top: 5px;
+  margin-left: 0;
+  display: inline-block;
+  background-color: #fff;
+  z-index: 1
+}
+
+div.tree treenode>div .toggle-children-wrapper::before {
+  content: "";
+  display: inline-block;
+  width: 7px;
+  border-top: 1px solid #23527c;
+  position: absolute;
+  top: 5px;
+  left: 2px
+}
+
+div.tree treenode>div .toggle-children-wrapper.toggle-children-wrapper-collapsed::after {
+  content: "";
+  display: inline-block;
+  height: 7px;
+  border-left: 1px solid #23527c;
+  position: absolute;
+  top: 2px;
+  left: 5px
+}
+
+div.tree treenode>div .toggle-children-wrapper .toggle-children {
+  display: none
+}
+
+div.tree treenode>div .node-content-wrapper {
+  margin-left: 4px
+}
+
+div.tree>treenode>div::before {
+  left: 14px
+}
+
+div.tree>treenode>div>.node-wrapper>treenodeexpander>.toggle-children-wrapper {
+  left: 22px
+}
+
+table > tbody > tr > td, .table > thead > tr > th {
+  word-wrap: break-word;
+  min-width: 80px;
+}

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.html
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.html b/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.html
new file mode 100644
index 0000000..4c9eb99
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.html
@@ -0,0 +1,78 @@
+<!--
+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 class="container-fluid">
+  <form name="Form" id="form" #prForm="ngForm" novalidate>
+      <label class="stepDesc">This step lets you select the single source of truth for data quality comparision with a target source.</label>
+      <div class="container-fluid">
+        <div class="col-md-4 col-lg-4 col-sm-4">
+          <fieldset>
+            <legend>Please select schema</legend>
+            <tree-root [nodes]="step1.nodeList" [options]="options"></tree-root>
+          </fieldset>
+        </div>
+        <div class="col-md-8 col-lg-8 col-sm-8">
+          <fieldset>
+            <legend>
+              Select attributes
+            </legend>
+            <div class="y-scrollable">
+              <div style="margin-top:10px;">
+                <label>View schema:</label>
+                <i style="color:#fff;font-weight: bold;">{{step1.currentDBstr}}{{step1.currentTable}}
+                </i>
+              </div>
+              <div style="margin-top:5px;">
+                <table class="table table-striped no-border">
+                  <thead>
+                  <tr style="background-color:#7D95CC">
+                    <th>
+                      <input type="checkbox" (click)="toggleAll()" [checked]="selectedAll" />
+                    </th>
+                    <th>Column Name</th>
+                    <th>Type</th>
+                    <th>Comment</th>
+                  </tr>
+                  </thead>
+                  <tbody>
+                  <tr *ngIf="!step1.schemaCollection || step1.schemaCollection.length == 0">
+                    <td colspan="5" style="text-align:center;"><span class="highlight">Please select a schema from the left tree first</span></td>
+                  </tr>
+                  <tr *ngFor="let row of step1.schemaCollection">
+                    <td>
+                      <input type="checkbox" (click)='toggleSelection(row)' [checked]="row.selected" value={{row.name}} />
+                    </td>
+                    <td>{{row.name}}</td>
+                    <td>{{row.type}}</td>
+                    <td>{{row.comment}}</td>
+                  </tr>
+                  </tbody>
+                </table>
+              </div>
+            </div>
+          </fieldset>
+        </div>
+      </div>
+  </form>
+
+  <div class="form-group btn-container">
+    <button class="btn btn-primary btn-o next-step btn-wide pull-right" (click)="nextChildStep()">
+      Next <i class="fa fa-arrow-circle-right"></i>
+    </button>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/d58bd194/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.spec.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.spec.ts b/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.spec.ts
new file mode 100644
index 0000000..13d47d4
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/pr/step1/step1.component.spec.ts
@@ -0,0 +1,43 @@
+/*
+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 { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PrStep1Component } from './step1.component';
+
+describe('PrStep1Component', () => {
+  let component: PrStep1Component;
+  let fixture: ComponentFixture<PrStep1Component>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ PrStep1Component ]
+    })
+      .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PrStep1Component);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should be created', () => {
+    expect(component).toBeTruthy();
+  });
+});