Skip to content

Commit

Permalink
frontend: Support paging/sorting/filtering in trials table (kubeflow#…
Browse files Browse the repository at this point in the history
…1441)

* Make trials table support paging, sorting and filtering.

Signed-off-by: Elena Zioga <[email protected]>
  • Loading branch information
elenzio9 committed Nov 25, 2022
1 parent 1b3c159 commit cdfd766
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 146 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ExperimentOverviewModule } from './overview/experiment-overview.module'
import { ExperimentDetailsTabModule } from './details/experiment-details-tab.module';
import { ExperimentYamlModule } from './yaml/experiment-yaml.module';
import { TrialsGraphEchartsModule } from './trials-graph-echarts/trials-graph-echarts.module';
import { KubeflowModule } from 'kubeflow';

@NgModule({
declarations: [ExperimentDetailsComponent],
Expand All @@ -33,6 +34,7 @@ import { TrialsGraphEchartsModule } from './trials-graph-echarts/trials-graph-ec
ExperimentYamlModule,
TitleActionsToolbarModule,
TrialsGraphEchartsModule,
KubeflowModule,
],
exports: [ExperimentDetailsComponent],
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,64 +1,10 @@
<table [dataSource]="data" class="wide" mat-table>
<!--- Note that these columns can be defined in any order.
The actual rendered columns are set as a property on the row definition" -->

<!-- Position Column -->
<ng-container
*ngFor="let column of displayedColumns; let i = index"
[matColumnDef]="column"
>
<th mat-header-cell *matHeaderCellDef>
{{ column === 'Kfp run' ? '' : column }}
</th>
<td
*matCellDef="let element"
[ngClass]="{ cell: column === 'Trial name' }"
mat-cell
>
<span
*ngIf="
column !== 'Trial name' && column !== 'Status' && column !== 'Kfp run'
"
>{{ element[i] }}
</span>

<span
(click)="openTrialModal(element[i])"
*ngIf="column === 'Trial name'"
class="name"
>{{ element[i] }}
</span>

<div *ngIf="column === 'Kfp run'" class="svg-color">
<mat-icon
(click)="goToKfpRun(element[i])"
[matTooltipDisabled]="!!element[i]"
[ngClass]="{ 'icon-disable': !element[i] }"
class="icon"
matTooltip="No KFP run"
svgIcon="pipeline-centered"
></mat-icon>
</div>

<span
*ngIf="column === 'Status'"
[ngClass]="{
green: element[i] === 'Succeeded',
red: element[i] === 'Failed'
}"
>{{ element[i] }}</span
>
</td>
</ng-container>

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr
(mouseleave)="handleMouseLeave()"
(mouseover)="handleMouseOver(row)"
*matRowDef="let row; let i = index; columns: displayedColumns"
[ngClass]="{ 'best-trail-row': bestTrialIndex === i }"
mat-row
>
>
</tr>
</table>
<div class="lib-content-wrapper">
<div class="page-padding lib-flex-grow lib-overflow-auto">
<lib-table
[config]="config"
[data]="processedData"
[highlightedRow]="bestTrialRow"
(actionsEmitter)="reactToAction($event)"
></lib-table>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,3 @@
display: block;
min-height: 550px;
}

.cell {
width: 300px;
}

.name {
cursor: pointer;

&:hover {
color: #1e88e5;
text-decoration: underline;
}
}

.green {
color: green;
}

.red {
color: red;
}

.icon {
cursor: pointer;

&-disable {
cursor: default;
opacity: 0.5;
}
}

td.mat-cell:not(:first-of-type) {
padding: 2px 28px 2px 0;
}

td.mat-cell:first-of-type {
padding: 2px 28px 2px 24px;
}

.mat-row:hover {
background-color: #f3f3f3;
}

.svg-color {
color: #1e88e5;
display: flex;
justify-content: flex-end;
margin-right: 16px;
}

::ng-deep :host svg {
fill: currentColor;
}

