Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/new-ui/v1beta1/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func main() {
http.HandleFunc("/katib/delete_experiment/", kuh.DeleteExperiment)

http.HandleFunc("/katib/fetch_experiment/", kuh.FetchExperiment)
http.HandleFunc("/katib/fetch_trial/", kuh.FetchTrial)
http.HandleFunc("/katib/fetch_suggestion/", kuh.FetchSuggestion)

http.HandleFunc("/katib/fetch_hp_job_info/", kuh.FetchHPJobInfo)
Expand Down
24 changes: 24 additions & 0 deletions pkg/new-ui/v1beta1/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,3 +397,27 @@ func (k *KatibUIHandler) FetchSuggestion(w http.ResponseWriter, r *http.Request)
return
}
}

// FetchTrial gets trial in specific namespace.
func (k *KatibUIHandler) FetchTrial(w http.ResponseWriter, r *http.Request) {
trialName := r.URL.Query()["trialName"][0]
namespace := r.URL.Query()["namespace"][0]

trial, err := k.katibClient.GetTrial(trialName, namespace)
if err != nil {
log.Printf("GetTrial failed: %v", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
response, err := json.Marshal(trial)
if err != nil {
log.Printf("Marshal Trial failed: %v", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if _, err = w.Write(response); err != nil {
log.Printf("Write trial failed: %v", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
5 changes: 5 additions & 0 deletions pkg/new-ui/v1beta1/frontend/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ import { Routes, RouterModule } from '@angular/router';
import { ExperimentsComponent } from './pages/experiments/experiments.component';
import { ExperimentDetailsComponent } from './pages/experiment-details/experiment-details.component';
import { ExperimentCreationComponent } from './pages/experiment-creation/experiment-creation.component';
import { TrialModalComponent } from './pages/experiment-details/trials-table/trial-modal/trial-modal.component';

const routes: Routes = [
{ path: '', component: ExperimentsComponent },
{ path: 'experiment/:experimentName', component: ExperimentDetailsComponent },
{ path: 'new', component: ExperimentCreationComponent },
{
path: 'experiment/:experimentName/trial/:trialName',
component: TrialModalComponent,
},
];

@NgModule({
Expand Down
2 changes: 2 additions & 0 deletions pkg/new-ui/v1beta1/frontend/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { AppComponent } from './app.component';
import { ExperimentsModule } from './pages/experiments/experiments.module';
import { ExperimentDetailsModule } from './pages/experiment-details/experiment-details.module';
import { ExperimentCreationModule } from './pages/experiment-creation/experiment-creation.module';
import { TrialModalModule } from './pages/experiment-details/trials-table/trial-modal/trial-modal.module';

@NgModule({
declarations: [AppComponent],
Expand All @@ -19,6 +20,7 @@ import { ExperimentCreationModule } from './pages/experiment-creation/experiment
ExperimentDetailsModule,
ReactiveFormsModule,
ExperimentCreationModule,
TrialModalModule,
],
providers: [],
bootstrap: [AppComponent],
Expand Down
84 changes: 84 additions & 0 deletions pkg/new-ui/v1beta1/frontend/src/app/models/trial.k8s.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { K8sObject } from 'kubeflow';
import { V1Container } from '@kubernetes/client-node';

/*
* K8s object definitions
*/
export const TRIAL_KIND = 'Trial';
export const TRIAL_APIVERSION = 'kubeflow.org/v1beta1';

export interface TrialK8s extends K8sObject {
spec?: TrialSpec;
status?: TrialStatus;
}

export interface TrialSpec {
metricsCollector: MetricsCollector;
objective: Objective;
parameterAssignments: { name: string; value: number }[];
primaryContainerName: string;
successCondition: string;
failureCondition: string;
runSpec: K8sObject;
}

export interface MetricsCollector {
collector?: CollectorSpec;
}

export interface CollectorSpec {
kind: CollectorKind;
customCollector: V1Container;
}

export type CollectorKind =
| 'StdOut'
| 'File'
| 'TensorFlowEvent'
| 'PrometheusMetric'
| 'Custom'
| 'None';

export interface Objective {
type: ObjectiveType;
goal: number;
objectiveMetricName: string;
additionalMetricNames: string[];
metricStrategies: MetricStrategy[];
}

export type ObjectiveType = 'maximize' | 'minimize';

export interface MetricStrategy {
name: string;
value: string;
}

export interface RunSpec {}

/*
* status
*/

interface TrialStatus {
startTime: string;
completionTime: string;
conditions: TrialStatusCondition[];
observation: {
metrics: {
name: string;
latest: string;
min: string;
max: string;
}[];
};
}

interface TrialStatusCondition {
type: string;
status: boolean;
reason: string;
message: string;
lastUpdateTime: string;
lastTransitionTime: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@
</ng-template>

<div class="tab-height-fix">
<mat-tab-group dynamicHeight animationDuration="0ms">
<mat-tab-group
dynamicHeight
animationDuration="0ms"
[(selectedIndex)]="selectedTab"
(selectedTabChange)="tabChanged($event)"
>
<mat-tab label="OVERVIEW">
<app-experiment-overview
[experimentName]="name"
Expand All @@ -45,6 +50,7 @@
(leaveMouseFromTrial)="mouseLeftTrial()"
(mouseOnTrial)="mouseOverTrial($event)"
[data]="details"
[experimentName]="name"
[displayedColumns]="columns"
[namespace]="namespace"
[bestTrialName]="bestTrialName"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { MatTabChangeEvent } from '@angular/material/tabs';
import {
ConfirmDialogService,
DIALOG_RESP,
Expand Down Expand Up @@ -35,6 +36,13 @@ export class ExperimentDetailsComponent implements OnInit, OnDestroy {
showGraph: boolean;
bestTrialName: string;
pageLoading = true;
selectedTab = 0;
tabs = new Map<string, number>([
['overview', 0],
['trials', 1],
['details', 2],
['yaml', 3],
]);

constructor(
private activatedRoute: ActivatedRoute,
Expand Down Expand Up @@ -62,6 +70,12 @@ export class ExperimentDetailsComponent implements OnInit, OnDestroy {
ngOnInit() {
this.name = this.activatedRoute.snapshot.params.experimentName;

if (this.activatedRoute.snapshot.queryParams['tab']) {
this.selectedTab = this.tabs.get(
this.activatedRoute.snapshot.queryParams['tab'],
);
}

this.subs.add(
this.namespaceService.getSelectedNamespace().subscribe(namespace => {
this.namespace = namespace;
Expand All @@ -70,6 +84,10 @@ export class ExperimentDetailsComponent implements OnInit, OnDestroy {
);
}

tabChanged(event: MatTabChangeEvent) {
this.selectedTab = event.index;
}

ngOnDestroy(): void {
this.subs.unsubscribe();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<lib-details-list-item key="Latest">
{{ latest }}
</lib-details-list-item>

<lib-details-list-item key="Minimum">
{{ min }}
</lib-details-list-item>

<lib-details-list-item key="Maximum">
{{ max }}
</lib-details-list-item>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { NgModule } from '@angular/core';
import { ConditionsTableModule, DetailsListModule } from 'kubeflow';
import { TrialModalMetricsComponent } from './metrics.component';

@NgModule({
declarations: [TrialModalMetricsComponent],
imports: [ConditionsTableModule, DetailsListModule],
exports: [TrialModalMetricsComponent],
})
export class TrialModalMetricsModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { TrialModalMetricsComponent } from './metrics.component';

describe('TrialModalMetricsComponent', () => {
let component: TrialModalMetricsComponent;
let fixture: ComponentFixture<TrialModalMetricsComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [TrialModalMetricsComponent],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(TrialModalMetricsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Component, Input } from '@angular/core';

@Component({
selector: 'app-metrics-overview',
templateUrl: './metrics.component.html',
})
export class TrialModalMetricsComponent {
@Input() name: string;
@Input() latest: string;
@Input() max: string;
@Input() min: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<div>
<lib-details-list-item key="Trial Name">
{{ trialName }}
</lib-details-list-item>

<lib-details-list-item key="Experiment Name">
{{ experimentName }}
</lib-details-list-item>

<lib-details-list-item key="Status" [icon]="statusIcon">
{{ status }}
</lib-details-list-item>

<lib-details-list-item key="Completion Time">
{{ completionTime }}
</lib-details-list-item>

<lib-details-list-item [chipsList]="performance" key="Performance">
</lib-details-list-item>

<ng-container *ngIf="trial.status.observation?.metrics">
<div
*ngFor="let metric of trial.status.observation?.metrics"
[style.margin-top]="'16px'"
>
<lib-heading-row heading="Metric:" subHeading="{{ metric.name }}">
</lib-heading-row>
<app-metrics-overview
[name]="metric.name"
[min]="metric.min"
[max]="metric.max"
[latest]="metric.latest"
></app-metrics-overview>
</div>
</ng-container>

<lib-conditions-table
*ngIf="trial"
[conditions]="trial.status.conditions"
title="Trial Conditions"
></lib-conditions-table>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { TrialModalOverviewComponent } from './trial-modal-overview.component';

describe('TrialModalOverviewComponent', () => {
let component: TrialModalOverviewComponent;
let fixture: ComponentFixture<TrialModalOverviewComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [TrialModalOverviewComponent],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(TrialModalOverviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Loading