Make plan deletion visible and reliable with in-page confirmation
Test and deploy / test-and-deploy (push) Successful in 1m28s

This commit is contained in:
snowspeeder committed 2026-09-07 06:22:43 -04:00
1 parent f2abdcefe1
commit a72aec9f86
4 files changed
+100 -8

No files matched your search

+40 -8
View File
@@ -18,6 +18,41 @@ function node(tag, text, className = "") {
el.className = className;
return el;
}
const deleteDialog = document.getElementById("delete-plan-dialog"),
deleteName = document.getElementById("delete-plan-name"),
deleteError = document.getElementById("delete-plan-error"),
deleteConfirm = document.getElementById("delete-plan-confirm"),
deleteCancel = document.getElementById("delete-plan-cancel");
let pendingDelete = null, deleting = false;
deleteCancel.onclick = () => deleteDialog.close();
deleteDialog.addEventListener("cancel", (event) => {
if (deleting) event.preventDefault();
});
deleteDialog.addEventListener("close", () => { pendingDelete = null; });
deleteConfirm.onclick = async () => {
if (!pendingDelete || deleting) return;
deleting = true;
deleteConfirm.disabled = deleteCancel.disabled = true;
deleteConfirm.textContent = "Deleting…";
deleteError.textContent = "";
try {
try {
await api("/api/plans/" + pendingDelete.id, { method: "DELETE" });
} catch (error) {
// Another tab may already have removed this plan.
if (error.status !== 404) throw error;
}
deleteDialog.close();
await load();
showToast("Plan deleted.");
} catch (error) {
deleteError.textContent = "Could not delete this plan. " + error.message + " Try again.";
} finally {
deleting = false;
deleteConfirm.disabled = deleteCancel.disabled = false;
deleteConfirm.textContent = "Delete plan";
}
};
async function load() {
const current = ++generation;
const params = new URLSearchParams(new FormData(form));
@@ -92,14 +127,11 @@ async function load() {
const remove = node("button", "Delete", "ghost-btn small");
remove.type = "button";
remove.setAttribute("aria-label", "Delete " + plan.title);
remove.onclick = async () => {
if (!confirm(`Delete “${plan.title}”?`)) return;
try {
await api("/api/plans/" + plan.id, { method: "DELETE" });
await load();
} catch (e) {
showToast(e.message, "fail");
}
remove.onclick = () => {
pendingDelete = plan;
deleteName.textContent = plan.title;
deleteError.textContent = "";
deleteDialog.showModal();
};
actions.append(clone, rename, remove);
tr.append(actions);