mirror of
https://github.com/simonw/datasette.git
synced 2026-06-23 01:04:49 +02:00
Drop table button in alter dialog
This commit is contained in:
parent
e834008075
commit
354780a136
4 changed files with 111 additions and 1 deletions
|
|
@ -2542,6 +2542,22 @@ dialog.table-alter-dialog::backdrop {
|
|||
color: var(--ink);
|
||||
}
|
||||
|
||||
.table-alter-dialog .btn-danger {
|
||||
background: #b91c1c;
|
||||
color: #fff;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.table-alter-dialog .btn-danger:hover {
|
||||
background: #991b1b;
|
||||
}
|
||||
|
||||
.table-alter-dialog .btn-danger:disabled,
|
||||
.table-alter-dialog .btn-danger:disabled:hover {
|
||||
background: #d98c8c;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.table-alter-dialog .btn-primary {
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
|
|
|
|||
|
|
@ -1571,6 +1571,7 @@ function setTableAlterDialogSaving(state, isSaving) {
|
|||
state.cancelButton.disabled = isSaving;
|
||||
state.addColumnButton.disabled = isSaving;
|
||||
state.backButton.disabled = isSaving;
|
||||
state.dropButton.disabled = isSaving;
|
||||
state.saveButton.textContent = isSaving
|
||||
? state.mode === "review"
|
||||
? "Applying..."
|
||||
|
|
@ -2465,6 +2466,8 @@ function showTableAlterEditor(state) {
|
|||
state.review.hidden = true;
|
||||
state.review.textContent = "";
|
||||
state.backButton.hidden = true;
|
||||
var data = tableAlterData();
|
||||
state.dropButton.hidden = !(data && data.dropPath);
|
||||
state.saveButton.textContent = tableAlterSaveButtonText(state);
|
||||
updateTableAlterMoveButtons(state);
|
||||
updateTableAlterSaveButtonState(state);
|
||||
|
|
@ -2479,6 +2482,7 @@ function showTableAlterReview(state, result) {
|
|||
state.review.hidden = false;
|
||||
state.review.textContent = "";
|
||||
state.backButton.hidden = false;
|
||||
state.dropButton.hidden = true;
|
||||
state.saveButton.textContent = tableAlterSaveButtonText(state);
|
||||
updateTableAlterSaveButtonState(state);
|
||||
|
||||
|
|
@ -2565,6 +2569,64 @@ async function applyTableAlterChanges(state, result) {
|
|||
}
|
||||
}
|
||||
|
||||
function tableAlterDatabaseUrl() {
|
||||
var data = tableAlterData();
|
||||
if (!data || !data.path) {
|
||||
return null;
|
||||
}
|
||||
var url = new URL(data.path, location.href);
|
||||
url.pathname = url.pathname.replace(/\/[^/]+\/-\/alter\/?$/, "");
|
||||
url.search = "";
|
||||
url.hash = "";
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
async function dropTableFromAlterDialog(state) {
|
||||
if (state.isSaving) {
|
||||
return;
|
||||
}
|
||||
var data = tableAlterData();
|
||||
if (!data || !data.dropPath) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!window.confirm(
|
||||
'Permanently delete the table "' +
|
||||
data.tableName +
|
||||
'"? This will delete all of its data and cannot be undone.',
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
clearTableAlterDialogError(state);
|
||||
setTableAlterDialogSaving(state, true);
|
||||
try {
|
||||
var response = await fetch(data.dropPath, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify({ confirm: true }),
|
||||
});
|
||||
var responseData = null;
|
||||
try {
|
||||
responseData = await response.json();
|
||||
} catch (_error) {
|
||||
responseData = null;
|
||||
}
|
||||
if (!response.ok || (responseData && responseData.ok === false)) {
|
||||
throw rowMutationRequestError(response, responseData);
|
||||
}
|
||||
state.shouldRestoreFocus = false;
|
||||
state.dialog.close();
|
||||
window.location.href = tableAlterDatabaseUrl() || "/";
|
||||
} catch (error) {
|
||||
setTableAlterDialogSaving(state, false);
|
||||
showTableAlterDialogError(state, error.message || "Could not drop table");
|
||||
}
|
||||
}
|
||||
|
||||
async function saveTableAlterDialog(state) {
|
||||
if (state.isSaving) {
|
||||
return;
|
||||
|
|
@ -2646,6 +2708,7 @@ function ensureTableAlterDialog(manager) {
|
|||
</div>
|
||||
<div class="table-alter-review" hidden></div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-danger table-alter-drop" hidden>Drop table</button>
|
||||
<button type="button" class="btn btn-ghost table-alter-back" hidden>Back</button>
|
||||
<button type="button" class="btn btn-ghost table-alter-cancel">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary table-alter-save">Review changes</button>
|
||||
|
|
@ -2664,6 +2727,7 @@ function ensureTableAlterDialog(manager) {
|
|||
columnList: dialog.querySelector(".table-alter-column-list"),
|
||||
addColumnButton: dialog.querySelector(".table-alter-add-column"),
|
||||
backButton: dialog.querySelector(".table-alter-back"),
|
||||
dropButton: dialog.querySelector(".table-alter-drop"),
|
||||
cancelButton: dialog.querySelector(".table-alter-cancel"),
|
||||
saveButton: dialog.querySelector(".table-alter-save"),
|
||||
currentButton: null,
|
||||
|
|
@ -2703,6 +2767,10 @@ function ensureTableAlterDialog(manager) {
|
|||
closeTableAlterDialog(tableAlterDialogState);
|
||||
});
|
||||
|
||||
tableAlterDialogState.dropButton.addEventListener("click", function () {
|
||||
dropTableFromAlterDialog(tableAlterDialogState);
|
||||
});
|
||||
|
||||
tableAlterDialogState.backButton.addEventListener("click", function () {
|
||||
if (tableAlterDialogState.isSaving) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -422,6 +422,15 @@ async def _table_alter_ui(
|
|||
data["customColumnTypes"] = _custom_column_type_options_for_create_table(
|
||||
datasette
|
||||
)
|
||||
can_drop_table = await datasette.allowed(
|
||||
action="drop-table",
|
||||
resource=TableResource(database=database_name, table=table_name),
|
||||
actor=request.actor,
|
||||
)
|
||||
if can_drop_table:
|
||||
data["dropPath"] = "{}/-/drop".format(
|
||||
datasette.urls.table(database_name, table_name)
|
||||
)
|
||||
return data
|
||||
|
||||
|
||||
|
|
@ -1193,6 +1202,11 @@ class TableDropView(BaseView):
|
|||
actor=request.actor, database=database_name, table=table_name
|
||||
)
|
||||
)
|
||||
self.ds.add_message(
|
||||
request,
|
||||
"Table {} dropped".format(table_name),
|
||||
self.ds.WARNING,
|
||||
)
|
||||
return Response.json({"ok": True}, status=200)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1089,8 +1089,9 @@ async def test_table_alter_action_button_and_data():
|
|||
"tables": {
|
||||
"items": {
|
||||
"permissions": {
|
||||
"alter-table": {"id": "root"},
|
||||
"alter-table": {"id": ["root", "alter-only"]},
|
||||
"set-column-type": {"id": "root"},
|
||||
"drop-table": {"id": "root"},
|
||||
},
|
||||
"column_types": {"name": "textarea"},
|
||||
},
|
||||
|
|
@ -1147,6 +1148,7 @@ async def test_table_alter_action_button_and_data():
|
|||
"textarea",
|
||||
"url",
|
||||
]
|
||||
assert alter_data["dropPath"] == "/data/items/-/drop"
|
||||
assert alter_data["columns"] == [
|
||||
{
|
||||
"name": "id",
|
||||
|
|
@ -1192,6 +1194,16 @@ async def test_table_alter_action_button_and_data():
|
|||
is None
|
||||
)
|
||||
assert "alterTable" not in table_data_from_soup(soup_without_permission)
|
||||
|
||||
# An actor that can alter but not drop should not get a dropPath
|
||||
response_alter_only = await ds.client.get(
|
||||
"/data/items", actor={"id": "alter-only"}
|
||||
)
|
||||
assert response_alter_only.status_code == 200
|
||||
alter_only_data = table_data_from_soup(
|
||||
Soup(response_alter_only.text, "html.parser")
|
||||
)["alterTable"]
|
||||
assert "dropPath" not in alter_only_data
|
||||
finally:
|
||||
ds.close()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue