From 769f302ea8f17e9d30104235cf9411a02394daf1 Mon Sep 17 00:00:00 2001 From: llama <100429699+iamllama@users.noreply.github.com> Date: Tue, 7 Jan 2025 22:41:52 +0800 Subject: [PATCH] Fix "discard changes" appearing on deck options (#3689) * patch original config after a preset is selected for the first time * update comment --- ts/routes/deck-options/lib.ts | 39 +++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/ts/routes/deck-options/lib.ts b/ts/routes/deck-options/lib.ts index a7295ddf6..da471e027 100644 --- a/ts/routes/deck-options/lib.ts +++ b/ts/routes/deck-options/lib.ts @@ -76,6 +76,10 @@ export class DeckOptionsState { private removedConfigs: DeckOptionsId[] = []; private schemaModified: boolean; private _presetAssignmentsChanged = false; + // tracks presets that have already been + // selected/loaded once, via their ids. + // needed for proper change detection + private loadedPresets: Set = new Set(); constructor(targetDeckId: DeckOptionsId, data: DeckConfigsForUpdate) { this.targetDeckId = targetDeckId; @@ -122,17 +126,46 @@ export class DeckOptionsState { this.currentConfig.subscribe((val) => this.onCurrentConfigChanged(val)); this.currentAuxData.subscribe((val) => this.onCurrentAuxDataChanged(val)); + // no need to call markCurrentPresetAsLoaded here + // since any changes components make will be before + // originalConfigsResolve is called on mount + this.loadedPresets.add(this.configs[this.selectedIdx].config.id); + // Must be resolved after all components are mounted, as some components // may modify the config during their initialization. [this.originalConfigsPromise, this.originalConfigsResolve] = promiseWithResolver(); } + /** + * Patch the original config if components change it after preset select + * `EasyDays` and `DateInput` both do this when their settings are blank + * We only need to patch when the preset is first selected. + */ + async markCurrentPresetAsLoaded(): Promise { + const id = this.configs[this.selectedIdx].config.id; + const loaded = this.loadedPresets; + // ignore new presets with an id of 0 + if (id && !loaded.has(id)) { + // preset was loaded for the first time, patch original config + loaded.add(id); + const original = await this.originalConfigsPromise; + // can't index into `original` with `this.selectedIdx` due to `sortConfigs` + const idx = original.configs.findIndex((conf) => conf.id === id); + // this should never be -1, since new presets are excluded, and removed presets aren't considered + if (idx !== -1) { + original.configs[idx] = cloneDeep(this.configs[this.selectedIdx].config); + } + } + } + setCurrentIndex(index: number): void { this.selectedIdx = index; this._presetAssignmentsChanged = true; this.updateCurrentConfig(); // use counts have changed this.updateConfigList(); + // wait for components that modify config on preset select + tick().then(() => this.markCurrentPresetAsLoaded()); } getCurrentName(): string { @@ -203,10 +236,8 @@ export class DeckOptionsState { this.schemaModified = true; } this.configs.splice(this.selectedIdx, 1); - this.selectedIdx = Math.max(0, this.selectedIdx - 1); - this._presetAssignmentsChanged = true; - this.updateCurrentConfig(); - this.updateConfigList(); + const newIdx = Math.max(0, this.selectedIdx - 1); + this.setCurrentIndex(newIdx); } dataForSaving(