mirror of
https://github.com/simonw/datasette.git
synced 2026-09-19 15:04:06 +02:00
Refactor row deletion to use the shared modal, refs #2790
This commit is contained in:
parent
814165c8b1
commit
90f543327e
3 changed files with 12 additions and 134 deletions
|
|
@ -1224,46 +1224,11 @@ button.table-insert-row svg {
|
|||
}
|
||||
|
||||
dialog.row-delete-dialog {
|
||||
--ink: #0f0f0f;
|
||||
--paper: #eef6ff;
|
||||
--muted: #6b6b6b;
|
||||
--rule: #d8e6f5;
|
||||
--accent: #1a56db;
|
||||
--card: #ffffff;
|
||||
border: none;
|
||||
border-radius: var(--modal-border-radius, 0.75rem);
|
||||
padding: 0;
|
||||
margin: auto;
|
||||
width: min(440px, calc(100vw - 32px));
|
||||
max-width: 95vw;
|
||||
box-shadow: var(--modal-shadow, 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04));
|
||||
animation: datasette-modal-slide-in var(--modal-animation-duration, 0.2s) ease-out;
|
||||
overflow: hidden;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
background: var(--card);
|
||||
}
|
||||
|
||||
dialog.row-delete-dialog[open] {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
dialog.row-delete-dialog::backdrop {
|
||||
background: var(--modal-backdrop-bg, rgba(0, 0, 0, 0.5));
|
||||
backdrop-filter: var(--modal-backdrop-blur, blur(4px));
|
||||
-webkit-backdrop-filter: var(--modal-backdrop-blur, blur(4px));
|
||||
animation: datasette-modal-fade-in var(--modal-animation-duration, 0.2s) ease-out;
|
||||
}
|
||||
|
||||
.row-delete-dialog .modal-header {
|
||||
padding: 20px 24px 12px;
|
||||
border-bottom: 1px solid var(--rule);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 12px;
|
||||
flex-shrink: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.row-delete-dialog .modal-title {
|
||||
|
|
@ -1272,9 +1237,6 @@ dialog.row-delete-dialog::backdrop {
|
|||
gap: 0.35rem;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.row-delete-message,
|
||||
|
|
@ -1306,53 +1268,9 @@ dialog.row-delete-dialog::backdrop {
|
|||
|
||||
.row-delete-dialog .modal-footer {
|
||||
padding: 18px 20px 14px;
|
||||
border-top: 1px solid var(--rule);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
flex-shrink: 0;
|
||||
background: var(--paper);
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.row-delete-dialog .btn {
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
padding: 9px 20px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
touch-action: manipulation;
|
||||
font-family: inherit;
|
||||
transition: background 0.12s;
|
||||
}
|
||||
|
||||
.row-delete-dialog .btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
border: 1px solid var(--rule);
|
||||
}
|
||||
|
||||
.row-delete-dialog .btn-ghost:hover {
|
||||
background: var(--rule);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.row-delete-dialog .btn-primary {
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.row-delete-dialog .btn-primary:hover {
|
||||
background: #1949b8;
|
||||
}
|
||||
|
||||
.row-delete-dialog .btn:disabled {
|
||||
opacity: 0.65;
|
||||
cursor: wait;
|
||||
}
|
||||
|
||||
dialog.row-edit-dialog {
|
||||
--ink: #0f0f0f;
|
||||
--paper: #eef6ff;
|
||||
|
|
|
|||
|
|
@ -2410,6 +2410,7 @@ function initTableCreateActions(manager) {
|
|||
|
||||
function setRowDeleteDialogBusy(state, isBusy) {
|
||||
state.isBusy = isBusy;
|
||||
state.modal.busy = isBusy;
|
||||
state.confirmButton.disabled = isBusy;
|
||||
state.cancelButton.disabled = isBusy;
|
||||
state.confirmButton.textContent = isBusy ? "Deleting..." : "Delete row";
|
||||
|
|
@ -4360,7 +4361,8 @@ function ensureRowDeleteDialog(manager) {
|
|||
return null;
|
||||
}
|
||||
|
||||
var dialog = document.createElement("dialog");
|
||||
var modal = DatasetteModal.create();
|
||||
var dialog = modal.dialog;
|
||||
dialog.id = ROW_DELETE_DIALOG_ID;
|
||||
dialog.className = "row-delete-dialog";
|
||||
dialog.setAttribute("aria-labelledby", "row-delete-title");
|
||||
|
|
@ -4372,13 +4374,14 @@ function ensureRowDeleteDialog(manager) {
|
|||
<p class="row-delete-message" id="row-delete-message">Delete row <span class="row-delete-id"></span>?</p>
|
||||
<p class="row-delete-error" role="alert" hidden></p>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-ghost row-delete-cancel">Cancel</button>
|
||||
<button type="button" class="btn btn-primary row-delete-confirm">Delete row</button>
|
||||
<button type="button" class="modal-btn modal-btn-ghost row-delete-cancel">Cancel</button>
|
||||
<button type="button" class="modal-btn modal-btn-primary row-delete-confirm">Delete row</button>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(dialog);
|
||||
document.body.appendChild(modal);
|
||||
|
||||
rowDeleteDialogState = {
|
||||
modal: modal,
|
||||
dialog: dialog,
|
||||
title: dialog.querySelector(".modal-title"),
|
||||
message: dialog.querySelector(".row-delete-message"),
|
||||
|
|
@ -4391,21 +4394,10 @@ function ensureRowDeleteDialog(manager) {
|
|||
currentPkPath: null,
|
||||
manager: manager,
|
||||
isBusy: false,
|
||||
shouldRestoreFocus: true,
|
||||
};
|
||||
|
||||
rowDeleteDialogState.cancelButton.addEventListener("click", function () {
|
||||
if (!rowDeleteDialogState.isBusy) {
|
||||
rowDeleteDialogState.shouldRestoreFocus = true;
|
||||
dialog.close();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.addEventListener("click", function (ev) {
|
||||
if (ev.target === dialog && !rowDeleteDialogState.isBusy) {
|
||||
rowDeleteDialogState.shouldRestoreFocus = true;
|
||||
dialog.close();
|
||||
}
|
||||
modal.requestClose("cancel");
|
||||
});
|
||||
|
||||
dialog.addEventListener("keydown", function (ev) {
|
||||
|
|
@ -4417,25 +4409,6 @@ function ensureRowDeleteDialog(manager) {
|
|||
if (!rowDeleteDialogState.isBusy) {
|
||||
rowDeleteDialogState.confirmButton.click();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (ev.key !== "Escape") {
|
||||
return;
|
||||
}
|
||||
if (rowDeleteDialogState.isBusy) {
|
||||
ev.preventDefault();
|
||||
return;
|
||||
}
|
||||
ev.preventDefault();
|
||||
rowDeleteDialogState.shouldRestoreFocus = true;
|
||||
dialog.close();
|
||||
});
|
||||
|
||||
dialog.addEventListener("cancel", function (ev) {
|
||||
if (rowDeleteDialogState.isBusy) {
|
||||
ev.preventDefault();
|
||||
} else {
|
||||
rowDeleteDialogState.shouldRestoreFocus = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -4443,13 +4416,6 @@ function ensureRowDeleteDialog(manager) {
|
|||
var state = rowDeleteDialogState;
|
||||
clearRowDeleteDialogError(state);
|
||||
setRowDeleteDialogBusy(state, false);
|
||||
if (
|
||||
state.shouldRestoreFocus &&
|
||||
state.currentButton &&
|
||||
document.contains(state.currentButton)
|
||||
) {
|
||||
state.currentButton.focus();
|
||||
}
|
||||
});
|
||||
|
||||
rowDeleteDialogState.confirmButton.addEventListener(
|
||||
|
|
@ -4476,8 +4442,7 @@ function ensureRowDeleteDialog(manager) {
|
|||
throw rowMutationRequestError(response, data);
|
||||
}
|
||||
if (data && data.redirect) {
|
||||
state.shouldRestoreFocus = false;
|
||||
state.dialog.close();
|
||||
state.modal.close({ restoreFocus: false });
|
||||
location.href = data.redirect;
|
||||
return;
|
||||
}
|
||||
|
|
@ -4489,8 +4454,7 @@ function ensureRowDeleteDialog(manager) {
|
|||
var statusMessage = state.currentPkPath
|
||||
? "Deleted row " + state.currentPkPath + "."
|
||||
: "Deleted row.";
|
||||
state.shouldRestoreFocus = false;
|
||||
state.dialog.close();
|
||||
state.modal.close({ restoreFocus: false });
|
||||
state.currentRow.remove();
|
||||
showRowMutationStatus(state.manager, statusMessage, false);
|
||||
if (focusTarget && document.contains(focusTarget)) {
|
||||
|
|
@ -4519,11 +4483,9 @@ function openRowDeleteDialog(button, manager) {
|
|||
}
|
||||
|
||||
state.manager = manager;
|
||||
state.currentButton = button;
|
||||
state.currentRow = row;
|
||||
state.currentDeleteUrl = rowDeleteUrl(row);
|
||||
state.currentPkPath = rowDisplayLabel(row);
|
||||
state.shouldRestoreFocus = true;
|
||||
|
||||
clearRowDeleteDialogError(state);
|
||||
setRowDeleteDialogBusy(state, false);
|
||||
|
|
@ -4535,9 +4497,7 @@ function openRowDeleteDialog(button, manager) {
|
|||
);
|
||||
state.rowId.textContent = state.currentPkPath || "this row";
|
||||
|
||||
if (!state.dialog.open) {
|
||||
state.dialog.showModal();
|
||||
}
|
||||
state.modal.show({ trigger: button });
|
||||
state.confirmButton.focus();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1603,7 +1603,7 @@ def test_delete_row_flow_removes_row(page, datasette_server):
|
|||
dialog = page.locator("#row-delete-dialog")
|
||||
dialog.wait_for()
|
||||
assert "Delete row 1" in dialog.inner_text()
|
||||
dialog.locator(".row-delete-confirm").click()
|
||||
dialog.locator(".row-delete-confirm").press("Enter")
|
||||
|
||||
page.locator(".row-mutation-status", has_text="Deleted row 1").wait_for()
|
||||
page.locator('tr[data-row="1"]').wait_for(state="detached")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue