diff --git a/src/app/components/experiment-workspace-detail/experiment-workspace-detail.component.ts b/src/app/components/experiment-workspace-detail/experiment-workspace-detail.component.ts index 238e91d..3d11c31 100644 --- a/src/app/components/experiment-workspace-detail/experiment-workspace-detail.component.ts +++ b/src/app/components/experiment-workspace-detail/experiment-workspace-detail.component.ts @@ -203,7 +203,7 @@ export class ExperimentWorkspaceDetailComponent implements OnInit { } private async updateTemplateId(templateId: string | null) { - if (templateId == null) { + if (templateId == null || templateId === "") { return; // no template selected } if (templateId === this.templateId) { diff --git a/src/app/components/experiment/experiment.component.html b/src/app/components/experiment/experiment.component.html index 9487b82..8c0c5e5 100644 --- a/src/app/components/experiment/experiment.component.html +++ b/src/app/components/experiment/experiment.component.html @@ -32,11 +32,21 @@

Experiment

+ + Default Template + + + None + + + {{template.value}} + + + -
diff --git a/src/app/components/experiment/experiment.component.ts b/src/app/components/experiment/experiment.component.ts index c8803ca..eb2bc27 100644 --- a/src/app/components/experiment/experiment.component.ts +++ b/src/app/components/experiment/experiment.component.ts @@ -4,8 +4,11 @@ import { ActivatedRoute, Router } from '@angular/router'; import { BehaviorSubject, Subscription } from 'rxjs'; import { debounceTime, filter, map } from 'rxjs/operators'; import { ExportExperimentDialog } from 'src/app/dialogs/export-experiment/export-experiment.component'; +import { PageApiObject } from 'src/app/services/api-data-types'; import { CurrentExperimentService } from 'src/app/services/current-experiment.service'; import { ExperimentApiObject, QhanaBackendService } from 'src/app/services/qhana-backend.service'; +import { PluginRegistryBaseService } from 'src/app/services/registry.service'; +import { TemplatesService } from 'src/app/services/templates.service'; @Component({ selector: 'qhana-experiment', @@ -34,7 +37,10 @@ export class ExperimentComponent implements OnInit, OnDestroy { experimentDescription: string = ""; // only updated on initial experiment load currentExperimentDescription: string = ""; - constructor(private route: ActivatedRoute, private router: Router, private experimentService: CurrentExperimentService, private backend: QhanaBackendService, public dialog: MatDialog) { } + experimentTemplates: { [id: string]: string } = {}; + experimentTemplateId: string | number | null = null; + + constructor(private route: ActivatedRoute, private router: Router, private experimentService: CurrentExperimentService, private backend: QhanaBackendService, private registry: PluginRegistryBaseService, private templates: TemplatesService, public dialog: MatDialog) { } ngOnInit(): void { this.routeSubscription = this.route.params.pipe(map(params => params.experimentId)).subscribe(experimentId => { @@ -48,6 +54,7 @@ export class ExperimentComponent implements OnInit, OnDestroy { this.lastSavedDescription = experiment?.description ?? ""; this.experimentDescription = experiment?.description ?? ""; this.currentExperimentDescription = experiment?.description ?? ""; + this.experimentTemplateId = experiment?.templateId ?? null; }); this.autoSaveTitleSubscription = this.titleUpdates.pipe( filter(value => value != null && value !== this.lastSavedTitle), @@ -57,6 +64,15 @@ export class ExperimentComponent implements OnInit, OnDestroy { filter(value => value != null && value !== this.lastSavedDescription), debounceTime(500) ).subscribe(this.saveDescription); + this.registry.getByRel([["ui-template", "collection"]]).then(result => { + result?.data.items.forEach(item => { + const templateId = item.resourceKey?.uiTemplateId; + const name = item.name; + if (templateId != null && name != null) { + this.experimentTemplates[templateId] = name; + } + }); + }); } ngOnDestroy(): void { @@ -156,4 +172,12 @@ export class ExperimentComponent implements OnInit, OnDestroy { }); } + async changeDefaultTemplate(templateId: string | null) { + if (this.experimentId == null) { + return; + } + this.experimentTemplateId = templateId; + await this.templates.setDefaultTemplate(this.experimentId, templateId); + this.experimentService.reloadExperiment(); + } } diff --git a/src/app/services/current-experiment.service.ts b/src/app/services/current-experiment.service.ts index 4228a10..d73c4e0 100644 --- a/src/app/services/current-experiment.service.ts +++ b/src/app/services/current-experiment.service.ts @@ -64,7 +64,7 @@ export class CurrentExperimentService { this.currentExperimentId.next(experimentId); } const current = this.currentExperiment.getValue(); - if (current != experiment || current?.name !== experiment?.name || current?.description !== experiment?.description) { + if (current != experiment || current?.name !== experiment?.name || current?.description !== experiment?.description || current?.templateId !== experiment?.templateId) { this.currentExperiment.next(experiment); } } @@ -81,5 +81,4 @@ export class CurrentExperimentService { this.updateCurrentExperiment(experimentId); } } - } diff --git a/src/app/services/qhana-backend.service.ts b/src/app/services/qhana-backend.service.ts index 6d2e9f3..19baa25 100644 --- a/src/app/services/qhana-backend.service.ts +++ b/src/app/services/qhana-backend.service.ts @@ -177,6 +177,15 @@ export interface TimelineStepPageOptions { unclearedSubstep?: number; } +export interface TemplateApiObject extends ApiObject { + templateId: string; +} + +export interface TemplatePostResponseApiObject extends ApiObject { + experimentId: number; + templateId?: string; +} + function urlIsString(url: string | null): url is string { return url != null; } @@ -491,4 +500,16 @@ export class QhanaBackendService { rootUrl => this.http.get(`${rootUrl}/experiments/${experimentId}/timeline/${step}/substeps/${substep}`) ); } + + public getExperimentDefaultTemplate(experimentId: number | string): Observable { + return this.callWithRootUrl( + rootUrl => this.http.get(`${rootUrl}/experiments/${experimentId}/template`) + ); + } + + public updateExperimentDefaultTemplate(experimentId: number | string, templateId: string | number | null): Observable { + return this.callWithRootUrl( + rootUrl => this.http.post(`${rootUrl}/experiments/${experimentId}/template`, { templateId: templateId }) + ); + } } diff --git a/src/app/services/templates.service.ts b/src/app/services/templates.service.ts index fb27dfd..dfcb4ee 100644 --- a/src/app/services/templates.service.ts +++ b/src/app/services/templates.service.ts @@ -20,8 +20,9 @@ import { ApiLink, ApiObject, PageApiObject } from './api-data-types'; import { CurrentExperimentService } from './current-experiment.service'; import { PluginRegistryBaseService } from './registry.service'; import { EnvService } from './env.service'; -import { distinctUntilChanged } from 'rxjs/operators'; +import { distinctUntilChanged, take } from 'rxjs/operators'; import { ActivatedRoute } from '@angular/router'; +import { QhanaBackendService } from './qhana-backend.service'; export interface TemplateApiObject extends ApiObject { // TODO check fields @@ -104,7 +105,7 @@ export class TemplatesService { return this.currentTemplateSubject.asObservable(); } - constructor(private registry: PluginRegistryBaseService, private env: EnvService, private currentExperiment: CurrentExperimentService, private route: ActivatedRoute) { + constructor(private registry: PluginRegistryBaseService, private env: EnvService, private currentExperiment: CurrentExperimentService, private backend: QhanaBackendService, private route: ActivatedRoute) { this.envSubscription = env.uiTemplateId.subscribe((defaultTemplateId) => { this.envTemplateIdSubject.next(defaultTemplateId); }); @@ -200,7 +201,7 @@ export class TemplatesService { } private async updateTemplate(templateId: string | null, subject: BehaviorSubject) { - if (templateId == null) { + if (templateId == null || templateId === "") { subject.next(null); return; } @@ -231,4 +232,12 @@ export class TemplatesService { const templateResponse = await this.getTemplate(templateId, ignoreCache); return templateResponse?.data?.groups ?? []; } + + async setDefaultTemplate(experimentId: string, templateId: string | null) { + this.backend.updateExperimentDefaultTemplate(experimentId, templateId).pipe(take(1)).subscribe( + response => { + this.defaultTemplateIdSubject.next(response?.templateId ?? null); + } + ); + } }