Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add modal confirmation for bulk delete #612

Merged
merged 1 commit into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions sqladmin/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@
from sqladmin._types import ENGINE_TYPE
from sqladmin.ajax import QueryAjaxModelLoader
from sqladmin.authentication import AuthenticationBackend, login_required
from sqladmin.helpers import is_async_session_maker, slugify_action_name
from sqladmin.helpers import (
get_object_identifier,
is_async_session_maker,
slugify_action_name,
)
from sqladmin.models import BaseView, ModelView

__all__ = [
Expand Down Expand Up @@ -102,6 +106,7 @@ def init_templating_engine(self) -> Jinja2Templates:
templates.env.globals["zip"] = zip
templates.env.globals["admin"] = self
templates.env.globals["is_list"] = lambda x: isinstance(x, list)
templates.env.globals["get_object_identifier"] = get_object_identifier

return templates

Expand Down Expand Up @@ -630,7 +635,7 @@ def get_save_redirect_url(
"""

identity = request.path_params["identity"]
identifier = model_view.get_identifier(obj)
identifier = get_object_identifier(obj)

if form.get("save") == "Save":
return request.url_for("admin:list", identity=identity)
Expand Down
11 changes: 4 additions & 7 deletions sqladmin/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -701,23 +701,23 @@ async def _run_query(self, stmt: ClauseElement) -> Any:
return await anyio.to_thread.run_sync(self._run_query_sync, stmt)

def _url_for_details(self, request: Request, obj: Any) -> Union[str, URL]:
pk = self.get_identifier(obj)
pk = get_object_identifier(obj)
return request.url_for(
"admin:details",
identity=slugify_class_name(obj.__class__.__name__),
pk=pk,
)

def _url_for_edit(self, request: Request, obj: Any) -> Union[str, URL]:
pk = self.get_identifier(obj)
pk = get_object_identifier(obj)
return request.url_for(
"admin:edit",
identity=slugify_class_name(obj.__class__.__name__),
pk=pk,
)

def _url_for_delete(self, request: Request, obj: Any) -> str:
pk = self.get_identifier(obj)
pk = get_object_identifier(obj)
query_params = urlencode({"pks": pk})
url = request.url_for(
"admin:delete", identity=slugify_class_name(obj.__class__.__name__)
Expand All @@ -734,7 +734,7 @@ def _url_for_details_with_prop(
return request.url_for(
"admin:details",
identity=slugify_class_name(target.__class__.__name__),
pk=self.get_identifier(target),
pk=get_object_identifier(target),
)

def _url_for_action(self, request: Request, action_name: str) -> str:
Expand All @@ -744,9 +744,6 @@ def _url_for_action(self, request: Request, action_name: str) -> str:
)
)

def get_identifier(self, obj: Any) -> Any:
return get_object_identifier(obj)

def _get_default_sort(self) -> List[Tuple[str, bool]]:
if self.column_default_sort:
if isinstance(self.column_default_sort, list):
Expand Down
15 changes: 4 additions & 11 deletions sqladmin/statics/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ $(document).on('keyup', '#search-input', function (e) {
// Make a new timeout set to go off in 1000ms (1 second)
timeout = setTimeout(function () {
$('#search-button').click();
}, 1000);
}, 1000);
});

// Date picker
Expand Down Expand Up @@ -121,16 +121,9 @@ $("#action-delete").click(function () {
}
});

$.ajax({
url: $(this).attr('data-url') + '?pks=' + pks.join(","),
method: 'DELETE',
success: function (result) {
window.location.href = result;
},
error: function (request, status, error) {
alert(request.responseText);
}
});
$('#action-delete').data("pk", pks);
$('#action-delete').data("url", $(this).data('url') + '?pks=' + pks.join(","));
$('#modal-delete').modal('show');
});

$("[id^='action-custom-']").click(function () {
Expand Down
8 changes: 4 additions & 4 deletions sqladmin/templates/details.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ <h3 class="card-title">
{% for pk in model_view.pk_columns -%}
{{ pk.name }}
{%- if not loop.last %};{% endif -%}
{% endfor %}: {{ model_view.get_identifier(model) }}</h3>
{% endfor %}: {{ get_object_identifier(model) }}</h3>
</div>
<div class="card-body border-bottom py-3">
<div class="table-responsive">
Expand Down Expand Up @@ -51,7 +51,7 @@ <h3 class="card-title">
</div>
{% if model_view.can_delete %}
<div class="col-md-1">
<a href="#" data-name="{{ model_view.name }}" data-pk="{{ model_view.get_identifier(model) }}" data-url="{{ model_view._url_for_delete(request, model) }}" data-bs-toggle="modal" data-bs-target="#modal-delete" class="btn btn-danger">
<a href="#" data-name="{{ model_view.name }}" data-pk="{{ get_object_identifier(model) }}" data-url="{{ model_view._url_for_delete(request, model) }}" data-bs-toggle="modal" data-bs-target="#modal-delete" class="btn btn-danger">
Delete
</a>
</div>
Expand All @@ -70,7 +70,7 @@ <h3 class="card-title">
{{ label }}
</a>
{% else %}
<a href="{{ model_view._url_for_action(request, custom_action) }}?pks={{ model_view.get_identifier(model) }}" class="btn btn-secondary">
<a href="{{ model_view._url_for_action(request, custom_action) }}?pks={{ get_object_identifier(model) }}" class="btn btn-secondary">
{{ label }}
</a>
{% endif %}
Expand All @@ -87,7 +87,7 @@ <h3 class="card-title">

{% for custom_action in model_view._custom_actions_in_detail %}
{% if custom_action in model_view._custom_actions_confirmation %}
{% with confirmation_message = model_view._custom_actions_confirmation[custom_action], custom_action=custom_action, url=model_view._url_for_action(request, custom_action) + '?pks=' + (model_view.get_identifier(model) | string) %}
{% with confirmation_message = model_view._custom_actions_confirmation[custom_action], custom_action=custom_action, url=model_view._url_for_action(request, custom_action) + '?pks=' + (get_object_identifier(model) | string) %}
{% include 'modals/details_action_confirmation.html' %}
{% endwith %}
{% endif %}
Expand Down
6 changes: 3 additions & 3 deletions sqladmin/templates/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ <h3 class="card-title">{{ model_view.name_plural }}</h3>
{% if model_view.can_delete or model_view._custom_actions_in_list %}
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
{% if model_view.can_delete %}
<a class="dropdown-item" id="action-delete" href="#" data-url="{{ url_for('admin:delete', identity=model_view.identity) }}">Delete selected items</a>
<a class="dropdown-item" id="action-delete" href="#" data-name="{{ model_view.name }}" data-url="{{ url_for('admin:delete', identity=model_view.identity) }}" data-bs-toggle="modal" data-bs-target="#modal-delete">Delete selected items</a>
{% endif %}
{% for custom_action, label in model_view._custom_actions_in_list.items() %}
{% if custom_action in model_view._custom_actions_confirmation %}
Expand Down Expand Up @@ -100,7 +100,7 @@ <h3 class="card-title">{{ model_view.name_plural }}</h3>
{% for row in pagination.rows %}
<tr>
<td>
<input type="hidden" value="{{ model_view.get_identifier(row) }}">
<input type="hidden" value="{{ get_object_identifier(row) }}">
<input class="form-check-input m-0 align-middle select-box" type="checkbox" aria-label="Select item">
</td>
<td class="text-end">
Expand All @@ -115,7 +115,7 @@ <h3 class="card-title">{{ model_view.name_plural }}</h3>
</a>
{% endif %}
{% if model_view.can_delete %}
<a href="#" data-name="{{ model_view.name }}" data-pk="{{ model_view.get_identifier(row) }}" data-url="{{ model_view._url_for_delete(request, row) }}" data-bs-toggle="modal" data-bs-target="#modal-delete" title="Delete">
<a href="#" data-name="{{ model_view.name }}" data-pk="{{ get_object_identifier(row) }}" data-url="{{ model_view._url_for_delete(request, row) }}" data-bs-toggle="modal" data-bs-target="#modal-delete" title="Delete">
<span class="me-1"><i class="fa-solid fa-trash"></i></span>
</a>
{% endif %}
Expand Down