blob: 44845ec3642de4a3c74eb6a228c2644cc6566a66 [file] [log] [blame]
<!--
Copyright 2019 Google LLC
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.
-->
<mat-spinner class="loading-spinner" color="accent" *ngIf="isLoading"></mat-spinner>
<mat-toolbar>
<mat-toolbar-row fxLayoutAlign="space-between center">
<h1>Test Runs</h1>
</mat-toolbar-row>
</mat-toolbar>
<div [class.loading-mask]="isLoading">
<div class="filter">
<!-- TODO Add column filtering -->
<mat-form-field fxFlex subscriptSizing="dynamic">
<mat-icon matPrefix class="filter-icon">filter_list</mat-icon>
<mat-label>Filter</mat-label>
<mat-chip-grid #chipList aria-label="Filter">
<mat-chip-row
*ngFor="let filter of filters"
(removed)="removeFilter(filter)">
{{ filter }}
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip-row>
<input
[matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="SEPARATOR_KEYCODES"
[matChipInputAddOnBlur]="true"
(matChipInputTokenEnd)="addFilter($event)"/>
</mat-chip-grid>
</mat-form-field>
<mat-divider vertical></mat-divider>
<mat-form-field fxFlex="300px" subscriptSizing="dynamic">
<mat-label>Status</mat-label>
<mat-select multiple [(ngModel)]="states"
(selectionChange)="resetPageTokenAndReload()">
<mat-option *ngFor="let state of TEST_RUN_STATES" [value]="state">
{{state | titlecase}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-divider vertical></mat-divider>
<button mat-icon-button class="view_columns_btn"
aria-label="View columns"
matTooltip="View columns"
[matMenuTriggerFor]="view_column_menu">
<mat-icon>view_column</mat-icon>
</button>
<mat-menu #view_column_menu="matMenu">
<ng-container *ngFor="let column of columns; let i=index">
<ng-container *ngIf="column.removable">
<button [attr.id]="column.fieldName + '_menu_btn'"
(click)="toggleDisplayColumn($event, column.show, i)" mat-menu-item>
<mat-icon>{{ column.show ? 'check_box' : 'check_box_outline_blank' }}</mat-icon>
<span class="menu-item">{{ column.displayName }}</span>
</button>
</ng-container>
</ng-container>
</mat-menu>
</div>
<div class="action-row">
<button
mat-stroked-button
class="delete-button"
color="accent"
(click)="deleteSelectedRows()"
[disabled]="this.selection.selected.length === 0"
>
Delete
</button>
</div>
<mat-table #table [dataSource]="dataSource" class="selectable"
(scroll)="checkTableScrolled()"
[class.scrolled]="isTableScrolled"
aria-label="Test run list">
<!-- Checkbox Column -->
<ng-container matColumnDef="select">
<mat-header-cell *matHeaderCellDef fxFlex="76px">
<mat-checkbox
(change)="$event ? toggleSelection() : null"
[checked]="isAllSelected()"
[indeterminate]="selection.selected.length > 0 && !isAllSelected()"
aria-label="Select all test runs"
class="select-all-checkbox"
>
</mat-checkbox>
</mat-header-cell>
<mat-cell *matCellDef="let row" fxFlex="76px">
<mat-checkbox
(click)="$event.stopPropagation()"
(change)="selection.toggle(row)"
[checked]="selection.isSelected(row)"
[disabled]="!isFinalTestRunState(row.state)"
>
</mat-checkbox>
</mat-cell>
</ng-container>
<!-- Test Name -->
<ng-container matColumnDef="test_name">
<mat-header-cell *matHeaderCellDef fxFlex class="test-name-column">Test</mat-header-cell>
<mat-cell *matCellDef="let testRun" fxFlex class="test-name-column">
{{testRun.test_name}}
</mat-cell>
</ng-container>
<!-- Test Package Version -->
<ng-container matColumnDef="test_package">
<mat-header-cell *matHeaderCellDef fxFlex="150px">Test Package</mat-header-cell>
<mat-cell *matCellDef="let testRun" fxFlex="150px">
{{testRun.test_package_info | testPackageInfo}}
</mat-cell>
</ng-container>
<!-- Device Specs -->
<ng-container matColumnDef="device_specs">
<mat-header-cell *matHeaderCellDef fxFlex="168px">Device Specs</mat-header-cell>
<mat-cell *matCellDef="let testRun" fxFlex="168px">
<overflow-list [data]="testRun.device_specs || []"
[overflowListType]="OverflowListType.BUTTON">
</overflow-list>
</mat-cell>
</ng-container>
<!-- Device Build -->
<ng-container matColumnDef="device_build">
<mat-header-cell *matHeaderCellDef fxFlex="182px">Device Build</mat-header-cell>
<mat-cell *matCellDef="let testRun" fxFlex="182px">
<overflow-list [data]="testRun.test_devices | mapListField: 'build_id'"
[overflowListType]="OverflowListType.BUTTON">
</overflow-list>
</mat-cell>
</ng-container>
<!-- Device Product -->
<ng-container matColumnDef="device_product">
<mat-header-cell *matHeaderCellDef fxFlex="128px">Product</mat-header-cell>
<mat-cell *matCellDef="let testRun" fxFlex="128px">
<overflow-list [data]="testRun.test_devices | mapListField: 'product'"
[overflowListType]="OverflowListType.BUTTON">
</overflow-list>
</mat-cell>
</ng-container>
<!-- Test Run Labels -->
<!-- TODO: add filtering -->
<ng-container matColumnDef="labels">
<mat-header-cell *matHeaderCellDef fxFlex="208px">Labels</mat-header-cell>
<mat-cell *matCellDef="let testRun" fxFlex="208px">
<overflow-list [data]="testRun.labels || []" [overflowListType]="OverflowListType.CHIP">
</overflow-list>
</mat-cell>
</ng-container>
<!-- Test Run Created Date -->
<ng-container matColumnDef="create_time">
<mat-header-cell *matHeaderCellDef fxFlex="120px">Created</mat-header-cell>
<mat-cell *matCellDef="let testRun" fxFlex="120px"
[title]="testRun.create_time | utc | date:'MM/dd/yyyy h:mma'">
{{testRun.create_time | utc | fromNow}}
</mat-cell>
</ng-container>
<!-- Test Run Status -->
<ng-container matColumnDef="status">
<mat-header-cell *matHeaderCellDef fxFlex="120px">Status</mat-header-cell>
<mat-cell *matCellDef="let testRun" fxFlex="120px">
<status-button [state]="testRun.state">
</status-button>
</mat-cell>
</ng-container>
<!-- Test Run Failures -->
<ng-container matColumnDef="failures">
<mat-header-cell *matHeaderCellDef fxFlex="150px">Test Failures</mat-header-cell>
<mat-cell *matCellDef="let testRun" fxFlex="150px">
<test-run-failures [state]="testRun.state"
[numFailedTests]="testRun.failed_test_count"
[numTotalTests]="testRun.total_test_count">
</test-run-failures>
</mat-cell>
</ng-container>
<!-- View Test Run Details Button -->
<ng-container matColumnDef="view" stickyEnd>
<mat-header-cell *matHeaderCellDef fxFlex="100px"></mat-header-cell>
<mat-cell *matCellDef="let testRun" fxFlex="100px">
<a
mat-stroked-button
color="accent"
[routerLink]="'/test_runs/' + testRun.id"
queryParamsHandling="merge"
>
View
</a>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayColumns;"></mat-row>
</mat-table>
<paginator
[pageSizeOptions]="PAGE_SIZE_OPTIONS"
(sizeChange)="resetPageTokenAndReload()"
(previous)="load(true)"
(next)="load(false)"
></paginator>
<div class="empty" *ngIf="!dataSource.data.length">
No test runs found.
</div>
</div>