refactor: extract shared utilities and standardize page patterns

- Add fmtBytes() and csvToArr() helpers to hoover/helpers.js
- Replace inline async patterns with ActionButton/ConfirmDelete in wireguard.js
- Convert addDomain/editDomain to QuickModal + apiSubmit in proxy.js
- Convert settingsModal handlers to formAction in certs.js
- Remove redundant synced handling from dhcp.js apply button
- Add onComplete callback to ConfirmDelete (fixes users.js onRefresh bug)
- Fix passkeys.js ActionCell/Table usage (invalid component API)
- Remove duplicate fmtBytes from dashboard.js
This commit is contained in:
2026-07-28 17:32:51 +00:00
parent 244576b8eb
commit 8bb3619ddc
10 changed files with 156 additions and 220 deletions
+19 -38
View File
@@ -92,47 +92,28 @@ function settingsModal(account) {
closeModal(idx);
});
inner.querySelector('[data-action="set-save"]')?.addEventListener('click', async () => {
if (isModalProcessing()) return;
setModalProcessing(true);
try {
inner.querySelector('[data-action="set-save"]')?.addEventListener('click',
formAction(async () => {
const email = ($val('set-email') || '').trim();
if (!email) { toast('Email is required', 'error'); return; }
const resp = await apiFetch('/api/certs/email', {
method: 'POST',
body: { email },
});
if (resp.ok) {
toast('Email updated', 'success');
closeModal(idx);
modelFetch('acme');
} else {
toast(resp.error || 'Failed', 'error');
}
} finally {
setModalProcessing(false);
refreshModals();
}
});
if (!email) throw 'Email is required';
const resp = await apiFetch('/api/certs/email', { method: 'POST', body: { email } });
if (!resp.ok) throw resp.error || 'Failed';
toast('Email updated', 'success');
closeModal(idx);
modelFetch('acme');
}),
);
inner.querySelector('[data-action="set-deactivate"]')?.addEventListener('click', async () => {
if (!confirm('Deactivate ACME account? You will need to register again to issue certificates.')) return;
if (isModalProcessing()) return;
setModalProcessing(true);
try {
inner.querySelector('[data-action="set-deactivate"]')?.addEventListener('click',
formAction(async () => {
if (!confirm('Deactivate ACME account? You will need to register again to issue certificates.')) throw new Error('Cancelled');
const resp = await apiFetch('/api/certs/account', { method: 'DELETE' });
if (resp.ok) {
toast('Account deactivated', 'success');
closeModal(idx);
modelFetch('acme');
} else {
toast(resp.error || 'Failed', 'error');
}
} finally {
setModalProcessing(false);
refreshModals();
}
});
if (!resp.ok) throw resp.error || 'Failed';
toast('Account deactivated', 'success');
closeModal(idx);
modelFetch('acme');
}),
);
});
}