.best-trail-row {
background-color: #ffffcd;

&:hover {
background-color: #ffff98;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@ import {
SimpleChanges,
} from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { TrialModalComponent } from './trial-modal/trial-modal.component';
import {
PropertyValue,
StatusValue,
ComponentValue,
TableConfig,
ActionEvent,
} from 'kubeflow';
import { parseStatus } from '../../experiments/utils';
import lowerCase from 'lodash-es/lowerCase';
import { KfpRunComponent } from './kfp-run/kfp-run.component';

@Component({
selector: 'app-trials-table',
Expand Down Expand Up @@ -38,41 +48,117 @@ export class TrialsTableComponent implements OnChanges {
@Output()
leaveMouseFromTrial = new EventEmitter<void>();

bestTrialIndex: number;
bestTrialRow: {};

config: TableConfig = { columns: [] };

constructor(public dialog: MatDialog, private router: Router) {}
processedData = [];

constructor(public dialog: MatDialog) {}

ngOnChanges(changes: SimpleChanges): void {
if (changes.displayedColumns) {
if (changes.displayedColumns && this.displayedColumns.length !== 0) {
this.displayedColumns = this.displayedColumns.slice(
0,
this.displayedColumns.length,
);
this.processedData = this.setData(this.data, this.displayedColumns);
this.config = this.setConfig(this.displayedColumns, this.processedData);
}

if (this.data.length > 0 && this.bestTrialName) {
this.bestTrialIndex = this.data.findIndex(
trial => trial[0] === this.bestTrialName,
);
this.bestTrialRow = this.processedData.find(obj => {
return obj['trial name'] === this.bestTrialName;
});
}
}

openTrialModal(name: string) {
this.router.navigate([`/experiment/${this.experimentName}/trial/${name}`]);
setData(data: any, displayedColumns: any) {
const processedData = [];
for (var i = 0; i < data.length; i++) {
var list = data[i];
processedData[i] = {};

for (var j = 0; j < displayedColumns.length; j++) {
var key = lowerCase(displayedColumns[j]);
var value = list[j];
processedData[i][key] = value;
}
}

return processedData;
}

handleMouseLeave = () => this.leaveMouseFromTrial.emit();
setConfig(displayedColumns: any, processedData: any) {
const columns = [];
for (var i = 0; i < displayedColumns.length; i++) {
if (displayedColumns[i] !== 'Kfp run') {
if (displayedColumns[i] === 'Trial name') {
columns.push({
matHeaderCellDef: displayedColumns[i],
matColumnDef: 'name',
value: new PropertyValue({
field: lowerCase(displayedColumns[i]),
isLink: true,
}),
sort: true,
});
} else if (displayedColumns[i] === 'Status') {
columns.push({
matHeaderCellDef: displayedColumns[i],
matColumnDef: displayedColumns[i],
value: new StatusValue({
valueFn: parseStatus,
}),
sort: true,
});
} else {
columns.push({
matHeaderCellDef: displayedColumns[i],
matColumnDef: displayedColumns[i],
value: new PropertyValue({
field: lowerCase(displayedColumns[i]),
}),
sort: true,
});
}
}
}

handleMouseOver = event => this.mouseOnTrial.emit(+event[event.length - 1]);
let kfpRunExists = false;
for (var i = 0; i < processedData.length; i++) {
if (processedData[i]['kfp run']) {
kfpRunExists = true;
}
}

goToKfpRun(kfpRun: string) {
// If the trial does not have a kfp run then do not redirect
if (!kfpRun) {
return;
if (kfpRunExists) {
columns.push({
matHeaderCellDef: '',
matColumnDef: 'actions',
value: new ComponentValue({
component: KfpRunComponent,
}),
});
}

this.router.navigate([]).then(() => {
window.open(`/pipeline/#/runs/details/${kfpRun}`);
});
return {
columns,
};
}

// Event handling functions
reactToAction(a: ActionEvent) {
switch (a.action) {
case 'name:link':
this.openTrialModal(a.data['trial name']);
break;
}
}

openTrialModal(name: string) {
const modalRef = this.dialog.open(TrialModalComponent, {});
modalRef.componentInstance.trialName = name;
modalRef.componentInstance.namespace = this.namespace;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';

import { TrialsTableComponent } from './trials-table.component';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TrialModalComponent } from './trial-modal/trial-modal.component';
import { MatButtonModule } from '@angular/material/button';
import { KubeflowModule } from 'kubeflow';
import { KfpRunComponent } from './kfp-run/kfp-run.component';
import { TrialModalModule } from './trial-modal/trial-modal.module';

@NgModule({
declarations: [TrialsTableComponent],
declarations: [TrialsTableComponent, KfpRunComponent],
imports: [
CommonModule,
MatTableModule,
Expand All @@ -21,9 +23,10 @@ import { TrialModalModule } from './trial-modal/trial-modal.module';
MatIconModule,
NgxChartsModule,
MatTooltipModule,
MatButtonModule,
KubeflowModule,
TrialModalModule,
],
entryComponents: [TrialModalComponent],
exports: [TrialsTableComponent],
})
export class TrialsTableModule {}

0 comments on commit cdfd766

Please sign in to comment.