dashboard: theme all remaining dialogs (replace native confirm/alert/prompt)
Follow-up to the themed-modal component: route every remaining native browser dialog through modal.js so nothing falls back to the OS chrome. - modal.js: add themedPrompt (input dialog) + themedToast (non-blocking transient notification, info/error/ok) alongside openDialog/themedConfirm. - Migrate call sites: bindAsyncForms confirm/prompt/alerts (common.js), the answer-validation alert (call.js), the M0V3 reparent confirm + action toasts (tabs.js), and the schedule form/cancel/fire confirms + validation and error alerts (schedules.js). - UX: blocking modal for confirms/prompts; non-blocking toast for transient errors + validation. Destructive confirms keep the danger styling. - CSS for the toast stack + prompt input. common.js <-> modal.js is a safe deferred import cycle (usage is call-time only); esbuild bundles it clean.
This commit is contained in:
parent
ff3317eb20
commit
7c2de690ec
6 changed files with 141 additions and 32 deletions
|
|
@ -4,6 +4,10 @@
|
|||
// infrastructure for the side panel.
|
||||
|
||||
import { linkify as termLinkify } from '@hive/shared/terminal.js';
|
||||
// Themed dialog/toast helpers (modal.js imports `el` back from here — a safe
|
||||
// deferred cycle: neither side uses the other at module-init time, only inside
|
||||
// runtime handlers).
|
||||
import { themedConfirm, themedPrompt, themedToast } from './modal.js';
|
||||
|
||||
// ─── helpers ────────────────────────────────────────────────────────────
|
||||
export const $ = (id) => document.getElementById(id);
|
||||
|
|
@ -58,9 +62,9 @@ export function bindAsyncForms(onSuccess) {
|
|||
const f = e.target;
|
||||
if (!(f instanceof HTMLFormElement) || !f.hasAttribute('data-async')) return;
|
||||
e.preventDefault();
|
||||
if (f.dataset.confirm && !confirm(f.dataset.confirm)) return;
|
||||
if (f.dataset.confirm && !(await themedConfirm({ message: f.dataset.confirm }))) return;
|
||||
if (f.dataset.prompt) {
|
||||
const ans = prompt(f.dataset.prompt, '');
|
||||
const ans = await themedPrompt({ message: f.dataset.prompt });
|
||||
if (ans === null) return; // operator hit Cancel
|
||||
// Drop into a hidden input named after `data-prompt-field` (or
|
||||
// 'note' by default) so the value rides along on the POST.
|
||||
|
|
@ -88,7 +92,7 @@ export function bindAsyncForms(onSuccess) {
|
|||
|| (resp.status >= 200 && resp.status < 400);
|
||||
if (!ok) {
|
||||
const text = await resp.text().catch(() => '');
|
||||
alert('action failed: ' + resp.status + (text ? '\n\n' + text : ''));
|
||||
themedToast('action failed: ' + resp.status + (text ? '\n\n' + text : ''), { type: 'error' });
|
||||
if (btn) { btn.disabled = false; btn.innerHTML = original; }
|
||||
return;
|
||||
}
|
||||
|
|
@ -101,7 +105,7 @@ export function bindAsyncForms(onSuccess) {
|
|||
onSuccess();
|
||||
}
|
||||
} catch (err) {
|
||||
alert('action failed: ' + err);
|
||||
themedToast('action failed: ' + err, { type: 'error' });
|
||||
if (btn) { btn.disabled = false; btn.innerHTML = original; }
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue