diff options
author | Jongmok Hong <jongmok@google.com> | 2018-10-02 08:54:47 +0900 |
---|---|---|
committer | Jongmok Hong <jongmok@google.com> | 2018-10-12 08:29:33 +0900 |
commit | 6cbe628b7c378aa6fd7b59dc06505adecb6b1af2 (patch) | |
tree | 2ead007a8bf3d8cd1406a0a755bdc67d58cd72f6 | |
parent | 29ce9f1172f1debf42ac2b74f96b0483bd88e679 (diff) | |
download | test_serving-6cbe628b7c378aa6fd7b59dc06505adecb6b1af2.tar.gz |
Add a Show Details button to list all properties.
Test: go/vtslab-schedule-dev/redirect/20181011t154848-dot-vtslab-schedule-dev
Bug: 117531288
Change-Id: If2ae84baf01d64d83e5918e5bd0dfdff1ddc31c8
-rw-r--r-- | gae/frontend/src/app/app.component.html | 17 | ||||
-rw-r--r-- | gae/frontend/src/app/app.component.scss | 28 | ||||
-rw-r--r-- | gae/frontend/src/app/app.component.ts | 37 | ||||
-rw-r--r-- | gae/frontend/src/app/app.module.ts | 6 | ||||
-rw-r--r-- | gae/frontend/src/app/appservice.ts | 37 | ||||
-rw-r--r-- | gae/frontend/src/app/menu/build/build.component.ts | 6 | ||||
-rw-r--r-- | gae/frontend/src/app/menu/dashboard/dashboard.component.ts | 6 | ||||
-rw-r--r-- | gae/frontend/src/app/menu/device/device.component.ts | 6 | ||||
-rw-r--r-- | gae/frontend/src/app/menu/job/job.component.html | 3 | ||||
-rw-r--r-- | gae/frontend/src/app/menu/job/job.component.scss | 17 | ||||
-rw-r--r-- | gae/frontend/src/app/menu/job/job.component.ts | 6 | ||||
-rw-r--r-- | gae/frontend/src/app/menu/lab/lab.component.ts | 6 | ||||
-rw-r--r-- | gae/frontend/src/app/menu/menu_base.ts | 10 | ||||
-rw-r--r-- | gae/frontend/src/app/menu/schedule/schedule.component.html | 3 | ||||
-rw-r--r-- | gae/frontend/src/app/menu/schedule/schedule.component.scss | 4 | ||||
-rw-r--r-- | gae/frontend/src/app/menu/schedule/schedule.component.ts | 6 | ||||
-rw-r--r-- | gae/frontend/src/styles.scss | 6 |
17 files changed, 185 insertions, 19 deletions
diff --git a/gae/frontend/src/app/app.component.html b/gae/frontend/src/app/app.component.html index a4df15a..8f21391 100644 --- a/gae/frontend/src/app/app.component.html +++ b/gae/frontend/src/app/app.component.html @@ -17,4 +17,19 @@ <app-nav-bar id="nav-bar"></app-nav-bar> </div> </header> -<router-outlet id="router-outlet"></router-outlet> +<mat-sidenav-container> + <mat-sidenav-content> + <router-outlet id="router-outlet"></router-outlet> + </mat-sidenav-content> + <mat-sidenav #sidenav mode="over" position="end" [(opened)]="sideNavOpened"> + <button mat-button (click)="sidenav.toggle()"> + <mat-icon>clear</mat-icon> + </button> + <mat-list> + <mat-list-item *ngFor="let property of selectedEntity"> + <h4 id="property-name" mat-line>{{property.name}}</h4> + <p id="property-value" mat-line *ngFor="let each of property.value">{{each}}</p> + </mat-list-item> + </mat-list> + </mat-sidenav> +</mat-sidenav-container> diff --git a/gae/frontend/src/app/app.component.scss b/gae/frontend/src/app/app.component.scss index e69de29..d818d0e 100644 --- a/gae/frontend/src/app/app.component.scss +++ b/gae/frontend/src/app/app.component.scss @@ -0,0 +1,28 @@ +mat-sidenav { + width: 400px; + padding: 30px 10px; +} + +#property-name { + color: rgba(0, 0, 0, 0.66); + font-size: 12px; + margin-bottom: 2px; +} + +#property-value { + font-size: 12px; +} + +.mat-button { + position: absolute; + top: 10px; + right: 10px; + min-width: 28px; + width: 28px; + height: 28px; + padding: 0; + .mat-icon { + width: 24px; + height: 24px; + } +} diff --git a/gae/frontend/src/app/app.component.ts b/gae/frontend/src/app/app.component.ts index 9e83762..68b7e6d 100644 --- a/gae/frontend/src/app/app.component.ts +++ b/gae/frontend/src/app/app.component.ts @@ -16,10 +16,47 @@ import { Component } from '@angular/core'; +import { AppService } from "./appservice"; + + @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { + _sideNavOpened = false; + get sideNavOpened(): boolean { + return this._sideNavOpened; + } + set sideNavOpened(value: boolean) { + this._sideNavOpened = value; + if (!value) { + this.selectedEntity = this.selectedEntity.slice(); + } + } + selectedEntity: {name: string; value: any[]}[] = []; + + constructor(private appService: AppService) { + appService.closeSideNavEmitter.subscribe(() => {this.sideNavOpened = false}); + appService.showDetailsEmitter.subscribe( + (entity) => { + if (entity) { + let self = this; + Object.keys(entity).forEach(function(value){ + if (value !== 'urlsafe_key') { + self.selectedEntity.push({ + name: value, + value: (entity[value] instanceof Array) ? entity[value] : [entity[value]] + }); + } + }); + } + this.sideNavOpened = !this.sideNavOpened; + }, + (error) => { + console.log(error); + } + ) + } } diff --git a/gae/frontend/src/app/app.module.ts b/gae/frontend/src/app/app.module.ts index c70fd52..ec940db 100644 --- a/gae/frontend/src/app/app.module.ts +++ b/gae/frontend/src/app/app.module.ts @@ -29,10 +29,12 @@ import { MatExpansionModule } from '@angular/material/expansion'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material'; import { MatInputModule } from '@angular/material/input'; +import { MatListModule } from '@angular/material/list'; import { MatPaginatorModule } from '@angular/material/paginator'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatSelectModule } from '@angular/material/select'; +import { MatSidenavModule } from '@angular/material/sidenav'; import { MatSortModule } from '@angular/material/sort'; import { MatTableModule } from '@angular/material/table'; import { MatTabsModule } from '@angular/material/tabs'; @@ -77,10 +79,12 @@ const appRoutes: Routes = [ MatFormFieldModule, MatIconModule, MatInputModule, + MatListModule, MatPaginatorModule, MatProgressSpinnerModule, MatSnackBarModule, MatSelectModule, + MatSidenavModule, MatSortModule, MatTableModule, MatTabsModule, @@ -93,10 +97,12 @@ const appRoutes: Routes = [ MatFormFieldModule, MatIconModule, MatInputModule, + MatListModule, MatPaginatorModule, MatProgressSpinnerModule, MatSnackBarModule, MatSelectModule, + MatSidenavModule, MatSortModule, MatTableModule, MatTabsModule, diff --git a/gae/frontend/src/app/appservice.ts b/gae/frontend/src/app/appservice.ts new file mode 100644 index 0000000..6b303f0 --- /dev/null +++ b/gae/frontend/src/app/appservice.ts @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed 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 {EventEmitter, Injectable, Output} from '@angular/core'; + + +@Injectable({ + providedIn: 'root', +}) +export class AppService { + @Output() closeSideNavEmitter = new EventEmitter(); + @Output() showDetailsEmitter = new EventEmitter(); + constructor() { + } + + /** Emits an EventEmitter to display entity in the side nav window. */ + showDetails(entity) { + this.showDetailsEmitter.emit(entity); + } + + /** Emits an EventEmitter to close the side nav window. */ + closeSideNav() { + this.closeSideNavEmitter.emit(); + } +} diff --git a/gae/frontend/src/app/menu/build/build.component.ts b/gae/frontend/src/app/menu/build/build.component.ts index e149f87..e4c7325 100644 --- a/gae/frontend/src/app/menu/build/build.component.ts +++ b/gae/frontend/src/app/menu/build/build.component.ts @@ -16,6 +16,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { MatSnackBar, MatTableDataSource, PageEvent } from '@angular/material'; +import { AppService } from '../../appservice'; import { Build } from '../../model/build'; import { BuildService } from './build.service'; import { FilterComponent } from '../../shared/filter/filter.component'; @@ -46,8 +47,9 @@ export class BuildComponent extends MenuBaseClass implements OnInit { @ViewChild(FilterComponent) filterComponent: FilterComponent; constructor(private buildService: BuildService, - public snackBar: MatSnackBar) { - super(snackBar); + appService: AppService, + snackBar: MatSnackBar) { + super(appService, snackBar); } ngOnInit(): void { diff --git a/gae/frontend/src/app/menu/dashboard/dashboard.component.ts b/gae/frontend/src/app/menu/dashboard/dashboard.component.ts index 79d85a0..0157ea8 100644 --- a/gae/frontend/src/app/menu/dashboard/dashboard.component.ts +++ b/gae/frontend/src/app/menu/dashboard/dashboard.component.ts @@ -16,6 +16,7 @@ import { Component, OnInit } from '@angular/core'; import { MatSnackBar } from '@angular/material'; +import { AppService } from '../../appservice'; import { BuildService } from "../build/build.service"; import { MenuBaseClass } from "../menu_base"; import { ScheduleService } from "../schedule/schedule.service"; @@ -33,8 +34,9 @@ export class DashboardComponent extends MenuBaseClass implements OnInit { constructor(private buildService: BuildService, private scheduleService: ScheduleService, - public snackBar: MatSnackBar) { - super(snackBar); + appService: AppService, + snackBar: MatSnackBar) { + super(appService, snackBar); } ngOnInit(): void { diff --git a/gae/frontend/src/app/menu/device/device.component.ts b/gae/frontend/src/app/menu/device/device.component.ts index 31407d5..2fc9a72 100644 --- a/gae/frontend/src/app/menu/device/device.component.ts +++ b/gae/frontend/src/app/menu/device/device.component.ts @@ -16,6 +16,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { MatSnackBar, MatTableDataSource, PageEvent } from '@angular/material'; +import { AppService } from '../../appservice'; import { Device } from '../../model/device'; import { DeviceService } from './device.service'; import { DeviceStatus, SchedulingStatus } from '../../shared/vtslab_status'; @@ -53,8 +54,9 @@ export class DeviceComponent extends MenuBaseClass implements OnInit { @ViewChild(FilterComponent) filterComponent: FilterComponent; constructor(private deviceService: DeviceService, - public snackBar: MatSnackBar) { - super(snackBar); + appService: AppService, + snackBar: MatSnackBar) { + super(appService, snackBar); } ngOnInit(): void { diff --git a/gae/frontend/src/app/menu/job/job.component.html b/gae/frontend/src/app/menu/job/job.component.html index 5151783..634402d 100644 --- a/gae/frontend/src/app/menu/job/job.component.html +++ b/gae/frontend/src/app/menu/job/job.component.html @@ -182,6 +182,9 @@ <ng-template #job_detail let-job> <div class="mat-row div-expandable" [@detailExpand] style="overflow: hidden"> <a href="{{job.infra_log_url}}" download><button mat-raised-button [disabled]="(!job.infra_log_url)">Download Infra Log</button></a> + <button mat-raised-button (click)="onShowDetailsClicked(job)"> + Show Details + </button> </div> </ng-template> <div class="loading-spinner" *ngIf="loading"> diff --git a/gae/frontend/src/app/menu/job/job.component.scss b/gae/frontend/src/app/menu/job/job.component.scss index 165de43..c8aee00 100644 --- a/gae/frontend/src/app/menu/job/job.component.scss +++ b/gae/frontend/src/app/menu/job/job.component.scss @@ -5,3 +5,20 @@ .mat-cell { padding: 0 10px 0 10px; } + +.element-row { + position: relative; + overflow: hidden; +} + +.element-row:not(.expanded) { + cursor: pointer; +} + +.element-row:not(.expanded):hover { + background: #f5f5f5; +} + +.element-row.expanded { + border-bottom-color: transparent; +} diff --git a/gae/frontend/src/app/menu/job/job.component.ts b/gae/frontend/src/app/menu/job/job.component.ts index 383ae19..4375581 100644 --- a/gae/frontend/src/app/menu/job/job.component.ts +++ b/gae/frontend/src/app/menu/job/job.component.ts @@ -17,6 +17,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { MatSnackBar, MatTableDataSource, PageEvent } from '@angular/material'; import { animate, state, style, transition, trigger } from '@angular/animations'; +import { AppService } from '../../appservice'; import { FilterComponent } from '../../shared/filter/filter.component'; import { FilterCondition } from '../../model/filter_condition'; import { FilterItem } from '../../model/filter_item'; @@ -84,8 +85,9 @@ export class JobComponent extends MenuBaseClass implements OnInit { sortDirection = ''; constructor(private jobService: JobService, - public snackBar: MatSnackBar) { - super(snackBar); + appService: AppService, + snackBar: MatSnackBar) { + super(appService, snackBar); } ngOnInit(): void { diff --git a/gae/frontend/src/app/menu/lab/lab.component.ts b/gae/frontend/src/app/menu/lab/lab.component.ts index 83fe3a1..bb7543b 100644 --- a/gae/frontend/src/app/menu/lab/lab.component.ts +++ b/gae/frontend/src/app/menu/lab/lab.component.ts @@ -16,6 +16,7 @@ import { Component, OnInit } from '@angular/core'; import { MatSnackBar, MatTableDataSource, PageEvent } from '@angular/material'; +import { AppService } from '../../appservice'; import { Host } from '../../model/host'; import { Lab } from '../../model/lab'; import { LabService } from './lab.service'; @@ -48,8 +49,9 @@ export class LabComponent extends MenuBaseClass implements OnInit { labPageIndex = 0; constructor(private labService: LabService, - public snackBar: MatSnackBar) { - super(snackBar); + appService: AppService, + snackBar: MatSnackBar) { + super(appService, snackBar); } labDataSource = new MatTableDataSource<Lab>(); diff --git a/gae/frontend/src/app/menu/menu_base.ts b/gae/frontend/src/app/menu/menu_base.ts index 316923e..9282fe5 100644 --- a/gae/frontend/src/app/menu/menu_base.ts +++ b/gae/frontend/src/app/menu/menu_base.ts @@ -17,6 +17,7 @@ /** This class defines and/or implements the common properties and methods * used among menus. */ +import { AppService } from '../appservice'; import { MatSnackBar } from '@angular/material'; import moment from 'moment-timezone'; @@ -29,7 +30,9 @@ export abstract class MenuBaseClass { pageSize = 100; pageIndex = 0; - protected constructor(public snackBar: MatSnackBar) { + protected constructor(private appService: AppService, + public snackBar: MatSnackBar) { + this.appService.closeSideNav(); this.snackBar.dismiss(); } @@ -58,4 +61,9 @@ export abstract class MenuBaseClass { this.loading = false; this.snackBar.open(message, 'DISMISS', {duration}); } + + /** Displays a side nav window and lists all properties of selected entity. */ + onShowDetailsClicked(entity) { + this.appService.showDetails(entity); + } } diff --git a/gae/frontend/src/app/menu/schedule/schedule.component.html b/gae/frontend/src/app/menu/schedule/schedule.component.html index c567639..e260325 100644 --- a/gae/frontend/src/app/menu/schedule/schedule.component.html +++ b/gae/frontend/src/app/menu/schedule/schedule.component.html @@ -102,6 +102,9 @@ <button mat-raised-button (click)="suspendSchedule([{urlsafe_key: schedule.urlsafe_key, suspend: !schedule.suspended}])"> {{(schedule.suspended ? "Resume" : "Suspend")}} </button> + <button mat-raised-button (click)="onShowDetailsClicked(schedule)"> + Show Details + </button> </div> </ng-template> <div class="loading-spinner" *ngIf="loading"> diff --git a/gae/frontend/src/app/menu/schedule/schedule.component.scss b/gae/frontend/src/app/menu/schedule/schedule.component.scss index a1e3e98..c8aee00 100644 --- a/gae/frontend/src/app/menu/schedule/schedule.component.scss +++ b/gae/frontend/src/app/menu/schedule/schedule.component.scss @@ -22,7 +22,3 @@ .element-row.expanded { border-bottom-color: transparent; } - -.div-expandable { - padding: 10px 20px 30px 20px; -} diff --git a/gae/frontend/src/app/menu/schedule/schedule.component.ts b/gae/frontend/src/app/menu/schedule/schedule.component.ts index 57ebd7b..6c72343 100644 --- a/gae/frontend/src/app/menu/schedule/schedule.component.ts +++ b/gae/frontend/src/app/menu/schedule/schedule.component.ts @@ -17,6 +17,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { MatSnackBar, MatTableDataSource, PageEvent } from '@angular/material'; import { animate, state, style, transition, trigger } from "@angular/animations"; +import { AppService } from '../../appservice'; import { FilterComponent } from '../../shared/filter/filter.component'; import { FilterItem } from '../../model/filter_item'; import { MenuBaseClass } from '../menu_base'; @@ -59,8 +60,9 @@ export class ScheduleComponent extends MenuBaseClass implements OnInit { @ViewChild(FilterComponent) filterComponent: FilterComponent; constructor(private scheduleService: ScheduleService, - public snackBar: MatSnackBar) { - super(snackBar); + appService: AppService, + snackBar: MatSnackBar) { + super(appService, snackBar); } ngOnInit(): void { diff --git a/gae/frontend/src/styles.scss b/gae/frontend/src/styles.scss index 7505757..574f294 100644 --- a/gae/frontend/src/styles.scss +++ b/gae/frontend/src/styles.scss @@ -46,5 +46,9 @@ body { } .div-expandable { - padding: 10px; + padding: 10px 20px 30px 20px; + + button { + margin-right: 20px; + } } |