Add a reusable Dismissible helper that persists 'hide this permanently' state server-side in data/ui-state.json via the existing authenticated /read-file + /write-file endpoints. It's a direct file write — no task is created (nothing in the task manager) and no system scan runs — so it sidesteps the heavyweight config_update path entirely and works across browsers/devices. The backup config-backup warning now dismisses through Dismissible instead of localStorage; any future notice can opt in with Dismissible.isDismissed(id)/dismiss(id). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
68 lines
2.1 KiB
JavaScript
68 lines
2.1 KiB
JavaScript
// Dismissible — reusable "hide this UI element permanently" store.
|
|
//
|
|
// State is persisted server-side in data/ui-state.json via the authenticated
|
|
// /read-file + /write-file endpoints, so a dismissal follows the user across
|
|
// browsers and devices. It is a direct file read/write: no task is created
|
|
// (nothing appears in the task manager) and no system scan runs.
|
|
//
|
|
// Usage:
|
|
// await Dismissible.load(); // once, before reading state (e.g. in a page init)
|
|
// if (!Dismissible.isDismissed('my-id')) { ...render the thing... }
|
|
// Dismissible.dismiss('my-id'); // on close — persists, fire-and-forget
|
|
// Dismissible.restore('my-id'); // bring it back
|
|
window.Dismissible = (() => {
|
|
const FILE = 'ui-state.json';
|
|
let dismissed = new Set();
|
|
let loaded = false;
|
|
|
|
async function load() {
|
|
if (loaded) return;
|
|
try {
|
|
const res = await fetch(`/read-file?path=${encodeURIComponent(FILE)}`);
|
|
if (res.ok) {
|
|
const data = JSON.parse(await res.text());
|
|
if (Array.isArray(data?.dismissed)) dismissed = new Set(data.dismissed);
|
|
}
|
|
// A 404 just means nothing has been dismissed yet — leave the set empty.
|
|
} catch (_) {
|
|
// On any error, fail open: treat nothing as dismissed so notices still show.
|
|
}
|
|
loaded = true;
|
|
}
|
|
|
|
function isDismissed(id) {
|
|
return dismissed.has(id);
|
|
}
|
|
|
|
async function dismiss(id) {
|
|
await load();
|
|
if (dismissed.has(id)) return;
|
|
dismissed.add(id);
|
|
await persist();
|
|
}
|
|
|
|
async function restore(id) {
|
|
await load();
|
|
if (!dismissed.has(id)) return;
|
|
dismissed.delete(id);
|
|
await persist();
|
|
}
|
|
|
|
async function persist() {
|
|
try {
|
|
await fetch('/write-file', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
path: FILE,
|
|
content: JSON.stringify({ dismissed: [...dismissed] }, null, 2)
|
|
})
|
|
});
|
|
} catch (err) {
|
|
console.warn('Dismissible: failed to persist state', err);
|
|
}
|
|
}
|
|
|
|
return { load, isDismissed, dismiss, restore };
|
|
})();
|