[helix-front] Enable/Disable clusters
Project: http://git-wip-us.apache.org/repos/asf/helix/repo Commit: http://git-wip-us.apache.org/repos/asf/helix/commit/28d1a2f8 Tree: http://git-wip-us.apache.org/repos/asf/helix/tree/28d1a2f8 Diff: http://git-wip-us.apache.org/repos/asf/helix/diff/28d1a2f8 Branch: refs/heads/master Commit: 28d1a2f8a8303bf418409d312f6cec943780e6e7 Parents: bf181da Author: Vivo Xu <v...@linkedin.com> Authored: Fri Sep 8 11:40:57 2017 -0700 Committer: Junkai Xue <j...@linkedin.com> Committed: Mon Nov 6 17:07:41 2017 -0800 ---------------------------------------------------------------------- helix-front/client/app/app-routing.module.ts | 4 --- .../cluster-detail.component.html | 33 +++++++++--------- .../cluster-detail.component.scss | 13 ++++++++ .../cluster-detail/cluster-detail.component.ts | 35 ++++++++++++++++++-- .../app/cluster/shared/cluster.resolver.ts | 2 ++ .../app/cluster/shared/cluster.service.ts | 10 ++++++ .../config-detail/config-detail.component.html | 8 ++--- .../config-detail/config-detail.component.ts | 7 ++-- .../instance-detail.component.html | 12 +++---- .../instance-detail.component.scss | 6 ---- .../instance-list/instance-list.component.html | 1 + .../instance-list/instance-list.component.ts | 9 +++-- .../resource-list.component.spec.ts | 15 ++++++++- .../resource-list/resource-list.component.ts | 22 +++++++----- .../workflow-list/workflow-list.component.html | 3 ++ .../workflow-list/workflow-list.component.scss | 3 ++ .../workflow-list/workflow-list.component.ts | 20 +++++------ 17 files changed, 137 insertions(+), 66 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/app-routing.module.ts ---------------------------------------------------------------------- diff --git a/helix-front/client/app/app-routing.module.ts b/helix-front/client/app/app-routing.module.ts index 41c7c47..961bde5 100644 --- a/helix-front/client/app/app-routing.module.ts +++ b/helix-front/client/app/app-routing.module.ts @@ -4,7 +4,6 @@ import { RouterModule, Routes } from '@angular/router'; import { AppComponent } from './app.component'; import { NodeViewerComponent } from './shared/node-viewer/node-viewer.component'; import { ClusterComponent } from './cluster/cluster.component'; -import { ClusterResolver } from './cluster/shared/cluster.resolver'; import { ClusterDetailComponent } from './cluster/cluster-detail/cluster-detail.component'; import { ConfigDetailComponent } from './configuration/config-detail/config-detail.component'; import { InstanceListComponent } from './instance/instance-list/instance-list.component'; @@ -36,9 +35,6 @@ const HELIX_ROUTES: Routes = [ { path: ':name', component: ClusterDetailComponent, - resolve: { - cluster: ClusterResolver - }, children: [ { path: '', http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.html ---------------------------------------------------------------------- diff --git a/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.html b/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.html index 835481d..4704417 100644 --- a/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.html +++ b/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.html @@ -1,31 +1,32 @@ <section class="cluster-detail"> - <section *ngIf="cluster"> + <section *ngIf="clusterName"> <md-toolbar class="mat-elevation-z1"> - <hi-detail-header [cluster]="cluster.name"></hi-detail-header> - <md-icon - *ngIf="cluster.enabled" - color="primary"> - check_circle - </md-icon> - <md-icon - *ngIf="!cluster.enabled" - color="warn" - mdTooltip="This cluster is paused."> - pause_circle_filled - </md-icon> - <md-toolbar-row class="information"> + <hi-detail-header [cluster]="clusterName"></hi-detail-header> + <md-toolbar-row *ngIf="isLoading" class="information"> + <md-spinner></md-spinner> + </md-toolbar-row> + <md-toolbar-row *ngIf="!isLoading" class="information"> <h6>Controller: <a md-button color="accent" routerLink="controller">{{ cluster.controller }}</a> </h6> + <section *ngIf="!cluster.enabled"> + <div class="offline"> + This Cluster is currently DISABLED + </div> + </section> <span fxFlex="1 1 auto"></span> <button md-mini-fab *ngIf="can" [mdMenuTriggerFor]="menu"> <md-icon>menu</md-icon> </button> <md-menu #menu="mdMenu"> - <button md-menu-item disabled> - <md-icon>pause</md-icon> + <button md-menu-item *ngIf="cluster.enabled" (click)="disableCluster()"> + <md-icon>not_interested</md-icon> <span>Disable this Cluster</span> </button> + <button md-menu-item *ngIf="!cluster.enabled" (click)="enableCluster()"> + <md-icon>play_circle_outline</md-icon> + <span>Enable this Cluster</span> + </button> <button md-menu-item (click)="addInstance()"> <md-icon>add</md-icon> <span>Add an Instance</span> http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.scss ---------------------------------------------------------------------- diff --git a/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.scss b/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.scss index e69de29..1da0a85 100644 --- a/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.scss +++ b/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.scss @@ -0,0 +1,13 @@ +@import 'client/theme.scss'; + +.offline { + font-size: 14px; + padding-left: 24px; + color: mat-color($hi-warn); +} + +.mat-spinner { + width: 30px; + height: 30px; + margin: 0 20px; +} http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.ts ---------------------------------------------------------------------- diff --git a/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.ts b/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.ts index 6333117..2f7b37f 100644 --- a/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.ts +++ b/helix-front/client/app/cluster/cluster-detail/cluster-detail.component.ts @@ -23,6 +23,8 @@ export class ClusterDetailComponent implements OnInit { { label: 'Configuration', link: 'configs' } ]; + isLoading = false; + clusterName: string; // for better UX needs cluster: Cluster; can = false; @@ -37,15 +39,26 @@ export class ClusterDetailComponent implements OnInit { } ngOnInit() { - this.route.data.subscribe(data => this.cluster = data.cluster); this.clusterService.can().subscribe(data => this.can = data); this.route.params .map(p => p.name) .subscribe(name => { - console.log(name); + this.clusterName = name; + this.loadCluster(); }); } + protected loadCluster() { + this.isLoading = true; + this.clusterService + .get(this.clusterName) + .subscribe( + data => this.cluster = data, + error => this.helperService.showError(error), + () => this.isLoading = false + ); + } + addInstance() { this.dialog .open(InputDialogComponent, { @@ -88,6 +101,24 @@ export class ClusterDetailComponent implements OnInit { }); } + enableCluster() { + this.clusterService + .enable(this.clusterName) + .subscribe( + () => this.loadCluster(), + error => this.helperService.showError(error) + ); + } + + disableCluster() { + this.clusterService + .disable(this.clusterName) + .subscribe( + () => this.loadCluster(), + error => this.helperService.showError(error) + ); + } + deleteCluster() { // disable delete function right now since it's too dangerous /* http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/cluster/shared/cluster.resolver.ts ---------------------------------------------------------------------- diff --git a/helix-front/client/app/cluster/shared/cluster.resolver.ts b/helix-front/client/app/cluster/shared/cluster.resolver.ts index 51d6df5..c7c737a 100644 --- a/helix-front/client/app/cluster/shared/cluster.resolver.ts +++ b/helix-front/client/app/cluster/shared/cluster.resolver.ts @@ -4,6 +4,8 @@ import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; import { ClusterService } from './cluster.service'; import { Cluster } from './cluster.model'; +/* not using this resolver for now since it will break the page when reload the page */ + @Injectable() export class ClusterResolver implements Resolve<Cluster> { http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/cluster/shared/cluster.service.ts ---------------------------------------------------------------------- diff --git a/helix-front/client/app/cluster/shared/cluster.service.ts b/helix-front/client/app/cluster/shared/cluster.service.ts index fef409e..2244729 100644 --- a/helix-front/client/app/cluster/shared/cluster.service.ts +++ b/helix-front/client/app/cluster/shared/cluster.service.ts @@ -34,4 +34,14 @@ export class ClusterService extends HelixService { return this .delete(`/clusters/${ name }`); } + + public enable(name: string) { + return this + .post(`/clusters/${ name }?command=enable`, null); + } + + public disable(name: string) { + return this + .post(`/clusters/${ name }?command=disable`, null); + } } http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/configuration/config-detail/config-detail.component.html ---------------------------------------------------------------------- diff --git a/helix-front/client/app/configuration/config-detail/config-detail.component.html b/helix-front/client/app/configuration/config-detail/config-detail.component.html index 1bbf564..7c053c5 100644 --- a/helix-front/client/app/configuration/config-detail/config-detail.component.html +++ b/helix-front/client/app/configuration/config-detail/config-detail.component.html @@ -1,8 +1,8 @@ -<section> - - <!-- TODO vxu: implement loading --> - +<section fxLayout="column" fxLayoutAlign="center center"> + <md-spinner *ngIf="isLoading"></md-spinner> <hi-node-viewer + *ngIf="!isLoading" + fxFlexFill [obj]="obj" [unlockable]="can && clusterName != null" (update)="updateConfig($event)" http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/configuration/config-detail/config-detail.component.ts ---------------------------------------------------------------------- diff --git a/helix-front/client/app/configuration/config-detail/config-detail.component.ts b/helix-front/client/app/configuration/config-detail/config-detail.component.ts index 31591c2..66b53aa 100644 --- a/helix-front/client/app/configuration/config-detail/config-detail.component.ts +++ b/helix-front/client/app/configuration/config-detail/config-detail.component.ts @@ -53,11 +53,8 @@ export class ConfigDetailComponent implements OnInit { () => this.isLoading = false ); } else { - this.route.parent.data - .subscribe(data => { - this.clusterName = data.cluster.name; - this.loadClusterConfig(); - }); + this.clusterName = this.route.parent.snapshot.params['name']; + this.loadClusterConfig(); } } http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/instance/instance-detail/instance-detail.component.html ---------------------------------------------------------------------- diff --git a/helix-front/client/app/instance/instance-detail/instance-detail.component.html b/helix-front/client/app/instance/instance-detail/instance-detail.component.html index b0af27f..a1d89c4 100644 --- a/helix-front/client/app/instance/instance-detail/instance-detail.component.html +++ b/helix-front/client/app/instance/instance-detail/instance-detail.component.html @@ -9,14 +9,12 @@ <hi-key-value-pair name="Session ID" prop="sessionId"></hi-key-value-pair> <hi-key-value-pair name="Helix Version" prop="helixVersion"></hi-key-value-pair> </hi-key-value-pairs> - <section *ngIf="!isLoading && !instance.liveInstance"> + <section *ngIf="!isLoading && !instance.healthy"> <div class="offline"> - This Instance is currently offline. - </div> - </section> - <section *ngIf="!isLoading && !instance.enabled"> - <div class="disabled"> - This Instance is currently disabled. + This Instance is currently + <span *ngIf="!instance.liveInstance">OFFLINE</span> + <span *ngIf="!instance.liveInstance && !instance.enabled">and</span> + <span *ngIf="!instance.enabled">DISABLED</span> </div> </section> <span fxFlex="1 1 auto"></span> http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/instance/instance-detail/instance-detail.component.scss ---------------------------------------------------------------------- diff --git a/helix-front/client/app/instance/instance-detail/instance-detail.component.scss b/helix-front/client/app/instance/instance-detail/instance-detail.component.scss index 21c4df1..2b809df 100644 --- a/helix-front/client/app/instance/instance-detail/instance-detail.component.scss +++ b/helix-front/client/app/instance/instance-detail/instance-detail.component.scss @@ -1,4 +1,3 @@ -@import '~@angular/material/theming'; @import 'client/theme.scss'; .information { @@ -15,9 +14,4 @@ padding-left: 24px; color: mat-color($hi-warn); } - - .disabled { - padding-left: 24px; - color: mat-color($hi-accent); - } } http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/instance/instance-list/instance-list.component.html ---------------------------------------------------------------------- diff --git a/helix-front/client/app/instance/instance-list/instance-list.component.html b/helix-front/client/app/instance/instance-list/instance-list.component.html index d76137f..192cc1a 100644 --- a/helix-front/client/app/instance/instance-list/instance-list.component.html +++ b/helix-front/client/app/instance/instance-list/instance-list.component.html @@ -7,6 +7,7 @@ columnMode="force" [footerHeight]="rowHeight" [rows]="instances" + [loadingIndicator]="isLoading" selectionType="single" [sorts]="sorts" (select)="onSelect($event)"> http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/instance/instance-list/instance-list.component.ts ---------------------------------------------------------------------- diff --git a/helix-front/client/app/instance/instance-list/instance-list.component.ts b/helix-front/client/app/instance/instance-list/instance-list.component.ts index d03fe3b..748dbc6 100644 --- a/helix-front/client/app/instance/instance-list/instance-list.component.ts +++ b/helix-front/client/app/instance/instance-list/instance-list.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; import { InstanceService } from '../shared/instance.service'; +import { HelperService } from '../../shared/helper.service'; @Component({ selector: 'hi-instance-list', @@ -10,6 +11,7 @@ import { InstanceService } from '../shared/instance.service'; }) export class InstanceListComponent implements OnInit { + isLoading = true; clusterName: string; instances: any[]; rowHeight = 40; @@ -21,7 +23,8 @@ export class InstanceListComponent implements OnInit { constructor( protected route: ActivatedRoute, protected router: Router, - protected service: InstanceService + protected service: InstanceService, + protected helper: HelperService ) { } ngOnInit() { @@ -30,7 +33,9 @@ export class InstanceListComponent implements OnInit { this.service .getAll(this.clusterName) .subscribe( - data => this.instances = data + data => this.instances = data, + error => this.helper.showError(error), + () => this.isLoading = false ); } } http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/resource/resource-list/resource-list.component.spec.ts ---------------------------------------------------------------------- diff --git a/helix-front/client/app/resource/resource-list/resource-list.component.spec.ts b/helix-front/client/app/resource/resource-list/resource-list.component.spec.ts index 4da2399..24a3e61 100644 --- a/helix-front/client/app/resource/resource-list/resource-list.component.spec.ts +++ b/helix-front/client/app/resource/resource-list/resource-list.component.spec.ts @@ -5,19 +5,32 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ResourceListComponent } from './resource-list.component'; import { ResourceService } from '../shared/resource.service'; +import { HelperService } from '../../shared/helper.service'; describe('ResourceListComponent', () => { let component: ResourceListComponent; let fixture: ComponentFixture<ResourceListComponent>; beforeEach(async(() => { + // stub HelperService for test purpose + const helperServiceStub = { + showError: (message: string) => {}, + showSnackBar: (message: string) => {} + }; + TestBed.configureTestingModule({ imports: [ HttpModule, RouterTestingModule ], declarations: [ ResourceListComponent ], - providers: [ ResourceService ], + providers: [ + ResourceService, + { + provide: HelperService, + useValue: helperServiceStub + } + ], schemas: [ /* avoid importing modules */ NO_ERRORS_SCHEMA http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/resource/resource-list/resource-list.component.ts ---------------------------------------------------------------------- diff --git a/helix-front/client/app/resource/resource-list/resource-list.component.ts b/helix-front/client/app/resource/resource-list/resource-list.component.ts index 3ba184c..4c72cf3 100644 --- a/helix-front/client/app/resource/resource-list/resource-list.component.ts +++ b/helix-front/client/app/resource/resource-list/resource-list.component.ts @@ -4,6 +4,7 @@ import { Router, ActivatedRoute } from '@angular/router'; import { Resource } from '../shared/resource.model'; import { ResourceService } from '../shared/resource.service'; import { WorkflowService } from '../../workflow/shared/workflow.service'; +import { HelperService } from '../../shared/helper.service'; import { Observable } from 'rxjs/Rx'; import * as _ from 'lodash'; @@ -33,7 +34,8 @@ export class ResourceListComponent implements OnInit { private router: Router, private route: ActivatedRoute, private service: ResourceService, - private workflowService: WorkflowService + private workflowService: WorkflowService, + protected helper: HelperService ) { } ngOnInit() { @@ -53,11 +55,12 @@ export class ResourceListComponent implements OnInit { () => this.isLoading = false ); } else { - this.route.parent.data.subscribe(data => { - this.isLoading = true; - this.clusterName = data.cluster.name; - this.fetchResources(); - }); + this.route.parent.params + .map(p => p.name) + .subscribe(name => { + this.clusterName = name; + this.fetchResources(); + }); } } } @@ -69,6 +72,9 @@ export class ResourceListComponent implements OnInit { protected fetchResources() { let jobs = []; + this.isLoading = true; + this.resources = null; + this.workflowService .getAll(this.clusterName) .concatMap(workflows => Observable.from(workflows)) @@ -82,7 +88,7 @@ export class ResourceListComponent implements OnInit { list => { jobs = jobs.concat(list); }, - error => console.log(error), + error => this.helper.showError(error), () => { this.service .getAll(this.clusterName) @@ -90,7 +96,7 @@ export class ResourceListComponent implements OnInit { result => { this.resources = _.differenceWith(result, jobs, (resource: Resource, name) => resource.name === name); }, - error => console.log(error), + error => this.helper.showError(error), () => this.isLoading = false ); } http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/workflow/workflow-list/workflow-list.component.html ---------------------------------------------------------------------- diff --git a/helix-front/client/app/workflow/workflow-list/workflow-list.component.html b/helix-front/client/app/workflow/workflow-list/workflow-list.component.html index b0089cb..f3b642f 100644 --- a/helix-front/client/app/workflow/workflow-list/workflow-list.component.html +++ b/helix-front/client/app/workflow/workflow-list/workflow-list.component.html @@ -1,6 +1,9 @@ <section fxLayout="column" fxLayoutAlign="center center"> <md-spinner *ngIf="isLoading"></md-spinner> <section fxFlexFill> + <section *ngIf="!isLoading && workflows.length == 0" class="empty"> + There's no workflow here. + </section> <md-nav-list> <a *ngFor="let name of workflows" md-list-item http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/workflow/workflow-list/workflow-list.component.scss ---------------------------------------------------------------------- diff --git a/helix-front/client/app/workflow/workflow-list/workflow-list.component.scss b/helix-front/client/app/workflow/workflow-list/workflow-list.component.scss index e69de29..c9d208f 100644 --- a/helix-front/client/app/workflow/workflow-list/workflow-list.component.scss +++ b/helix-front/client/app/workflow/workflow-list/workflow-list.component.scss @@ -0,0 +1,3 @@ +.empty { + padding: 20px; +} http://git-wip-us.apache.org/repos/asf/helix/blob/28d1a2f8/helix-front/client/app/workflow/workflow-list/workflow-list.component.ts ---------------------------------------------------------------------- diff --git a/helix-front/client/app/workflow/workflow-list/workflow-list.component.ts b/helix-front/client/app/workflow/workflow-list/workflow-list.component.ts index 0824b17..08963d9 100644 --- a/helix-front/client/app/workflow/workflow-list/workflow-list.component.ts +++ b/helix-front/client/app/workflow/workflow-list/workflow-list.component.ts @@ -22,18 +22,16 @@ export class WorkflowListComponent implements OnInit { ngOnInit() { if (this.route.parent) { - this.route.parent.data.subscribe(data => { - this.isLoading = true; - this.clusterName = data.cluster.name; + this.isLoading = true; + this.clusterName = this.route.parent.snapshot.params['name']; - this.service - .getAll(this.clusterName) - .subscribe( - workflows => this.workflows = workflows, - error => console.log(error), - () => this.isLoading = false - ); - }); + this.service + .getAll(this.clusterName) + .subscribe( + workflows => this.workflows = workflows, + error => console.log(error), + () => this.isLoading = false + ); } }