From b72937e8fb56c9bbb78049154c4f3086141cc4bd Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 14 May 2018 19:46:03 +0200 Subject: [PATCH] Fix webui --- webui/.angular-cli.json | 4 +- webui/package.json | 2 +- webui/src/app.sass | 27 + webui/src/app/app.component.spec.ts | 2 +- webui/src/app/app.module.ts | 32 +- .../charts/bar-chart/bar-chart.component.ts | 51 +- .../line-chart/line-chart.component.html | 2 +- .../charts/line-chart/line-chart.component.ts | 87 ++- .../components/header/header.component.html | 38 +- .../app/components/header/header.component.ts | 1 + .../components/health/health.component.html | 12 +- .../app/components/health/health.component.ts | 40 +- .../providers/providers.component.html | 590 +++++++++--------- .../providers/providers.component.ts | 41 +- webui/src/app/directives/let.directive.ts | 21 + webui/src/app/pipes/backend.filter.pipe.ts | 17 + webui/src/app/pipes/frontend.filter.pipe.ts | 18 + webui/src/app/pipes/keys.pipe.ts | 4 +- webui/src/app/services/api.service.ts | 67 +- webui/src/styles/app.sass | 25 +- webui/src/styles/charts.sass | 6 - webui/src/styles/content.sass | 67 +- webui/src/styles/label.sass | 29 - webui/src/styles/message.sass | 98 ++- webui/src/styles/nav.sass | 6 +- webui/src/styles/typography.sass | 12 +- webui/src/styles/variables.sass | 1 + webui/yarn.lock | 6 +- 28 files changed, 696 insertions(+), 610 deletions(-) create mode 100644 webui/src/app.sass create mode 100644 webui/src/app/directives/let.directive.ts create mode 100644 webui/src/app/pipes/backend.filter.pipe.ts create mode 100644 webui/src/app/pipes/frontend.filter.pipe.ts delete mode 100644 webui/src/styles/label.sass create mode 100644 webui/src/styles/variables.sass diff --git a/webui/.angular-cli.json b/webui/.angular-cli.json index 145265719..dc1419956 100644 --- a/webui/.angular-cli.json +++ b/webui/.angular-cli.json @@ -8,7 +8,7 @@ "root": "src", "outDir": "dist", "assets": [ - "assets", + "assets/images", "favicon.ico" ], "index": "index.html", @@ -19,7 +19,7 @@ "testTsconfig": "tsconfig.spec.json", "prefix": "app", "styles": [ - "styles/app.sass" + "app.sass" ], "scripts": [ "../node_modules/@fortawesome/fontawesome/index.js", diff --git a/webui/package.json b/webui/package.json index 9dec23f21..b52a59d60 100644 --- a/webui/package.json +++ b/webui/package.json @@ -27,7 +27,7 @@ "@angular/router": "^5.2.0", "@fortawesome/fontawesome": "^1.1.5", "@fortawesome/fontawesome-free-solid": "^5.0.10", - "bulma": "^0.6.2", + "bulma": "^0.7.0", "core-js": "^2.4.1", "d3": "^4.13.0", "date-fns": "^1.29.0", diff --git a/webui/src/app.sass b/webui/src/app.sass new file mode 100644 index 000000000..64a380502 --- /dev/null +++ b/webui/src/app.sass @@ -0,0 +1,27 @@ +@charset "utf-8" + +@import 'styles/typography' +@import 'styles/variables' +@import 'styles/colors' +@import '~bulma/sass/utilities/all' +@import '~bulma/sass/base/all' +@import '~bulma/sass/grid/all' +@import '~bulma/sass/elements/container' +@import '~bulma/sass/elements/tag' +@import '~bulma/sass/elements/other' +@import '~bulma/sass/elements/box' +@import '~bulma/sass/elements/form' +@import '~bulma/sass/elements/table' +@import '~bulma/sass/components/navbar' +@import '~bulma/sass/components/tabs' +@import '~bulma/sass/elements/notification' +@import 'styles/nav' +@import 'styles/content' +@import 'styles/message' +@import 'styles/charts' +@import 'styles/helper' + +html + font-family: $open-sans + height: 100% + background: $background diff --git a/webui/src/app/app.component.spec.ts b/webui/src/app/app.component.spec.ts index 16c7679ce..8836204f4 100644 --- a/webui/src/app/app.component.spec.ts +++ b/webui/src/app/app.component.spec.ts @@ -1,4 +1,4 @@ -import { TestBed, async } from '@angular/core/testing'; +import { async, TestBed } from '@angular/core/testing'; import { AppComponent } from './app.component'; describe('AppComponent', () => { diff --git a/webui/src/app/app.module.ts b/webui/src/app/app.module.ts index a544f385f..c9ba2741a 100644 --- a/webui/src/app/app.module.ts +++ b/webui/src/app/app.module.ts @@ -1,18 +1,21 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; import { CommonModule } from '@angular/common'; -import { RouterModule } from '@angular/router'; import { HttpClientModule } from '@angular/common/http'; +import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; +import { AppComponent } from './app.component'; +import { BarChartComponent } from './charts/bar-chart/bar-chart.component'; +import { LineChartComponent } from './charts/line-chart/line-chart.component'; +import { HeaderComponent } from './components/header/header.component'; +import { HealthComponent } from './components/health/health.component'; +import { ProvidersComponent } from './components/providers/providers.component'; +import { LetDirective } from './directives/let.directive'; +import { BackendFilterPipe } from './pipes/backend.filter.pipe'; +import { FrontendFilterPipe } from './pipes/frontend.filter.pipe'; +import { KeysPipe } from './pipes/keys.pipe'; import { ApiService } from './services/api.service'; import { WindowService } from './services/window.service'; -import { AppComponent } from './app.component'; -import { HeaderComponent } from './components/header/header.component'; -import { ProvidersComponent } from './components/providers/providers.component'; -import { HealthComponent } from './components/health/health.component'; -import { LineChartComponent } from './charts/line-chart/line-chart.component'; -import { BarChartComponent } from './charts/bar-chart/bar-chart.component'; -import { KeysPipe } from './pipes/keys.pipe'; @NgModule({ declarations: [ @@ -22,7 +25,10 @@ import { KeysPipe } from './pipes/keys.pipe'; HealthComponent, LineChartComponent, BarChartComponent, - KeysPipe + KeysPipe, + FrontendFilterPipe, + BackendFilterPipe, + LetDirective ], imports: [ BrowserModule, @@ -30,8 +36,8 @@ import { KeysPipe } from './pipes/keys.pipe'; HttpClientModule, FormsModule, RouterModule.forRoot([ - { path: '', component: ProvidersComponent, pathMatch: 'full' }, - { path: 'status', component: HealthComponent } + {path: '', component: ProvidersComponent, pathMatch: 'full'}, + {path: 'status', component: HealthComponent} ]) ], providers: [ diff --git a/webui/src/app/charts/bar-chart/bar-chart.component.ts b/webui/src/app/charts/bar-chart/bar-chart.component.ts index 8d130c4fb..47946d9ae 100644 --- a/webui/src/app/charts/bar-chart/bar-chart.component.ts +++ b/webui/src/app/charts/bar-chart/bar-chart.component.ts @@ -1,15 +1,7 @@ -import { Component, Input, OnInit, ElementRef, OnChanges, SimpleChanges } from '@angular/core'; +import { Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { axisBottom, axisLeft, easeLinear, max, min, scaleBand, scaleLinear, select } from 'd3'; +import * as _ from 'lodash'; import { WindowService } from '../../services/window.service'; -import { - min, - max, - easeLinear, - select, - axisLeft, - axisBottom, - scaleBand, - scaleLinear -} from 'd3'; @Component({ selector: 'app-bar-chart', @@ -23,12 +15,12 @@ export class BarChartComponent implements OnInit, OnChanges { x: any; y: any; g: any; - bars: any; width: number; height: number; - margin = { top: 40, right: 40, bottom: 40, left: 40 }; + margin = {top: 40, right: 40, bottom: 40, left: 40}; loading: boolean; data: any[]; + previousData: any[]; constructor(public elementRef: ElementRef, public windowService: WindowService) { this.loading = true; @@ -37,7 +29,7 @@ export class BarChartComponent implements OnInit, OnChanges { ngOnInit() { this.barChartEl = this.elementRef.nativeElement.querySelector('.bar-chart'); this.setup(); - setTimeout(() => this.loading = false, 4000); + setTimeout(() => this.loading = false, 1000); this.windowService.resize.subscribe(w => this.draw()); } @@ -47,15 +39,20 @@ export class BarChartComponent implements OnInit, OnChanges { return; } - this.data = this.value; - this.draw(); + if (!_.isEqual(this.previousData, this.value)) { + this.previousData = _.cloneDeep(this.value); + this.data = this.value; + + this.draw(); + } } setup(): void { this.width = this.barChartEl.clientWidth - this.margin.left - this.margin.right; this.height = this.barChartEl.clientHeight - this.margin.top - this.margin.bottom; - this.svg = select(this.barChartEl).append('svg') + this.svg = select(this.barChartEl) + .append('svg') .attr('width', this.width + this.margin.left + this.margin.right) .attr('height', this.height + this.margin.top + this.margin.bottom); @@ -73,11 +70,16 @@ export class BarChartComponent implements OnInit, OnChanges { } draw(): void { + if (this.barChartEl.clientWidth === 0 || this.barChartEl.clientHeight === 0) { + this.previousData = []; + } else { + this.width = this.barChartEl.clientWidth - this.margin.left - this.margin.right; + this.height = this.barChartEl.clientHeight - this.margin.top - this.margin.bottom; + } + this.x.domain(this.data.map((d: any) => d.code)); this.y.domain([0, max(this.data, (d: any) => d.count)]); - this.width = this.barChartEl.clientWidth - this.margin.left - this.margin.right; - this.height = this.barChartEl.clientHeight - this.margin.top - this.margin.bottom; this.svg .attr('width', this.width + this.margin.left + this.margin.right) @@ -93,17 +95,16 @@ export class BarChartComponent implements OnInit, OnChanges { this.g.select('.axis--y') .call(axisLeft(this.y).tickSize(-this.width)); + // Clean previous graph + this.g.selectAll('.bar').remove(); + const bars = this.g.selectAll('.bar').data(this.data); bars.enter() .append('rect') .attr('class', 'bar') - .attr('x', (d: any) => d.code) - .attr('y', (d: any) => d.count) - .attr('width', this.x.bandwidth()) - .attr('height', (d: any) => (this.height - this.y(d.count)) < 0 ? 0 : this.height - this.y(d.count)); - - bars.attr('x', (d: any) => this.x(d.code)) + .style('fill', (d: any) => 'hsl(' + Math.floor(((d.code - 100) * 310 / 427) + 50) + ', 50%, 50%)') + .attr('x', (d: any) => this.x(d.code)) .attr('y', (d: any) => this.y(d.count)) .attr('width', this.x.bandwidth()) .attr('height', (d: any) => (this.height - this.y(d.count)) < 0 ? 0 : this.height - this.y(d.count)); diff --git a/webui/src/app/charts/line-chart/line-chart.component.html b/webui/src/app/charts/line-chart/line-chart.component.html index 929411c3e..f216459d8 100644 --- a/webui/src/app/charts/line-chart/line-chart.component.html +++ b/webui/src/app/charts/line-chart/line-chart.component.html @@ -1,5 +1,5 @@
-
+
Loading, please wait... diff --git a/webui/src/app/charts/line-chart/line-chart.component.ts b/webui/src/app/charts/line-chart/line-chart.component.ts index 92fc7c0cd..e07f132ea 100644 --- a/webui/src/app/charts/line-chart/line-chart.component.ts +++ b/webui/src/app/charts/line-chart/line-chart.component.ts @@ -1,20 +1,20 @@ -import { Component, Input, OnInit, ElementRef, OnChanges, SimpleChanges } from '@angular/core'; -import { WindowService } from '../../services/window.service'; +import { Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { - range, - scaleTime, - scaleLinear, - min, - max, - curveLinear, - line, - easeLinear, - select, - axisLeft, axisBottom, - timeSecond, - timeFormat + axisLeft, + curveLinear, + easeLinear, + line, + max, + min, + range, + scaleLinear, + scaleTime, + select, + timeFormat, + timeSecond } from 'd3'; +import { WindowService } from '../../services/window.service'; @Component({ selector: 'app-line-chart', @@ -23,7 +23,10 @@ import { export class LineChartComponent implements OnChanges, OnInit { @Input() value: { count: number, date: string }; + firstDisplay: boolean; + dirty: boolean; lineChartEl: HTMLElement; + loadingEl: HTMLElement; svg: any; g: any; line: any; @@ -39,15 +42,19 @@ export class LineChartComponent implements OnChanges, OnInit { yAxis: any; height: number; width: number; - margin = { top: 40, right: 40, bottom: 60, left: 60 }; + margin = {top: 40, right: 40, bottom: 60, left: 60}; loading = true; constructor(private elementRef: ElementRef, public windowService: WindowService) { } ngOnInit() { this.lineChartEl = this.elementRef.nativeElement.querySelector('.line-chart'); + this.loadingEl = this.elementRef.nativeElement.querySelector('.line-chart-loading'); this.limit = 40; + + // related to the Observable.timer(0, 3000) in health component this.duration = 3000; + this.now = new Date(Date.now() - this.duration); this.options = { @@ -55,22 +62,37 @@ export class LineChartComponent implements OnChanges, OnInit { color: '#3A84C5' }; + this.firstDisplay = true; this.render(); - setTimeout(() => this.loading = false, 4000); + this.windowService.resize.subscribe(w => { if (this.svg) { - const el = this.lineChartEl.querySelector('svg'); - el.parentNode.removeChild(el); + this.dirty = true; + this.loading = true; this.render(); } }); } render() { - this.width = this.lineChartEl.clientWidth - this.margin.left - this.margin.right; - this.height = this.lineChartEl.clientHeight - this.margin.top - this.margin.bottom; + // When the lineChartEl is not displayed (is-hidden), width and length are equal to 0. + let elt; + if (this.lineChartEl.clientWidth === 0 || this.lineChartEl.clientHeight === 0) { + elt = this.loadingEl; + } else { + elt = this.lineChartEl; + } + this.width = elt.clientWidth - this.margin.left - this.margin.right; + this.height = elt.clientHeight - this.margin.top - this.margin.bottom; - this.svg = select(this.lineChartEl).append('svg') + + const el = this.lineChartEl.querySelector('svg'); + if (el) { + el.parentNode.removeChild(el); + } + + this.svg = select(this.lineChartEl) + .append('svg') .attr('width', this.width + this.margin.left + this.margin.right) .attr('height', this.height + this.margin.top + this.margin.bottom) .append('g') @@ -80,7 +102,7 @@ export class LineChartComponent implements OnChanges, OnInit { this.data = range(this.limit).map(i => 0); } - this.x = scaleTime().range([0, this.width]); + this.x = scaleTime().range([0, this.width - 10]); this.y = scaleLinear().range([this.height, 0]); this.x.domain([this.now - (this.limit - 2), this.now - this.duration]); @@ -91,7 +113,9 @@ export class LineChartComponent implements OnChanges, OnInit { .y((d: any) => this.y(d)) .curve(curveLinear); - this.svg.append('defs').append('clipPath') + this.svg + .append('defs') + .append('clipPath') .attr('id', 'clip') .append('rect') .attr('width', this.width) @@ -121,7 +145,7 @@ export class LineChartComponent implements OnChanges, OnInit { this.updateData(this.value.count); } - updateData = (value: number) => { + updateData(value: number) { this.data.push(value * 1000000); this.now = new Date(); @@ -132,9 +156,13 @@ export class LineChartComponent implements OnChanges, OnInit { this.xAxis .transition() - .duration(this.duration) + .duration(this.firstDisplay || this.dirty ? 0 : this.duration) .ease(easeLinear) - .call(axisBottom(this.x).tickSize(-this.height).ticks(timeSecond, 5).tickFormat(timeFormat('%H:%M:%S'))) + .call(axisBottom(this.x).tickSize(-this.height).ticks(timeSecond, 5).tickFormat(timeFormat('%H:%M:%S'))); + + this.xAxis + .transition() + .duration(0) .selectAll('text') .style('text-anchor', 'end') .attr('dx', '-.8em') @@ -157,6 +185,13 @@ export class LineChartComponent implements OnChanges, OnInit { .ease(easeLinear) .attr('transform', `translate(${this.x(this.now - (this.limit - 1) * this.duration)})`); + this.firstDisplay = false; + this.dirty = false; + + if (this.loading) { + this.loading = false; + } + this.data.shift(); } } diff --git a/webui/src/app/components/header/header.component.html b/webui/src/app/components/header/header.component.html index 46fc6d6a3..7254a8afb 100644 --- a/webui/src/app/components/header/header.component.html +++ b/webui/src/app/components/header/header.component.html @@ -1,22 +1,27 @@ -