fix: ask before replacing a saved preset

Saving a character, object, or scene reused an existing name and
overwrote that preset without asking. Updating the preset already
linked to the region still saves directly.
This commit is contained in:
by-ae
2026-11-01 07:31:19 +10:00
parent 17858e1963
commit 479e0bb069
4 changed files with 61 additions and 5 deletions
+23 -4
View File
@@ -5,7 +5,7 @@ import {
} from "./utility.js";
import {
loadStores, saveStoreEntry, deleteStoreEntry, installBuilderQueueHooks, installBgUpdateListener,
normalizeStoreName,
normalizeStoreName, savedPresetCollision,
} from "./ideogram4_shared.js";
import {
captionText, cleanPalette, dimsFromAspect, elementToRegion, ideogramResolutionWarning,
@@ -1959,9 +1959,11 @@ app.registerExtension({
sceneSaveBtn.addEventListener("mousedown", (e) => e.stopPropagation());
sceneSaveBtn.addEventListener("click", () => {
showModal("Save Scene", [{ key: "name", label: "Scene name", placeholder: "my-scene" }], async (r) => {
const name = (r.name || "").trim();
const name = normalizeStoreName(r.name || "");
if (!name) return;
try {
const collision = savedPresetCollision(await existingPresetNames("scenes"), name);
if (collision && !confirm(`Replace saved scene "${collision}"? This cannot be undone.`)) return;
await saveStoreEntry("scenes", name, captureSceneState());
console.log("ByAE Ideogram: saved scene:", name);
} catch (e) {
@@ -2056,13 +2058,30 @@ app.registerExtension({
return ta;
}
async function existingPresetNames(bucket) {
try {
const stores = await loadStores();
return Object.keys(stores[bucket] || {});
} catch (e) {
console.warn("ByAE Ideogram: could not check existing presets before save", e);
return [];
}
}
async function persistBoxToStore(b, type, name) {
const bucket = type === "object" ? "objects" : "characters";
const safeName = normalizeStoreName(name);
if (!safeName) return;
const linked = b.storeRef && b.storeRef.type === type ? b.storeRef.name : "";
try {
const savedName = await saveStoreEntry(bucket, name, boxPayload(b));
if (normalizeStoreName(linked) !== safeName) {
const collision = savedPresetCollision(await existingPresetNames(bucket), safeName, linked);
if (collision && !confirm(`Replace saved ${type} "${collision}"? This cannot be undone.`)) return;
}
const savedName = await saveStoreEntry(bucket, safeName, boxPayload(b));
b.storeRef = { type, name: savedName };
commit();
console.log("ByAE Ideogram: saved", type, name);
console.log("ByAE Ideogram: saved", type, savedName);
} catch (e) {
console.error("ByAE Ideogram: failed to save:", e);
alert("Failed to save: " + e.message);
+13
View File
@@ -13,6 +13,19 @@ export function normalizeStoreName(name) {
return String(name ?? "").trim().normalize("NFC");
}
/**
* Stored name this save would replace, or null.
* Saving the preset already linked to the region is an update, not a replacement.
*/
export function savedPresetCollision(existingNames, name, linkedName) {
const target = normalizeStoreName(name);
if (!target) return null;
const match = (existingNames || []).find((entry) => normalizeStoreName(entry) === target);
if (!match) return null;
if (linkedName && normalizeStoreName(linkedName) === target) return null;
return match;
}
export async function loadStores() {
try {
const resp = await fetch(STORE_API, {