From cdfd76634d633cf5124746a5f6f8a6b21a9bf97f Mon Sep 17 00:00:00 2001 From: Elena Zioga Date: Mon, 5 Sep 2022 12:44:27 +0300 Subject: [PATCH] frontend: Support paging/sorting/filtering in trials table (#1441) * Make trials table support paging, sorting and filtering. Signed-off-by: Elena Zioga --- .../experiment-details.module.ts | 2 + .../trials-table/trials-table.component.html | 74 ++--------- .../trials-table/trials-table.component.scss | 61 --------- .../trials-table/trials-table.component.ts | 122 +++++++++++++++--- .../trials-table/trials-table.module.ts | 9 +- 5 files changed, 122 insertions(+), 146 deletions(-) diff --git a/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/experiment-details.module.ts b/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/experiment-details.module.ts index fa92d6f0203..d8ef47256c4 100644 --- a/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/experiment-details.module.ts +++ b/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/experiment-details.module.ts @@ -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], @@ -33,6 +34,7 @@ import { TrialsGraphEchartsModule } from './trials-graph-echarts/trials-graph-ec ExperimentYamlModule, TitleActionsToolbarModule, TrialsGraphEchartsModule, + KubeflowModule, ], exports: [ExperimentDetailsComponent], }) diff --git a/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.component.html b/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.component.html index 74890613f74..013ba91a577 100644 --- a/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.component.html +++ b/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.component.html @@ -1,64 +1,10 @@ - - - - - - - - - - - - > - -
- {{ column === 'Kfp run' ? '' : column }} - - {{ element[i] }} - - - {{ element[i] }} - - -
- -
- - {{ element[i] }} -
+
+
+ +
+
diff --git a/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.component.scss b/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.component.scss index 3e21c31fa0f..348ef5e5367 100644 --- a/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.component.scss +++ b/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.component.scss @@ -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; - } -} diff --git a/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.component.ts b/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.component.ts index 03b9e228b66..1e1eb5fe8ec 100644 --- a/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.component.ts +++ b/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.component.ts @@ -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', @@ -38,41 +48,117 @@ export class TrialsTableComponent implements OnChanges { @Output() leaveMouseFromTrial = new EventEmitter(); - 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; } } diff --git a/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.module.ts b/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.module.ts index 19d3d7fc379..18432ca1985 100644 --- a/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.module.ts +++ b/pkg/new-ui/v1beta1/frontend/src/app/pages/experiment-details/trials-table/trials-table.module.ts @@ -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, @@ -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 {}