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/10/29 01:56:02 UTC
incubator-griffin git commit: [GRIFFIN-203] Plaintext mode" for
measure creation
Repository: incubator-griffin
Updated Branches:
refs/heads/master e4d587d95 -> bcfd0e269
[GRIFFIN-203] Plaintext mode" for measure creation
Created json/yaml measure creation flow:
![2018-10-24 21 41 44](https://user-images.githubusercontent.com/15277543/47476643-4aa37680-d7d6-11e8-9488-fe2e247617a1.gif)
Added ability to view measure as yaml:
![2018-10-24 21 42 23](https://user-images.githubusercontent.com/15277543/47476652-4d9e6700-d7d6-11e8-86f3-f35fdc44dda1.gif)
I did not add any input validation, for now only server side validation is working. I'm not quite sure if copying validation from service side is a good choice.
Author: Arthur Gavlyukovskiy <ag...@gmail.com>
Closes #446 from gavlyukovskiy/raw-measures.
Project: http://git-wip-us.apache.org/repos/asf/incubator-griffin/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-griffin/commit/bcfd0e26
Tree: http://git-wip-us.apache.org/repos/asf/incubator-griffin/tree/bcfd0e26
Diff: http://git-wip-us.apache.org/repos/asf/incubator-griffin/diff/bcfd0e26
Branch: refs/heads/master
Commit: bcfd0e2693d743cde61f50621e11cc351bbbb197
Parents: e4d587d
Author: Arthur Gavlyukovskiy <ag...@gmail.com>
Authored: Sun Oct 28 18:55:44 2018 -0700
Committer: Yuepeng <yu...@griffin-2454820.phx02.dev.ebayc3.com>
Committed: Sun Oct 28 18:55:44 2018 -0700
----------------------------------------------------------------------
ui/angular/package.json | 2 +
ui/angular/src/app/app.module.ts | 8 +-
.../create-measure.component.html | 34 ++-
.../create-measure/raw/raw.component.css | 238 +++++++++++++++++++
.../create-measure/raw/raw.component.html | 102 ++++++++
.../create-measure/raw/raw.component.spec.ts | 43 ++++
.../measure/create-measure/raw/raw.component.ts | 146 ++++++++++++
.../measure-detail/measure-detail.component.css | 4 +
.../measure-detail.component.html | 22 +-
.../measure-detail/measure-detail.component.ts | 12 +-
.../src/app/service/measure-format.service.ts | 48 ++++
11 files changed, 649 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/bcfd0e26/ui/angular/package.json
----------------------------------------------------------------------
diff --git a/ui/angular/package.json b/ui/angular/package.json
index 6926014..91b5d16 100644
--- a/ui/angular/package.json
+++ b/ui/angular/package.json
@@ -30,6 +30,7 @@
"core-js": "^2.4.1",
"echarts": "^3.7.0",
"font-awesome": "^4.7.0",
+ "js-yaml": "^3.11.2",
"ng2-bootstrap": "1.6.3",
"ng2-nouislider": "^1.7.6",
"ngx-echarts": "2.3.1",
@@ -45,6 +46,7 @@
"@types/jasminewd2": "~2.0.2",
"@types/jquery": "^3.2.12",
"@types/node": "~6.0.60",
+ "@types/js-yaml": "~3.11.2",
"angular-tree-component": "^4.1.0",
"codelyzer": "~3.1.1",
"font-awesome": "^4.7.0",
http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/bcfd0e26/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 196fdbc..1598841 100644
--- a/ui/angular/src/app/app.module.ts
+++ b/ui/angular/src/app/app.module.ts
@@ -59,6 +59,7 @@ import {LoaderService} from './loader/loader.service';
import {LoaderComponent} from './loader/loader.component';
import {JobDetailComponent} from './job/job-detail/job-detail.component';
import {StreamingComponent} from './job/create-job/streaming/streaming.component';
+import {RawComponent} from "./measure/create-measure/raw/raw.component";
const appRoutes: Routes = [
@@ -113,6 +114,10 @@ const appRoutes: Routes = [
component: PubComponent
},
{
+ path: 'createmeasureraw',
+ component: RawComponent
+ },
+ {
path: 'detailed/:name',
component: DetailMetricComponent
},
@@ -168,7 +173,8 @@ const appRoutes: Routes = [
ConfigurationComponent,
LoaderComponent,
JobDetailComponent,
- StreamingComponent
+ StreamingComponent,
+ RawComponent
],
imports: [
BrowserModule,
http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/bcfd0e26/ui/angular/src/app/measure/create-measure/create-measure.component.html
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/create-measure.component.html b/ui/angular/src/app/measure/create-measure/create-measure.component.html
index 22ff6b6..5aaabc3 100644
--- a/ui/angular/src/app/measure/create-measure/create-measure.component.html
+++ b/ui/angular/src/app/measure/create-measure/create-measure.component.html
@@ -180,7 +180,39 @@ under the License.
</div>
</div>
<div class="panel-footer stepDesc">
- <label>Example: any data</label> ...
+ <label>Example:</label> any data ...
+ </div>
+ </section>
+ </div>
+ <div class="col-lg-6 col-md-6 col-sm-6 ruletypes">
+ <section id="panel-4" class="panel panel-yellow" (click)="click('raw')">
+ <div class="panel-heading">
+ <span style="font-size:20px">JSON/YAML measure</span>
+ <span class="pull-right" style="font-size:20px">
+ <span class="fa fa-arrow-circle-right"></span>
+ </span>
+ </div>
+ <div class="swMain panel-body">
+ <label class="label-definition">Definition: Submit measure with JSON/YAML measure definition utilizing
+ advanced configuration capabilities that are not available through other flows</label>
+ <ul style="border-radius:0; background: none">
+ <li>
+ <div class="selected1child" style="cursor:default">
+ <div class="stepNumber">
+ 1
+ </div>
+ <span class="stepDesc text-small"> Configuration </span>
+ </div>
+ </li>
+ </ul>
+ <div>
+ <ol>
+ <li>Create measure directly from JSON/YAML</li>
+ </ol>
+ </div>
+ </div>
+ <div class="panel-footer stepDesc">
+ <label>Example:</label> measure with custom configuration like custom spark sql
</div>
</section>
</div>
http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/bcfd0e26/ui/angular/src/app/measure/create-measure/raw/raw.component.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/raw/raw.component.css b/ui/angular/src/app/measure/create-measure/raw/raw.component.css
new file mode 100644
index 0000000..cf68d86
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/raw/raw.component.css
@@ -0,0 +1,238 @@
+/*
+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 {
+ font-weight: normal;
+}
+
+.container {
+ max-height: 40vh;
+ overflow-y: scroll;
+}
+
+.swMain > ul {
+ display: table;
+ list-style: none;
+ margin: 0 0 20px;
+ padding: 10px 0;
+ position: relative;
+ width: 100%;
+ background: #f7f7f8;
+ border-radius: 5px
+}
+
+.formStep {
+ background-color: #000000;
+ border-radius: 5px;
+ padding: 10px;
+ /*height:800px;*/
+}
+
+.swMain > ul li {
+ display: table-cell;
+ text-align: center;
+ width: 1%
+}
+
+.swMain > ul li > a:before {
+ border-top: 4px solid #c8c7cc;
+ /* content: ""; */
+ display: block;
+ font-size: 0;
+ height: 1px;
+ overflow: hidden;
+ position: relative;
+ top: 21px;
+ width: 100%;
+ z-index: 1
+}
+
+.swMain > ul .stepNumber {
+ background-color: #fff;
+ border: 5px solid #c8c7cc;
+ border-radius: 100%;
+ color: #546474;
+ display: inline-block;
+ font-size: 15px;
+ height: 40px;
+ line-height: 30px;
+ position: relative;
+ text-align: center;
+ width: 40px;
+ z-index: 2
+}
+
+.swMain > ul li > a.selected .stepNumber {
+ border-color: #007AFF
+}
+
+.swMain ul li > a.done .stepNumber {
+ border-color: #007AFF;
+ background-color: #007AFF;
+ color: #fff;
+ text-indent: -9999px
+}
+
+.swMain ul li > a.done .stepNumber:before {
+ content: "\f00c";
+ display: inline;
+ float: right;
+ font-family: FontAwesome;
+ font-weight: 300;
+ height: auto;
+ text-shadow: none;
+ margin-right: 7px;
+ text-indent: 0
+}
+
+.swMain ul li > a.done.wait .stepNumber {
+ background-color: #F6F6F6 !important;
+ color: #CCC !important;
+ text-indent: 0 !important
+}
+
+.swMain ul li > a.done.wait .stepNumber:before {
+ content: "" !important
+}
+
+.swMain > ul li .stepDesc {
+ color: #8e8e93;
+ display: block;
+ font-size: 14px;
+ margin-top: 4px;
+ max-width: 100%;
+ table-layout: fixed;
+ text-align: center;
+ word-wrap: break-word;
+ z-index: 104
+}
+
+.swMain li > a.done .stepDesc,
+.swMain > ul li > a.selected .stepDesc {
+ /*color: #2B3D53*/
+ color: #007AFF
+}
+
+.swMain > ul li > a.disabled {
+ cursor: default
+}
+
+.swMain .progress {
+ margin-bottom: 30px
+}
+
+.swMain .stepContainer {
+ height: auto !important
+}
+
+.swMain .y-scrollable {
+ overflow-y: auto;
+ overflow-x: hidden;
+ max-height: 600px;
+}
+
+fieldset {
+ border: 1px solid #e6e8e8;
+ border-radius: 5px;
+ margin: 20px 0;
+ padding: 25px;
+ position: relative;
+ min-width: 0;
+ display: block;
+}
+
+fieldset legend {
+ background-color: #000000;
+ left: 10px;
+ padding: 0 10px;
+ position: absolute;
+ top: -12px;
+ color: #fff;
+ font-weight: 400;
+ width: auto !important;
+ border: none !important;
+}
+
+.btn-o {
+ background: 0 0 !important;
+}
+
+.btn-wide {
+ min-width: 120px;
+}
+
+.btn-container {
+ height: 50px;
+ /*position: absolute;
+ bottom: 10;*/
+}
+
+.btn-flat {
+ outline: none !important;
+}
+
+::-webkit-scrollbar {
+ width: 6px;
+}
+
+::-webkit-scrollbar-track {
+ background-color: #eaeaea;
+ /*background-color: #0a0a0a;*/
+ border-left: 1px solid #ccc;
+}
+
+::-webkit-scrollbar-thumb {
+ background-color: #ccc;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background-color: #aaa;
+}
+
+.disabled {
+ pointer-events: none;
+ cursor: default;
+ opacity: 0.6;
+}
+
+a {
+ color: white;
+}
+
+.code-viewport {
+ background-color: #333333;
+ border: 1px solid #1d1d1d;
+ border-radius: 4px;
+ font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+ font-size: 13px;
+ line-height: 1.5;
+ color: #e4e4e4;
+ word-break: break-all;
+ word-wrap: break-word;
+ white-space: pre;
+ overflow: auto;
+ resize: none;
+ outline: none;
+}
+
+.fixed-textarea {
+ height: 450px;
+}
http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/bcfd0e26/ui/angular/src/app/measure/create-measure/raw/raw.component.html
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/raw/raw.component.html b/ui/angular/src/app/measure/create-measure/raw/raw.component.html
new file mode 100644
index 0000000..ff2f4da
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/raw/raw.component.html
@@ -0,0 +1,102 @@
+<!--
+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" (window:resize)="onResize($event)">
+ <div class="row">
+ <h5 class="over-title margin-bottom-15">Create Measure</h5>
+ </div>
+ <div class="row">
+ <form name="Form" id="form" #prForm="ngForm" novalidate>
+ <div id="wizard" class="swMain">
+ <ul>
+ <li>
+ <a class="selected">
+ <div class="stepNumber">
+ 1
+ </div>
+ <span class="stepDesc text-small"> Configuration </span>
+ </a>
+ </li>
+ </ul>
+ </div>
+ <div id="step-1" 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': !valid, 'has-success': valid}">
+ <div class="row">
+ <label class="col-md-2 col-lg-2 col-sm-2 control-label">
+ Raw measure<span class="symbol required"></span>:
+ </label>
+ <div class="col-md-10 col-lg-10 col-sm-10">
+ <div class="btn-group btn-group-sm navbar-right" role="group" aria-label="Format">
+ <button type="button" class="btn btn-flat btn-primary" [ngClass]="{'active': format == Format.json}" (click)="changeFormat(Format.json)">JSON</button>
+ <button type="button" class="btn btn-flat btn-primary" [ngClass]="{'active': format == Format.yaml}" (click)="changeFormat(Format.yaml)">YAML</button>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <textarea class="code-viewport fixed-textarea" required [(ngModel)]="data" #content="ngModel" name="content" (ngModelChange)="onInputChange()"></textarea>
+ <span class="error text-small block " *ngIf="!valid">Measure is not valid</span>
+ </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>
+ </div>
+ </fieldset>
+ </div>
+ <div class="form-group btn-container">
+ <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>
+ </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()">×</button>
+ <h4 class="modal-title">Save the measure?</h4>
+ </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>
+ </div>
+ </form>
+ </div>
+</div>
http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/bcfd0e26/ui/angular/src/app/measure/create-measure/raw/raw.component.spec.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/raw/raw.component.spec.ts b/ui/angular/src/app/measure/create-measure/raw/raw.component.spec.ts
new file mode 100644
index 0000000..15a7a97
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/raw/raw.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 {RawComponent} from './raw.component';
+
+describe('RawComponent', () => {
+ let component: RawComponent;
+ let fixture: ComponentFixture<RawComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [RawComponent]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RawComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should be created', () => {
+ expect(component).toBeTruthy();
+ });
+});
http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/bcfd0e26/ui/angular/src/app/measure/create-measure/raw/raw.component.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/create-measure/raw/raw.component.ts b/ui/angular/src/app/measure/create-measure/raw/raw.component.ts
new file mode 100644
index 0000000..743cd59
--- /dev/null
+++ b/ui/angular/src/app/measure/create-measure/raw/raw.component.ts
@@ -0,0 +1,146 @@
+/*
+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} from "@angular/core";
+import {ServiceService} from "../../../service/service.service";
+import {TREE_ACTIONS, ITreeOptions} from "angular-tree-component";
+import {ToasterService} from "angular2-toaster";
+import * as $ from "jquery";
+import {HttpClient} from "@angular/common/http";
+import {ActivatedRoute, Router} from "@angular/router";
+import {AfterViewChecked, ElementRef} from "@angular/core";
+import {MeasureFormatService, Format} from "../../../service/measure-format.service";
+
+@Component({
+ selector: "app-raw",
+ templateUrl: "./raw.component.html",
+ providers: [ServiceService, MeasureFormatService],
+ styleUrls: ["./raw.component.css"]
+})
+export class RawComponent implements AfterViewChecked {
+
+ constructor(
+ private elementRef: ElementRef,
+ private toasterService: ToasterService,
+ private measureFormatService: MeasureFormatService,
+ private http: HttpClient,
+ private router: Router,
+ public serviceService: ServiceService
+ ) {
+ }
+
+ data = "";
+ valid = false;
+ Format: typeof Format = Format;
+ format: Format;
+ createResult: any;
+ public visible = false;
+ public visibleAnimate = false;
+
+ public hide(): void {
+ this.visibleAnimate = false;
+ setTimeout(() => (this.visible = false), 300);
+ $("#save").removeAttr("disabled");
+ }
+
+ public onContainerClicked(event: MouseEvent): void {
+ if ((<HTMLElement>event.target).classList.contains("modal")) {
+ this.hide();
+ }
+ }
+
+ onResize(event) {
+ this.resizeWindow();
+ }
+
+ ngAfterViewChecked() {
+ this.resizeWindow();
+ }
+
+ resizeWindow() {
+ var stepSelection = ".formStep";
+ $(stepSelection).css({
+ height: window.innerHeight - $(stepSelection).offset().top
+ });
+ $("fieldset").height(
+ $(stepSelection).height() -
+ $(stepSelection + ">.stepDesc").height() -
+ $(".btn-container").height() -
+ 130
+ );
+ $(".y-scrollable").css({
+ height: $("fieldset").height()
+ });
+ }
+
+ submit(form) {
+ if (!form.valid) {
+ this.toasterService.pop(
+ "error",
+ "Error!",
+ "please complete the form in this step before proceeding"
+ );
+ return false;
+ }
+ this.visible = true;
+ setTimeout(() => (this.visibleAnimate = true), 100);
+ }
+
+ save() {
+ let measure2Save = this.measureFormatService.parse(this.data, this.format);
+ console.log(measure2Save);
+ let addModels = this.serviceService.config.uri.addModels;
+ $("#save").attr("disabled", "true");
+ this.http.post(addModels, measure2Save).subscribe(
+ data => {
+ this.createResult = data;
+ this.hide();
+ this.router.navigate(["/measures"]);
+ },
+ err => {
+ let response = JSON.parse(err.error);
+ if (response.code === '40901') {
+ this.toasterService.pop("error", "Error!", "Measure name already exists!");
+ } else {
+ this.toasterService.pop("error", "Error!", response.message);
+ }
+ console.log("Error when creating measure");
+ }
+ );
+ }
+
+ onInputChange() {
+ let format = this.measureFormatService.determineFormat(this.data);
+ if (format) {
+ this.format = format;
+ this.valid = true;
+ }
+ else {
+ this.format = null;
+ this.valid = false;
+ }
+ }
+
+ changeFormat(format: Format) {
+ if (this.valid) {
+ let content = this.measureFormatService.parse(this.data, this.format);
+ this.data = this.measureFormatService.format(content, format);
+ this.format = format;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/bcfd0e26/ui/angular/src/app/measure/measure-detail/measure-detail.component.css
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/measure-detail/measure-detail.component.css b/ui/angular/src/app/measure/measure-detail/measure-detail.component.css
index 9e8c026..034d248 100644
--- a/ui/angular/src/app/measure/measure-detail/measure-detail.component.css
+++ b/ui/angular/src/app/measure/measure-detail/measure-detail.component.css
@@ -28,3 +28,7 @@ under the License.
word-break: break-all;
word-wrap: break-word;
}
+
+.btn-flat {
+ outline: none !important;
+}
http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/bcfd0e26/ui/angular/src/app/measure/measure-detail/measure-detail.component.html
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/measure-detail/measure-detail.component.html b/ui/angular/src/app/measure/measure-detail/measure-detail.component.html
index 02871de..be02599 100644
--- a/ui/angular/src/app/measure/measure-detail/measure-detail.component.html
+++ b/ui/angular/src/app/measure/measure-detail/measure-detail.component.html
@@ -190,11 +190,25 @@ under the License.
{{index.name}} : {{index.infos}}
</div>
</div>
- <h5 class="row">Rules JSON</h5>
+ <h5 class="row">Rules</h5>
<div *ngIf="ruleData['evaluate.rule']">
- <a *ngIf="!showFullRules" (click)="showFullRules=true">Show full JSON</a>
- <a *ngIf="showFullRules" (click)="showFullRules=false">Show rules only</a>
- <pre class="code-viewport">{{ getJsonContent() }}</pre>
+ <div class="row">
+ <div class="col-md-6 col-lg-6 col-sm-6">
+ <label class="form-check-label">
+ Show rules only:
+ <input class="form-check-input" type="checkbox" [checked]="!showFullRules" (change)="showFullRules = !showFullRules">
+ </label>
+ </div>
+ <div class="col-md-6 col-lg-6 col-sm-6">
+ <div class="btn-group btn-group-sm navbar-right" role="group" aria-label="Format">
+ <button type="button" class="btn btn-flat btn-primary" [ngClass]="{'active': format == Format.json}" (click)="format=Format.json">JSON</button>
+ <button type="button" class="btn btn-flat btn-primary" [ngClass]="{'active': format == Format.yaml}" (click)="format=Format.yaml">YAML</button>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <pre class="code-viewport">{{ getRawContent() }}</pre>
+ </div>
</div>
</div>
</div>
http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/bcfd0e26/ui/angular/src/app/measure/measure-detail/measure-detail.component.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/measure/measure-detail/measure-detail.component.ts b/ui/angular/src/app/measure/measure-detail/measure-detail.component.ts
index a30f4fb..5ad5fae 100644
--- a/ui/angular/src/app/measure/measure-detail/measure-detail.component.ts
+++ b/ui/angular/src/app/measure/measure-detail/measure-detail.component.ts
@@ -17,15 +17,16 @@ specific language governing permissions and limitations
under the License.
*/
import {Component, OnInit} from "@angular/core";
-import {Router, ActivatedRoute, ParamMap} from "@angular/router";
+import {ActivatedRoute, Router} from "@angular/router";
import "rxjs/add/operator/switchMap";
import {HttpClient} from "@angular/common/http";
import {ServiceService} from "../../service/service.service";
+import {MeasureFormatService, Format} from "../../service/measure-format.service";
@Component({
selector: "app-measure-detail",
templateUrl: "./measure-detail.component.html",
- providers: [ServiceService],
+ providers: [ServiceService, MeasureFormatService],
styleUrls: ["./measure-detail.component.css"]
})
export class MeasureDetailComponent implements OnInit {
@@ -35,6 +36,7 @@ export class MeasureDetailComponent implements OnInit {
private route: ActivatedRoute,
private router: Router,
private http: HttpClient,
+ private measureFormatService: MeasureFormatService,
public serviceService: ServiceService
) {
}
@@ -42,6 +44,8 @@ export class MeasureDetailComponent implements OnInit {
ruleData: any;
getModelUrl: string;
showFullRules: boolean;
+ Format: typeof Format = Format;
+ format: Format = Format.json;
ruleDes = [];
sourceLength: number;
sourceDB: string;
@@ -112,13 +116,13 @@ export class MeasureDetailComponent implements OnInit {
);
}
- getJsonContent() {
+ getRawContent() {
let content;
if (!this.showFullRules) {
content = (this.ruleData['evaluate.rule'] || {})['rules'];
} else {
content = this.ruleData;
}
- return JSON.stringify(content, null, 4);
+ return this.measureFormatService.format(content, this.format);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/bcfd0e26/ui/angular/src/app/service/measure-format.service.ts
----------------------------------------------------------------------
diff --git a/ui/angular/src/app/service/measure-format.service.ts b/ui/angular/src/app/service/measure-format.service.ts
new file mode 100644
index 0000000..a840470
--- /dev/null
+++ b/ui/angular/src/app/service/measure-format.service.ts
@@ -0,0 +1,48 @@
+import {Injectable} from "@angular/core";
+import * as yaml from "js-yaml";
+
+@Injectable()
+export class MeasureFormatService {
+ constructor() {
+ }
+
+ format(measure: any, format: Format) {
+ switch (format) {
+ case Format.json:
+ return JSON.stringify(measure, null, 4);
+ case Format.yaml:
+ return yaml.dump(measure);
+
+ }
+ }
+
+ parse(data: string, format: Format) {
+ switch (format) {
+ case Format.json:
+ return JSON.parse(data);
+ case Format.yaml:
+ return yaml.load(data);
+
+ }
+ }
+
+ determineFormat(data: string) {
+ try {
+ JSON.parse(data);
+ return Format.json;
+ } catch (e) {}
+ try {
+ if (yaml.load(data)) {
+ return Format.yaml;
+ }
+ } catch (e) {}
+ return null;
+ }
+}
+
+export enum Format {
+ json = 1,
+ yaml = 2
+}
+
+