From b1983dec5626c0a8d1121dff2bf846e586190537 Mon Sep 17 00:00:00 2001 From: librelad Date: Sat, 23 May 2026 00:25:15 +0100 Subject: [PATCH] feat(webui): server-side dismissible UI notices (Dismissible helper) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: librelad --- containers/libreportal/frontend/index.html | 1 + .../js/components/backup/backup-page.js | 11 +-- .../frontend/js/utils/dismissible.js | 67 +++++++++++++++++++ 3 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 containers/libreportal/frontend/js/utils/dismissible.js diff --git a/containers/libreportal/frontend/index.html b/containers/libreportal/frontend/index.html index 6113cf0..65172ac 100755 --- a/containers/libreportal/frontend/index.html +++ b/containers/libreportal/frontend/index.html @@ -86,6 +86,7 @@ + diff --git a/containers/libreportal/frontend/js/components/backup/backup-page.js b/containers/libreportal/frontend/js/components/backup/backup-page.js index 7eff02b..7e89d6b 100644 --- a/containers/libreportal/frontend/js/components/backup/backup-page.js +++ b/containers/libreportal/frontend/js/components/backup/backup-page.js @@ -94,6 +94,7 @@ class BackupPage { this.applyActiveTabUi(this.currentTab); this.bindEvents(); await this.refreshAll(); + await window.Dismissible?.load(); this.render(); this.updatePageHeader(); this.updatePrimaryAction(); @@ -213,7 +214,7 @@ class BackupPage { const dismissWarn = e.target.closest('[data-action="dismiss-config-warning"]'); if (dismissWarn) { - localStorage.setItem('libreportal:backup-config-warning-dismissed', '1'); + window.Dismissible?.dismiss('backup-config-warning'); const banner = dismissWarn.closest('.backup-warning-banner'); const divider = banner?.nextElementSibling; if (divider && divider.classList.contains('config-divider')) divider.remove(); @@ -830,10 +831,10 @@ class BackupPage { const body = document.getElementById('backup-configuration-body'); if (!body) return; - // The warning is a dismissible nudge, so its dismissed state lives in - // localStorage (per-browser) rather than server config. Banner + its - // divider are omitted entirely once dismissed. - const warningDismissed = localStorage.getItem('libreportal:backup-config-warning-dismissed') === '1'; + // Dismissed state is persisted server-side via Dismissible + // (data/ui-state.json), so it follows the user across browsers/devices. + // Banner + its divider are omitted entirely once dismissed. + const warningDismissed = !!window.Dismissible?.isDismissed('backup-config-warning'); const warningHTML = warningDismissed ? '' : `