add sort functionality to table columns in ui

This commit is contained in:
Manuel Gugger 2023-01-06 16:12:51 +01:00
parent 7b4e2628b2
commit 77ec92f7eb
4 changed files with 43 additions and 30 deletions

View File

@ -18,7 +18,9 @@ pub struct Params {
page: Option<u64>, page: Option<u64>,
entities_per_page: Option<u64>, entities_per_page: Option<u64>,
render_partial: Option<bool>, render_partial: Option<bool>,
search: Option<String> search: Option<String>,
sort_by: Option<String>,
sort_order: Option<String>
} }
pub async fn list<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>( pub async fn list<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
@ -50,6 +52,8 @@ pub async fn list<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
let search = params.search.clone().unwrap_or(String::new()); let search = params.search.clone().unwrap_or(String::new());
let db = data.get_db(); let db = data.get_db();
let sort_by = params.sort_by.clone().unwrap_or(view_model.primary_key.to_string());
let sort_order = params.sort_order.clone().unwrap_or(String::new());
let result = E::list(db, page, entities_per_page, &search).await; let result = E::list(db, page, entities_per_page, &search).await;
match result { match result {
Ok(res) => { Ok(res) => {
@ -76,11 +80,12 @@ pub async fn list<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
ctx.insert("entity_name", &entity_name); ctx.insert("entity_name", &entity_name);
ctx.insert("notifications", &notifications); ctx.insert("notifications", &notifications);
ctx.insert("page", &page); ctx.insert("page", &page);
ctx.insert("params", &entities_per_page);
ctx.insert("entities_per_page", &entities_per_page); ctx.insert("entities_per_page", &entities_per_page);
ctx.insert("render_partial", &render_partial); ctx.insert("render_partial", &render_partial);
ctx.insert("view_model", &ActixAdminViewModelSerializable::from(view_model.clone())); ctx.insert("view_model", &ActixAdminViewModelSerializable::from(view_model.clone()));
ctx.insert("search", &search); ctx.insert("search", &search);
ctx.insert("sort_by", &sort_by);
ctx.insert("sort_order", &sort_order);
let body = TERA let body = TERA
.render("list.html", &ctx) .render("list.html", &ctx)

View File

@ -27,7 +27,7 @@
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</div> </div>
<div class="fade-in"> <div>
{% block content %} {% block content %}
{% endblock content %} {% endblock content %}
</div> </div>

View File

@ -3,10 +3,8 @@
<title>Actix Admin</title> <title>Actix Admin</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/all.min.css" <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css">
integrity="sha512-1sCRPdkRXhBV2PBLUdRb4tMg1w2YPf37qatUFeS7zlBy7jJI8Lf4VHwWfZZfpXtYSLy85pkm9GaYVYMfw5BC1A==" <script src="https://unpkg.com/htmx.org@1.8.4"></script>
crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://unpkg.com/htmx.org@1.7.0"></script>
<script> <script>
function checkAll(bx) { function checkAll(bx) {
@ -18,6 +16,17 @@
} }
} }
function sort_by(column) {
document.getElementById("sort_by").value = column;
current_sort_order = document.getElementById("sort_order").value;
if(current_sort_order == "asc") {
document.getElementById("sort_order").value = "desc";
} else {
document.getElementById("sort_order").value = "asc";
}
document.getElementById('search_form').submit();
}
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
// Get all "navbar-burger" elements // Get all "navbar-burger" elements
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0); const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
@ -59,23 +68,4 @@
z-index: 6; z-index: 6;
pointer-events: none pointer-events: none
} }
.fade-in {
opacity: 1;
animation-name: fadeInOpacity;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 0.2s;
}
@keyframes fadeInOpacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style> </style>

View File

@ -33,7 +33,7 @@
<p class="control has-icons-left has-icons-right"> <p class="control has-icons-left has-icons-right">
<input class="input is-rounded" type="search" id="search" value="{{ search }}" name="search" <input class="input is-rounded" type="search" id="search" value="{{ search }}" name="search"
placeholder="Search" placeholder="Search"
hx-get="/admin/{{ entity_name }}/list?render_partial=true&entities_per_page={{ entities_per_page }}&page={{ page }}" hx-get="/admin/{{ entity_name }}/list?render_partial=true&entities_per_page={{ entities_per_page }}&page={{ page }}&sort_by={{ sort_by }}&sort_order={{ sort_order }}"
hx-trigger="keyup changed delay:500ms, search" hx-target="#{{ entity_name }}table" hx-trigger="keyup changed delay:500ms, search" hx-target="#{{ entity_name }}table"
hx-indicator="#loading"> hx-indicator="#loading">
<span class="icon is-small is-left"> <span class="icon is-small is-left">
@ -45,8 +45,10 @@
</div> </div>
<div class="column is-narrow"> <div class="column is-narrow">
<div> <div>
<form hx-boost="true" hx-indicator="#loading"> <form id="search_form" hx-boost="true" hx-indicator="#loading">
<input type="hidden" value="{{ search }}" name="search"> <input type="hidden" value="{{ search }}" name="search">
<input type="hidden" id="sort_by" name="sort_by" value="{{ sort_by}}">
<input type="hidden" id="sort_order" name="sort_order" value="{{ sort_order }}">
<div class="select"> <div class="select">
<div class="control has-icons-left has-icons-right"> <div class="control has-icons-left has-icons-right">
<select class="select" name="entities_per_page" onchange="this.form.submit()"> <select class="select" name="entities_per_page" onchange="this.form.submit()">
@ -72,9 +74,25 @@
<th> <th>
<input type="checkbox" onclick="checkAll(this)"> <input type="checkbox" onclick="checkAll(this)">
</th> </th>
<th>{{ view_model.primary_key | title }}</th> <th onclick="sort_by('{{ view_model.primary_key }}');" class="is-clickable">{{ view_model.primary_key | title }}
{% if sort_by == view_model.primary_key %}
{% if sort_order == "asc" %}
<i class="ml-1 fa-solid fa-caret-up"></i>
{% else %}
<i class="ml-1 fa-solid fa-caret-down"></i>
{% endif %}
{% endif %}
</th>
{% for model_field in view_model.fields -%} {% for model_field in view_model.fields -%}
<th>{{ model_field.field_name | split(pat="_") | join(sep=" ") | title }}</th> <th onclick="sort_by('{{ model_field.field_name }}');" class="is-clickable">{{ model_field.field_name | split(pat="_") | join(sep=" ") | title }}
{% if sort_by == model_field.field_name %}
{% if sort_order == "asc" %}
<i class="ml-1 fa-solid fa-caret-up"></i>
{% else %}
<i class="ml-1 fa-solid fa-caret-down"></i>
{% endif %}
{% endif %}
</th>
{%- endfor %} {%- endfor %}
<th> <th>
<!-- Edit Action --> <!-- Edit Action -->