implement column sorting
This commit is contained in:
parent
dcdc8a1737
commit
4eafe6e40a
@ -68,8 +68,8 @@ pub fn derive_actix_admin_view_model(input: proc_macro::TokenStream) -> proc_mac
|
||||
|
||||
#[actix_admin::prelude::async_trait(?Send)]
|
||||
impl ActixAdminViewModelTrait for Entity {
|
||||
async fn list(db: &DatabaseConnection, page: u64, entities_per_page: u64, search: &String) -> Result<(u64, Vec<ActixAdminModel>), ActixAdminError> {
|
||||
let entities = Entity::list_model(db, page, entities_per_page, search).await;
|
||||
async fn list(db: &DatabaseConnection, page: u64, entities_per_page: u64, search: &str, sort_by: &str, sort_order: &SortOrder) -> Result<(u64, Vec<ActixAdminModel>), ActixAdminError> {
|
||||
let entities = Entity::list_model(db, page, entities_per_page, search, sort_by, sort_order).await;
|
||||
entities
|
||||
}
|
||||
|
||||
@ -155,6 +155,7 @@ pub fn derive_actix_admin_model(input: proc_macro::TokenStream) -> proc_macro::T
|
||||
let fields_type_path = get_actix_admin_fields_type_path_string(&fields);
|
||||
let fields_textarea = get_actix_admin_fields_textarea(&fields);
|
||||
let fields_file_upload = get_actix_admin_fields_file_upload(&fields);
|
||||
let fields_match_name_to_columns = get_match_name_to_column(&fields);
|
||||
|
||||
let expanded = quote! {
|
||||
actix_admin::prelude::lazy_static! {
|
||||
@ -236,14 +237,25 @@ pub fn derive_actix_admin_model(input: proc_macro::TokenStream) -> proc_macro::T
|
||||
|
||||
#[actix_admin::prelude::async_trait]
|
||||
impl ActixAdminModelTrait for Entity {
|
||||
async fn list_model(db: &DatabaseConnection, page: u64, posts_per_page: u64, search: &String) -> Result<(u64, Vec<ActixAdminModel>), ActixAdminError> {
|
||||
async fn list_model(db: &DatabaseConnection, page: u64, posts_per_page: u64, search: &str, sort_by: &str, sort_order: &SortOrder) -> Result<(u64, Vec<ActixAdminModel>), ActixAdminError> {
|
||||
use sea_orm::{ query::* };
|
||||
let paginator = Entity::find()
|
||||
|
||||
let sort_column = match sort_by {
|
||||
#(#fields_match_name_to_columns)*
|
||||
_ => panic!("Unknown column")
|
||||
};
|
||||
|
||||
let query = if sort_order.eq(&SortOrder::Asc) {
|
||||
Entity::find().order_by_asc(sort_column)
|
||||
} else {
|
||||
Entity::find().order_by_desc(sort_column)
|
||||
};
|
||||
|
||||
let paginator = query
|
||||
.filter(
|
||||
Condition::any()
|
||||
#(#fields_searchable)*
|
||||
)
|
||||
.order_by_asc(Column::Id)
|
||||
.paginate(db, posts_per_page);
|
||||
let num_pages = paginator.num_pages().await?;
|
||||
let mut model_entities = Vec::new();
|
||||
|
@ -17,7 +17,15 @@ pub fn get_fields_for_tokenstream(input: proc_macro::TokenStream) -> std::vec::V
|
||||
}
|
||||
|
||||
fn capitalize_first_letter(s: &str) -> String {
|
||||
s[0..1].to_uppercase() + &s[1..]
|
||||
if s.len() > 0 {
|
||||
s[0..1].to_uppercase() + &s[1..]
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn to_camelcase(s: &str) -> String {
|
||||
s.split("_").fold(String::new(), |a, b| capitalize_first_letter(&a) + &capitalize_first_letter(b))
|
||||
}
|
||||
|
||||
pub fn filter_fields(fields: &Fields) -> Vec<ModelField> {
|
||||
@ -208,12 +216,26 @@ pub fn get_actix_admin_fields_file_upload(fields: &Vec<ModelField>) -> Vec<Token
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn get_match_name_to_column(fields: &Vec<ModelField>) -> Vec<TokenStream> {
|
||||
fields
|
||||
.iter()
|
||||
.map(|model_field| {
|
||||
let column_name = model_field.ident.to_string();
|
||||
let column_name_capitalized = to_camelcase(&column_name);
|
||||
let column_ident = Ident::new(&column_name_capitalized, Span::call_site());
|
||||
quote! {
|
||||
#column_name => Column::#column_ident,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn get_actix_admin_fields_searchable(fields: &Vec<ModelField>) -> Vec<TokenStream> {
|
||||
fields
|
||||
.iter()
|
||||
.filter(|model_field| model_field.searchable)
|
||||
.map(|model_field| {
|
||||
let column_name = format!("{}", capitalize_first_letter(&model_field.ident.to_string()));
|
||||
let column_name = capitalize_first_letter(&model_field.ident.to_string());
|
||||
let column_ident = Ident::new(&column_name, Span::call_site());
|
||||
quote! {
|
||||
.add(Column::#column_ident.contains(&search))
|
||||
|
@ -146,7 +146,7 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
|
||||
if add_to_menu {
|
||||
let menu_element = ActixAdminMenuElement {
|
||||
name: menu_element_name.to_string(),
|
||||
link: format!("{}", path.replacen("/", "", 1)),
|
||||
link: path.replacen("/", "", 1),
|
||||
is_custom_handler: true,
|
||||
};
|
||||
let category = self.actix_admin.entity_names.get_mut("");
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use sea_orm::DatabaseConnection;
|
||||
use serde::Serialize;
|
||||
use serde::{Serialize };
|
||||
use std::collections::HashMap;
|
||||
use tera::{Tera, Result, to_value, try_get_value };
|
||||
use std::{ hash::BuildHasher};
|
||||
@ -31,7 +31,7 @@ pub mod prelude {
|
||||
pub use actix_admin_macros::{ DeriveActixAdmin, DeriveActixAdminModel, DeriveActixAdminViewModel, DeriveActixAdminEnumSelectList, DeriveActixAdminModelSelectList };
|
||||
pub use crate::{ ActixAdminError, ActixAdminAppDataTrait, ActixAdmin, ActixAdminConfiguration };
|
||||
pub use crate::{ hashmap, ActixAdminSelectListTrait };
|
||||
pub use crate::routes::{ create_or_edit_post, get_admin_ctx };
|
||||
pub use crate::routes::{ create_or_edit_post, get_admin_ctx, SortOrder };
|
||||
pub use crate::{ TERA };
|
||||
pub use itertools::izip;
|
||||
pub use lazy_static::lazy_static;
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::routes::SortOrder;
|
||||
use crate::{ActixAdminError, ActixAdminViewModelField};
|
||||
use actix_multipart::{Multipart, MultipartError};
|
||||
use actix_web::web::Bytes;
|
||||
@ -17,7 +18,9 @@ pub trait ActixAdminModelTrait {
|
||||
db: &DatabaseConnection,
|
||||
page: u64,
|
||||
posts_per_page: u64,
|
||||
search: &String,
|
||||
search: &str,
|
||||
sort_by: &str,
|
||||
sort_order: &SortOrder
|
||||
) -> Result<(u64, Vec<ActixAdminModel>), ActixAdminError>;
|
||||
fn get_fields() -> &'static [ActixAdminViewModelField];
|
||||
fn validate_model(model: &mut ActixAdminModel);
|
||||
|
@ -57,7 +57,7 @@ pub async fn delete_many<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>
|
||||
session: Session,
|
||||
_req: HttpRequest,
|
||||
data: web::Data<T>,
|
||||
form: web::Form<Vec<(String, i32)>>,
|
||||
form: web::Form<Vec<(String, String)>>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let actix_admin = data.get_actix_admin();
|
||||
let entity_name = E::get_entity_name();
|
||||
@ -74,7 +74,7 @@ pub async fn delete_many<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>
|
||||
let db = &data.get_db();
|
||||
let entity_name = E::get_entity_name();
|
||||
|
||||
let ids: Vec<i32> = form.iter().map(|el| el.1).collect();
|
||||
let ids: Vec<i32> = form.iter().filter(|el| el.0 == "ids").map(|el| el.1.parse::<i32>().unwrap()).collect();
|
||||
|
||||
// TODO: implement delete_many
|
||||
for id in ids {
|
||||
@ -104,11 +104,32 @@ pub async fn delete_many<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>
|
||||
}
|
||||
}
|
||||
|
||||
let entities_per_page = form.iter()
|
||||
.find(|el| el.0 == "entities_per_page")
|
||||
.map(|e| e.1.to_string())
|
||||
.unwrap_or("10".to_string());
|
||||
let search = form.iter()
|
||||
.find(|el| el.0 == "search")
|
||||
.map(|e| e.1.to_string())
|
||||
.unwrap_or_default();
|
||||
let sort_by = form.iter()
|
||||
.find(|el| el.0 == "sort_by")
|
||||
.map(|e| e.1.to_string())
|
||||
.unwrap_or("id".to_string());
|
||||
let sort_order = form.iter()
|
||||
.find(|el| el.0 == "sort_order")
|
||||
.map(|e| e.1.to_string())
|
||||
.unwrap_or("Asc".to_string());
|
||||
let page = form.iter()
|
||||
.find(|el| el.0 == "page")
|
||||
.map(|e| e.1.to_string())
|
||||
.unwrap_or("1".to_string());
|
||||
|
||||
match errors.is_empty() {
|
||||
true => Ok(HttpResponse::SeeOther()
|
||||
.append_header((
|
||||
header::LOCATION,
|
||||
format!("/admin/{}/list?render_partial=true", entity_name),
|
||||
format!("/admin/{}/list?render_partial=true&entities_per_page={}&search={}&sort_by={}&sort_order={}&page={}", entity_name, entities_per_page, search, sort_by, sort_order, page),
|
||||
))
|
||||
.finish()),
|
||||
false => Ok(HttpResponse::InternalServerError().finish()),
|
||||
|
@ -2,7 +2,7 @@ use actix_web::{error, web, Error, HttpRequest, HttpResponse};
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize};
|
||||
use tera::{Context};
|
||||
use crate::prelude::*;
|
||||
use crate::{prelude::*};
|
||||
|
||||
use crate::ActixAdminViewModelTrait;
|
||||
use crate::ActixAdminViewModel;
|
||||
@ -14,12 +14,6 @@ use super::{ add_auth_context, user_can_access_page, render_unauthorized};
|
||||
|
||||
const DEFAULT_ENTITIES_PER_PAGE: u64 = 10;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum SortOrder {
|
||||
Asc,
|
||||
Desc,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Params {
|
||||
page: Option<u64>,
|
||||
@ -30,6 +24,12 @@ pub struct Params {
|
||||
sort_order: Option<SortOrder>
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum SortOrder {
|
||||
Asc,
|
||||
Desc,
|
||||
}
|
||||
|
||||
pub async fn list<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
||||
session: Session,
|
||||
req: HttpRequest,
|
||||
@ -61,7 +61,8 @@ pub async fn list<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
||||
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.as_ref().unwrap_or(&SortOrder::Asc);
|
||||
let result = E::list(db, page, entities_per_page, &search).await;
|
||||
|
||||
let result = E::list(db, page, entities_per_page, &search, &sort_by, &sort_order).await;
|
||||
match result {
|
||||
Ok(res) => {
|
||||
let entities = res.1;
|
||||
@ -101,8 +102,6 @@ pub async fn list<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
||||
ctx.insert("search", &search);
|
||||
ctx.insert("sort_by", &sort_by);
|
||||
ctx.insert("sort_order", &sort_order);
|
||||
ctx.insert("sort_order_asc", &SortOrder::Asc);
|
||||
ctx.insert("sort_order_desc", &SortOrder::Desc);
|
||||
|
||||
let body = TERA
|
||||
.render("list.html", &ctx)
|
||||
|
@ -8,7 +8,7 @@ mod index;
|
||||
pub use index::{ index, not_found, get_admin_ctx };
|
||||
|
||||
mod list;
|
||||
pub use list::{ list };
|
||||
pub use list::{ list, SortOrder };
|
||||
|
||||
mod show;
|
||||
pub use show::show;
|
||||
|
@ -2,7 +2,7 @@ use async_trait::async_trait;
|
||||
use sea_orm::DatabaseConnection;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::collections::HashMap;
|
||||
use crate::ActixAdminModel;
|
||||
use crate::{ActixAdminModel, SortOrder};
|
||||
use actix_session::{Session};
|
||||
use std::convert::From;
|
||||
use crate::ActixAdminError;
|
||||
@ -13,7 +13,9 @@ pub trait ActixAdminViewModelTrait {
|
||||
db: &DatabaseConnection,
|
||||
page: u64,
|
||||
entities_per_page: u64,
|
||||
search: &String
|
||||
search: &str,
|
||||
sort_by: &str,
|
||||
sort_order: &SortOrder
|
||||
) -> Result<(u64, Vec<ActixAdminModel>), ActixAdminError>;
|
||||
|
||||
// TODO: Replace return value with proper Result Type containing Ok or Err
|
||||
|
@ -31,14 +31,14 @@ function checkAll(bx) {
|
||||
}
|
||||
|
||||
function sort_by(column) {
|
||||
document.getElementById("sort_by").value = column;
|
||||
current_sort_order = document.getElementById("sort_order").value;
|
||||
if (current_sort_order == "{{ sort_order_asc }}") {
|
||||
document.getElementById("sort_order").value = "{{ sort_order_desc }}";
|
||||
current_sort_order = document.getElementsByName("sort_order")[0].value;
|
||||
if (current_sort_order == "Asc") {
|
||||
document.getElementsByName("sort_order").forEach((e) => e.value = "Desc");
|
||||
} else {
|
||||
document.getElementById("sort_order").value = "{{ sort_order_asc }}";
|
||||
document.getElementsByName("sort_order").forEach((e) => e.value = "Asc");
|
||||
}
|
||||
document.getElementById('search_form').submit();
|
||||
document.getElementsByName("sort_by").forEach((e) => e.value = column);
|
||||
document.getElementById('table_form').requestSubmit();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
@ -24,7 +24,7 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div>
|
||||
<div id="content">
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
</div>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<div class="buttons">
|
||||
<a class="button is-primary" href="create" hx-boost="true" hx-indicator="#loading">Create</a>
|
||||
|
||||
<div hx-include="#checked-rows" hx-target="#{{ entity_name }}table" class="dropdown is-hoverable">
|
||||
<div class="dropdown is-hoverable">
|
||||
<div class="dropdown-trigger">
|
||||
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu4">
|
||||
<span>With selected</span>
|
||||
@ -20,38 +20,35 @@
|
||||
<div class="dropdown-menu" id="dropdown-menu4">
|
||||
<div class="dropdown-content">
|
||||
<div class="dropdown-item">
|
||||
<a href="#" hx-indicator="#loading" hx-confirm="Are you sure?" hx-delete="delete">Delete</a>
|
||||
<a hx-include="#table_form" hx-target="#{{ entity_name }}table" href="#"
|
||||
hx-indicator="#loading" hx-confirm="Are you sure?" hx-delete="delete">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-narrow">
|
||||
{% if view_model.show_search %}
|
||||
<div class="field">
|
||||
<p class="control has-icons-left has-icons-right">
|
||||
<input class="input is-rounded" type="search" id="search" value="{{ search }}" name="search"
|
||||
placeholder="Search"
|
||||
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-indicator="#loading">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-search"></i>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="column is-narrow">
|
||||
<div>
|
||||
<form id="search_form" hx-boost="true" hx-indicator="#loading">
|
||||
<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 }}">
|
||||
<form id="search_form" action="/admin/{{ entity_name }}/list" hx-boost="true" hx-indicator="#loading"
|
||||
hx-target="#{{ entity_name }}table" hx-trigger="reload_table from:#entities_per_page"
|
||||
hx-vals='{ "render_partial" : "true" }'>
|
||||
<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="column is-narrow">
|
||||
<div class="field is-horizontal">
|
||||
{% if view_model.show_search %}
|
||||
<p class="control has-icons-left has-icons-right">
|
||||
<input class="input is-rounded" type="search" id="search" value="{{ search }}" name="search"
|
||||
placeholder="Search" hx-get="/admin/{{ entity_name }}/list"
|
||||
hx-trigger="keyup changed delay:500ms, search">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-search"></i>
|
||||
</span>
|
||||
</p>
|
||||
{% endif %}
|
||||
<div class="select">
|
||||
<div class="control has-icons-left has-icons-right">
|
||||
<select class="select" name="entities_per_page" onchange="this.form.submit()">
|
||||
<div class="ml-1 control has-icons-left has-icons-right">
|
||||
<select id="entities_per_page" class="select" name="entities_per_page"
|
||||
onchange="this.dispatchEvent(new Event('reload_table'));">
|
||||
{% for a in [10,20,50,100,] %}
|
||||
<option {% if entities_per_page==a %}selected{% endif %} value="{{ a }}">{{ a }}</option>
|
||||
{% endfor %}
|
||||
@ -59,19 +56,24 @@
|
||||
<p class="help">Entities per Page</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
<div id="{{ entity_name }}table">
|
||||
<form id="checked-rows">
|
||||
<div class="is-relative">
|
||||
{% include "loader.html" %}
|
||||
<table class="table is-relative is-fullwidth is-hoverable is-striped">
|
||||
<thead>
|
||||
<div class="is-relative">
|
||||
{% include "loader.html" %}
|
||||
<form id="table_form" hx-indicator="#loading" hx-get="/admin/{{ entity_name }}/list"
|
||||
hx-vals='{ "render_partial" : "true" }' hx-target="#{{ entity_name }}table">
|
||||
<input type="hidden" id="sort_by" name="sort_by" value="{{ sort_by }}">
|
||||
<input type="hidden" id="sort_order" name="sort_order" value="{{ sort_order }}">
|
||||
<input type="hidden" name="entities_per_page" value="{{ entities_per_page }}">
|
||||
<input type="hidden" name="search" value="{{ search }}">
|
||||
<input type="hidden" name="page" value="{{ page }}">
|
||||
<table class="table is-relative is-fullwidth is-hoverable is-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<input type="checkbox" onclick="checkAll(this)">
|
||||
@ -79,9 +81,9 @@
|
||||
<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 == "{{ sort_order_asc }}" %}
|
||||
{% if sort_order == "Asc" %}
|
||||
<i class="ml-1 fa-solid fa-caret-up"></i>
|
||||
{% elif sort_order == "{{ sort_order_desc }}" %}
|
||||
{% elif sort_order == "Desc" %}
|
||||
<i class="ml-1 fa-solid fa-caret-down"></i>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@ -90,9 +92,9 @@
|
||||
<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 == "{{ sort_order_asc }}" %}
|
||||
{% if sort_order == "Asc" %}
|
||||
<i class="ml-1 fa-solid fa-caret-up"></i>
|
||||
{% elif sort_order == "{{ sort_order_desc }}" %}
|
||||
{% elif sort_order == "Desc" %}
|
||||
<i class="ml-1 fa-solid fa-caret-down"></i>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@ -103,8 +105,9 @@
|
||||
<!-- Delete Action -->
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody hx-confirm="Are you sure?" hx-target="closest tr" hx-indicator="#loading" hx-swap="outerHTML">
|
||||
</form>
|
||||
</thead>
|
||||
<tbody hx-indicator="#loading" hx-boost="true">
|
||||
{% for entity in entities -%}
|
||||
<tr>
|
||||
<td><input type="checkbox" name="ids" value="{{ entity.primary_key }}"></td>
|
||||
@ -125,37 +128,47 @@
|
||||
{% endif %}
|
||||
{%- endfor %}
|
||||
<td>
|
||||
<a href="edit/{{ entity.primary_key }}"><i class="fa-solid fa-pen-to-square"></i></a>
|
||||
<a hx-delete="delete/{{ entity.primary_key }}"><i class="fa-solid fa-trash"></i></a>
|
||||
<a hx-target="body" href="edit/{{ entity.primary_key }}"><i class="fa-solid fa-pen-to-square"></i></a>
|
||||
<a hx-target="closest tr" hx-confirm="Are you sure?"
|
||||
hx-delete="delete/{{ entity.primary_key }}"><i class="fa-solid fa-trash"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
{%- endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="{{ view_model.fields | length + 3 }}">
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="{{ view_model.fields | length + 3 }}">
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</form>
|
||||
<nav hx-boost="true" hx-indicator="#loading" class="pagination is-rounded is-centered" role="pagination"
|
||||
</div>
|
||||
<nav hx-boost="true"
|
||||
hx-push-url="true"
|
||||
hx-target="#{{ entity_name }}table"
|
||||
hx-vals='{
|
||||
"entities_per_page" : "{{ entities_per_page }}",
|
||||
"search" : "{{ search }}",
|
||||
"sort_by" : "{{ sort_by }}",
|
||||
"sort_order" : "{{ sort_order }}",
|
||||
"render_partial" : "true"
|
||||
}' hx-indicator="#loading" class="pagination is-rounded is-centered" role="pagination"
|
||||
aria-label="pagination">
|
||||
{% if page > 1 %}
|
||||
<a href="?page={{ page - 1 }}&entities_per_page={{ entities_per_page }}&search={{ search }}"
|
||||
<a href="?&page={{ page - 1 }}"
|
||||
class="pagination-previous left-arrow-click"><i class="fa-solid fa-arrow-left"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if page < num_pages %} <a
|
||||
href="?page={{ page + 1 }}&entities_per_page={{ entities_per_page }}&search={{ search }}"
|
||||
href="?page={{ page + 1 }}"
|
||||
class="pagination-next right-arrow-click"><i class="fa-solid fa-arrow-right"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
<ul class="pagination-list">
|
||||
<li>
|
||||
<a class="pagination-link {% if page == 1 %}is-current{% endif %}"
|
||||
href="?page={{ 1 }}&entities_per_page={{ entities_per_page }}&search={{ search }}"
|
||||
href="?page={{ 1 }}"
|
||||
aria-label="Goto page 1">1</a>
|
||||
</li>
|
||||
<li>
|
||||
@ -164,14 +177,14 @@
|
||||
{% for i in range(start=min_show_page,end=max_show_page) %}
|
||||
<li><a class="pagination-link {% if page == i+1 %}is-current{% endif %}"
|
||||
aria-label="Goto page {{ i + 1 }}"
|
||||
href="?page={{ i + 1 }}&entities_per_page={{ entities_per_page }}&search={{ search }}">{{
|
||||
href="?page={{ i + 1 }}">{{
|
||||
i + 1 }}</a></li>
|
||||
{%- endfor %}
|
||||
<li>
|
||||
<span class="pagination-ellipsis">…</span>
|
||||
</li>
|
||||
<li>
|
||||
<a href="?page={{ num_pages }}&entities_per_page={{ entities_per_page }}&search={{ search }}"
|
||||
<a href="?page={{ num_pages }}"
|
||||
class="pagination-link is-rounded {% if page == num_pages %}is-current{% endif %}"
|
||||
aria-label="Goto page {{ num_pages }}">{{ num_pages }} </a>
|
||||
</li>
|
||||
|
@ -4,14 +4,14 @@
|
||||
Actix Admin
|
||||
</a>
|
||||
|
||||
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
|
||||
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbar">
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div id="navbarBasicExample" class="navbar-menu">
|
||||
<div id="navbar" class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
{% for category, entities in entity_names %}
|
||||
{% if category == "" %}
|
||||
|
@ -78,8 +78,13 @@ mod get_request_is_success {
|
||||
let page_size = 20; // Verify with default size in list.rs
|
||||
let url = format!("/admin/{}/list?page={}&entities_per_page={}", crate::Comment::get_entity_name(), page, page_size);
|
||||
|
||||
let entities = crate::Comment::find()
|
||||
.order_by_asc(crate::comment::Column::Id)
|
||||
let query = if page_size == 5 {
|
||||
crate::Comment::find().order_by_asc(crate::comment::Column::Id)
|
||||
} else {
|
||||
crate::Comment::find().order_by_asc(crate::comment::Column::Id)
|
||||
};
|
||||
|
||||
let entities = query
|
||||
.paginate(&db, page_size)
|
||||
.fetch_page(page-1)
|
||||
.await
|
||||
|
Loading…
Reference in New Issue
Block a user