From 2b9c25657a648225c5a69b9a193ecf6972f8dfb8 Mon Sep 17 00:00:00 2001 From: Vera Malieske Date: Fri, 18 Sep 2026 14:26:16 +0200 Subject: [PATCH] Fix V&A issue within create-new-entity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs here: the visibility step was disappearing mid-edit because it reacted to a flag that got flipped too early, and the embedded dialog was accidentally picking up data from its parent dialog instead of its own input. Fixed both — one now checks the initial state instead of the live one, the other gets an explicit "embedded" flag so it knows where to pull its data from. --- .../create-new-entity.component.html | 1 + .../create-new-entity.component.ts | 4 +- .../visibility-and-access-dialog.component.ts | 61 ++++++++++--------- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/src/app/dialogs/create-new-entity/create-new-entity.component.html b/src/app/dialogs/create-new-entity/create-new-entity.component.html index 7d3a3f3b..4b483c91 100644 --- a/src/app/dialogs/create-new-entity/create-new-entity.component.html +++ b/src/app/dialogs/create-new-entity/create-new-entity.component.html @@ -296,6 +296,7 @@

{{ 'Downloadable' | translate }}

@if (serverEntity(); as serverEntity) { diff --git a/src/app/dialogs/create-new-entity/create-new-entity.component.ts b/src/app/dialogs/create-new-entity/create-new-entity.component.ts index 3bca8536..9be04406 100644 --- a/src/app/dialogs/create-new-entity/create-new-entity.component.ts +++ b/src/app/dialogs/create-new-entity/create-new-entity.component.ts @@ -157,6 +157,7 @@ export class CreateNewEntityComponent implements AfterViewInit, OnInit, OnDestro readonly uploadedFiles = signal([]); readonly serverEntity = signal(undefined); readonly entitySettings = signal(undefined); + private initialEntityFinished = signal(false); viewerUrl = computed(() => { const entity = this.serverEntity(); @@ -419,6 +420,7 @@ export class CreateNewEntityComponent implements AfterViewInit, OnInit, OnDestro if (stepper) { stepper.steps.first.interacted = true; } + this.initialEntityFinished.set(!!this.dialogData.finished); } } @@ -478,7 +480,7 @@ export class CreateNewEntityComponent implements AfterViewInit, OnInit, OnDestro showVisibilityStep = computed(() => { const hasDialogData = !!this.dialogRef && !!this.dialogData; if (!hasDialogData) return true; - return !this.serverEntityFinished(); + return !this.initialEntityFinished(); }); public async uploadBaseEntity(stepper: MatStepper) { diff --git a/src/app/dialogs/visibility-and-access-dialog/visibility-and-access-dialog.component.ts b/src/app/dialogs/visibility-and-access-dialog/visibility-and-access-dialog.component.ts index 8800ae17..c19ffc85 100644 --- a/src/app/dialogs/visibility-and-access-dialog/visibility-and-access-dialog.component.ts +++ b/src/app/dialogs/visibility-and-access-dialog/visibility-and-access-dialog.component.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, Component, computed, inject, input, signal } from '@angular/core'; +import { AfterViewInit, Component, computed, effect, inject, input, signal } from '@angular/core'; import { AsyncPipe } from '@angular/common'; import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; @@ -62,25 +62,31 @@ export type ChangedVisibilitySettings = Pick); +export class VisibilityAndAccessDialogComponent { + private dialogRef = inject(MatDialogRef, { + optional: true, + }); private backend = inject(BackendService); private account = inject(AccountService); private helper = inject(DialogHelperService); private permission = inject(PermissionService); + public embedded = input(false); + // If the dialog is used as part of the upload process, we recieve input data instead of mat dialog data. public inputData = input(); - public dialogData = inject(MAT_DIALOG_DATA); - public element = computed(() => this.inputData() ?? this.dialogData); + public dialogData = inject(MAT_DIALOG_DATA, { + optional: true, + }); + public element = computed(() => (this.embedded() ? this.inputData() : this.dialogData)); public elementType = computed(() => { const element = this.element()?.at(0); if (!element) return undefined; return isEntity(element) ? 'entity' : isCompilation(element) ? 'compilation' : undefined; }); - public componentType = computed(() => (this.inputData() ? 'component' : 'dialog')); + public componentType = computed(() => (this.embedded() ? 'component' : 'dialog')); - public data = signal(structuredClone(this.element())); + public data = signal(undefined); public isMulti = computed(() => { const data = this.data(); return data && data.length > 1; @@ -230,32 +236,33 @@ export class VisibilityAndAccessDialogComponent implements AfterViewInit { ), ); - public published = signal( - (() => { - const data = this.data(); - if (!data) return false; - return data.every(el => !!el.online); - })(), - ); + public published = signal(false); + public download = signal(false); public async togglePublished(checked: boolean) { if (!this.data) return; this.published.set(checked); } - public download = signal( - (() => { - const data = this.data(); - if (!data) return false; - return data.every(el => (isEntity(el) ? el.options?.allowDownload : false)); - })(), - ); - public async toggleDownload(checked: boolean) { if (!this.data) return; this.download.set(checked); } + constructor() { + effect( + () => { + const element = this.element(); + if (!element) return; + const cloned = structuredClone(element); + this.data.set(cloned); + this.published.set(cloned.every(el => !!el.online)); + this.download.set(cloned.every(el => (isEntity(el) ? el.options?.allowDownload : false))); + }, + { allowSignalWrites: true }, + ); + } + public userSelected(event: MatAutocompleteSelectedEvent) { const newUser = event.option.value; @@ -331,7 +338,7 @@ export class VisibilityAndAccessDialogComponent implements AfterViewInit { } public cancel() { - this.dialogRef.close(false); + this.dialogRef?.close(false); } public async save() { @@ -379,15 +386,9 @@ export class VisibilityAndAccessDialogComponent implements AfterViewInit { ); await Promise.all(savePromises); - this.dialogRef.close(data); + this.dialogRef?.close(data); } catch (error) { console.error('Entity could not be saved: ', error); } } - - ngAfterViewInit(): void { - // If we open the component without dialogdata, input is sometimes not available until the component is fully initialized. - // This is a workaround to ensure that the data is set correctly. - if (!this.data()) this.data.set(structuredClone(this.element())); - } }