From 88b11b6f891deccccd752274b24200c7630eac6a Mon Sep 17 00:00:00 2001 From: Manuel Gugger Date: Mon, 20 Mar 2023 18:29:37 +0100 Subject: [PATCH] render_partial if hx-target header detected in req --- basictest/basic/Cargo.toml | 21 ------- basictest/basic/entity/comment.rs | 52 ------------------ basictest/basic/entity/mod.rs | 91 ------------------------------- basictest/basic/entity/post.rs | 74 ------------------------- basictest/basic/main.rs | 87 ----------------------------- examples/azure_auth/main.rs | 10 ++-- src/routes/create_or_edit_get.rs | 2 +- src/routes/create_or_edit_post.rs | 3 +- src/routes/delete.rs | 2 +- src/routes/list.rs | 2 +- src/routes/mod.rs | 1 - src/routes/show.rs | 2 +- src/templates/create_or_edit.html | 3 +- src/templates/list.html | 18 ++---- src/templates/show.html | 3 +- 15 files changed, 18 insertions(+), 353 deletions(-) delete mode 100644 basictest/basic/Cargo.toml delete mode 100644 basictest/basic/entity/comment.rs delete mode 100644 basictest/basic/entity/mod.rs delete mode 100644 basictest/basic/entity/post.rs delete mode 100644 basictest/basic/main.rs diff --git a/basictest/basic/Cargo.toml b/basictest/basic/Cargo.toml deleted file mode 100644 index 4b68cd1..0000000 --- a/basictest/basic/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "actix-admin-example" -description = "An admin interface for actix-web" -version = "0.4.0" -edition = "2021" - -[[bin]] -name = "actix-admin-example" -path = "main.rs" - -[dependencies] -actix-web = "^4.2.1" -actix-rt = "2.7.0" -actix-multipart = "^0.4.0" -sea-orm = { version = "^0.11.1", features = [ "sqlx-sqlite", "runtime-actix-native-tls", "macros" ], default-features = true } -chrono = "0.4.23" -tera = "^1.17.1" -serde = "^1.0.152" -serde_derive = "^1.0.152" -actix-admin = { version = "0.4.0", path = "../../" } -regex = "1.7.1" \ No newline at end of file diff --git a/basictest/basic/entity/comment.rs b/basictest/basic/entity/comment.rs deleted file mode 100644 index 33149b8..0000000 --- a/basictest/basic/entity/comment.rs +++ /dev/null @@ -1,52 +0,0 @@ -use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; -use actix_admin::prelude::*; -use super::Post; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, DeriveActixAdmin, DeriveActixAdminModel, DeriveActixAdminViewModel)] -#[sea_orm(table_name = "comment")] -pub struct Model { - #[sea_orm(primary_key)] - #[serde(skip_deserializing)] - #[actix_admin(primary_key)] - pub id: i32, - pub comment: String, - #[sea_orm(column_type = "Text")] - #[actix_admin(html_input_type = "email", list_regex_mask= "^([a-zA-Z]*)")] - pub user: String, - #[sea_orm(column_type = "DateTime")] - pub insert_date: DateTime, - pub is_visible: bool, - #[actix_admin(select_list="Post")] - pub post_id: Option, - pub my_decimal: Decimal -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::post::Entity", - from = "Column::PostId", - to = "super::post::Column::Id" - )] - Post, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Post.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} - -impl ActixAdminModelValidationTrait for Entity { - fn validate(model: &ActiveModel) -> HashMap { - let mut errors = HashMap::new(); - if model.my_decimal.clone().unwrap() < Decimal::from(100 as i16) { - errors.insert("my_decimal".to_string(), "Must be larger than 100".to_string()); - } - - errors - } -} \ No newline at end of file diff --git a/basictest/basic/entity/mod.rs b/basictest/basic/entity/mod.rs deleted file mode 100644 index ae6ea04..0000000 --- a/basictest/basic/entity/mod.rs +++ /dev/null @@ -1,91 +0,0 @@ -// setup -use sea_orm::sea_query::{ForeignKeyCreateStatement, ColumnDef, TableCreateStatement}; -use sea_orm::{Set, EntityTrait, error::*, sea_query, ConnectionTrait, DbConn, ExecResult}; -pub mod comment; -pub mod post; -pub use comment::Entity as Comment; -pub use post::Entity as Post; -use chrono::{Local, Duration, DurationRound}; -use sea_orm::prelude::Decimal; - -// setup -async fn create_table(db: &DbConn, stmt: &TableCreateStatement) -> Result { - let builder = db.get_database_backend(); - db.execute(builder.build(stmt)).await -} - -pub async fn create_post_table(db: &DbConn) -> Result { - let stmt = sea_query::Table::create() - .table(post::Entity) - .if_not_exists() - .col( - ColumnDef::new(post::Column::Id) - .integer() - .not_null() - .auto_increment() - .primary_key(), - ) - .col(ColumnDef::new(post::Column::Title).string().not_null()) - .col(ColumnDef::new(post::Column::Text).string().not_null()) - .col(ColumnDef::new(post::Column::TeaMandatory).string().not_null()) - .col(ColumnDef::new(post::Column::TeaOptional).string()) - .col(ColumnDef::new(post::Column::InsertDate).date().not_null()) - .col(ColumnDef::new(post::Column::Attachment).string()) - .to_owned(); - - let _result = create_table(db, &stmt).await; - - let stmt = sea_query::Table::create() - .table(comment::Entity) - .if_not_exists() - .col( - ColumnDef::new(post::Column::Id) - .integer() - .not_null() - .auto_increment() - .primary_key(), - ) - .col(ColumnDef::new(comment::Column::Comment).string().not_null()) - .col(ColumnDef::new(comment::Column::User).string().not_null()) - .col(ColumnDef::new(comment::Column::InsertDate).date_time().not_null()) - .col(ColumnDef::new(comment::Column::IsVisible).boolean().not_null()) - .col(ColumnDef::new(comment::Column::MyDecimal).decimal().not_null()) - .col(ColumnDef::new(comment::Column::PostId).integer()) - .foreign_key( - ForeignKeyCreateStatement::new() - .name("fk-comment-post") - .from_tbl(Comment) - .from_col(comment::Column::PostId) - .to_tbl(Post) - .to_col(post::Column::Id), - ) - .to_owned(); - - let res = create_table(db, &stmt).await; - - for i in 1..1000 { - let row = post::ActiveModel { - title: Set(format!("Test {}", i)), - text: Set("some content".to_string()), - tea_mandatory: Set(post::Tea::EverydayTea), - tea_optional: Set(None), - insert_date: Set(Local::now().date_naive()), - ..Default::default() - }; - let _res = Post::insert(row).exec(db).await; - } - - for i in 1..1000 { - let row = comment::ActiveModel { - comment: Set(format!("Test {}", i)), - user: Set("me@home.com".to_string()), - my_decimal: Set(Decimal::new(105, 0)), - insert_date: Set(Local::now().naive_utc().duration_round(Duration::minutes(1)).unwrap()), - is_visible: Set(i%2 == 0), - ..Default::default() - }; - let _res = Comment::insert(row).exec(db).await; - } - - res -} diff --git a/basictest/basic/entity/post.rs b/basictest/basic/entity/post.rs deleted file mode 100644 index e23f4de..0000000 --- a/basictest/basic/entity/post.rs +++ /dev/null @@ -1,74 +0,0 @@ -use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; -use actix_admin::prelude::*; -use std::fmt; -use std::fmt::Display; -use std::str::FromStr; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, DeriveActixAdmin, DeriveActixAdminViewModel, DeriveActixAdminModel, DeriveActixAdminModelSelectList)] -#[sea_orm(table_name = "post")] -pub struct Model { - #[sea_orm(primary_key)] - #[serde(skip_deserializing)] - #[actix_admin(primary_key)] - pub id: i32, - #[actix_admin(searchable, not_empty)] - pub title: String, - #[sea_orm(column_type = "Text")] - #[actix_admin(searchable, textarea, list_hide_column)] - pub text: String, - #[actix_admin(select_list="Tea")] - pub tea_mandatory: Tea, - #[actix_admin(select_list="Tea")] - pub tea_optional: Option, - #[sea_orm(column_type = "Date")] - #[actix_admin(list_sort_position="1")] - pub insert_date: Date, - #[actix_admin(file_upload)] - pub attachment: Option -} - -impl Display for Model { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &*self { - _ => write!(formatter, "{} {}", &self.title, ""/* &self.insert_date*/), - } - } -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::comment::Entity")] - Comment, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Comment.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} - -#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Deserialize, Serialize, DeriveActixAdminEnumSelectList)] -#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "tea")] -pub enum Tea { - #[sea_orm(string_value = "EverydayTea")] - EverydayTea, - #[sea_orm(string_value = "BreakfastTea")] - BreakfastTea, -} - -impl FromStr for Tea { - type Err = (); - - fn from_str(input: &str) -> Result { - match input { - "EverydayTea" => Ok(Tea::EverydayTea), - "BreakfastTea" => Ok(Tea::BreakfastTea), - _ => Err(()), - } - } -} - -impl ActixAdminModelValidationTrait for Entity {} \ No newline at end of file diff --git a/basictest/basic/main.rs b/basictest/basic/main.rs deleted file mode 100644 index 1174f62..0000000 --- a/basictest/basic/main.rs +++ /dev/null @@ -1,87 +0,0 @@ -extern crate serde_derive; - -use actix_admin::prelude::*; -use actix_web::{web, App, HttpServer, middleware}; -use sea_orm::{ConnectOptions, DatabaseConnection}; -use std::time::Duration; -mod entity; -use entity::{Post, Comment}; - -#[derive(Clone)] -pub struct AppState { - pub db: DatabaseConnection, - pub actix_admin: ActixAdmin, -} - -impl ActixAdminAppDataTrait for AppState { - fn get_db(&self) -> &DatabaseConnection { - &self.db - } - fn get_actix_admin(&self) -> &ActixAdmin { - &self.actix_admin - } -} - -fn create_actix_admin_builder() -> ActixAdminBuilder { - let configuration = ActixAdminConfiguration { - enable_auth: false, - user_is_logged_in: None, - login_link: None, - logout_link: None, - file_upload_directory: "./file_uploads" - }; - - let mut admin_builder = ActixAdminBuilder::new(configuration); - - - let post_view_model = ActixAdminViewModel::from(Post); - admin_builder.add_entity::(&post_view_model); - - let some_category = "Groupings"; - let comment_view_model = ActixAdminViewModel::from(Comment); - admin_builder.add_entity_to_category::(&comment_view_model, some_category); - - admin_builder -} - -fn get_db_options() -> ConnectOptions { - let db_url = "sqlite::memory:".to_string(); - let mut opt = ConnectOptions::new(db_url); - opt.max_connections(100) - .min_connections(5) - .connect_timeout(Duration::from_secs(8)) - .idle_timeout(Duration::from_secs(8)) - .sqlx_logging(true); - opt -} - -#[actix_rt::main] -async fn main() { - let opt = get_db_options(); - let conn = sea_orm::Database::connect(opt).await.unwrap(); - let _ = entity::create_post_table(&conn).await; - - println!("The admin interface is available at http://localhost:5000/admin/"); - - HttpServer::new(move || { - - let actix_admin_builder = create_actix_admin_builder(); - - let app_state = AppState { - db: conn.clone(), - actix_admin: actix_admin_builder.get_actix_admin(), - }; - - App::new() - .app_data(web::Data::new(app_state)) - .service( - actix_admin_builder.get_scope::() - ) - .wrap(middleware::Logger::default()) - }) - .bind("127.0.0.1:5000") - .expect("Can not bind to port 5000") - .run() - .await - .unwrap(); -} \ No newline at end of file diff --git a/examples/azure_auth/main.rs b/examples/azure_auth/main.rs index 98aabdb..1a2ba81 100644 --- a/examples/azure_auth/main.rs +++ b/examples/azure_auth/main.rs @@ -155,9 +155,6 @@ async fn main() { .expect("Invalid redirect URL"), ); - let mut tera = Tera::parse(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap(); - tera.extend(&TERA).unwrap(); - let _tera_res = tera.build_inheritance_chains(); let db_url = "sqlite::memory:".to_string(); let mut opt = ConnectOptions::new(db_url); @@ -173,12 +170,17 @@ async fn main() { let cookie_secret_key = Key::generate(); HttpServer::new(move || { let actix_admin_builder = create_actix_admin_builder(); + + let actix_admin = actix_admin_builder.get_actix_admin(); + let mut tera = Tera::parse(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap(); + tera.extend(&actix_admin.tera).unwrap(); + let _tera_res = tera.build_inheritance_chains(); let app_state = AppState { oauth: client.clone(), tmpl: tera.clone(), db: conn.clone(), - actix_admin: actix_admin_builder.get_actix_admin(), + actix_admin: actix_admin, }; App::new() diff --git a/src/routes/create_or_edit_get.rs b/src/routes/create_or_edit_get.rs index 03fe5f5..7af2187 100644 --- a/src/routes/create_or_edit_get.rs +++ b/src/routes/create_or_edit_get.rs @@ -75,7 +75,7 @@ async fn create_or_edit_get( let entities_per_page = params .entities_per_page .unwrap_or(DEFAULT_ENTITIES_PER_PAGE); - let render_partial = params.render_partial.unwrap_or(false); + let render_partial = req.headers().contains_key("HX-Target"); let search = params.search.clone().unwrap_or(String::new()); let sort_by = params .sort_by diff --git a/src/routes/delete.rs b/src/routes/delete.rs index b374ed5..7991dfc 100644 --- a/src/routes/delete.rs +++ b/src/routes/delete.rs @@ -129,7 +129,7 @@ pub async fn delete_many true => Ok(HttpResponse::SeeOther() .append_header(( header::LOCATION, - 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), + format!("/admin/{}/list?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()), diff --git a/src/routes/list.rs b/src/routes/list.rs index 23eaf10..bb06b56 100644 --- a/src/routes/list.rs +++ b/src/routes/list.rs @@ -71,7 +71,7 @@ pub async fn list( let entities_per_page = params .entities_per_page .unwrap_or(DEFAULT_ENTITIES_PER_PAGE); - let render_partial = params.render_partial.unwrap_or(false); + let render_partial = req.headers().contains_key("HX-Target"); let search = params.search.clone().unwrap_or(String::new()); let db = data.get_db(); diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 9ce55c9..d1e5713 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -27,7 +27,6 @@ use serde::{Deserialize}; pub struct Params { page: Option, entities_per_page: Option, - render_partial: Option, search: Option, sort_by: Option, sort_order: Option diff --git a/src/routes/show.rs b/src/routes/show.rs index 36ef033..9affa81 100644 --- a/src/routes/show.rs +++ b/src/routes/show.rs @@ -47,7 +47,7 @@ pub async fn show(sessio let entities_per_page = params .entities_per_page .unwrap_or(DEFAULT_ENTITIES_PER_PAGE); - let render_partial = params.render_partial.unwrap_or(false); + let render_partial = req.headers().contains_key("HX-Target"); let search = params.search.clone().unwrap_or(String::new()); 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); diff --git a/src/templates/create_or_edit.html b/src/templates/create_or_edit.html index 5834806..103fd8b 100644 --- a/src/templates/create_or_edit.html +++ b/src/templates/create_or_edit.html @@ -38,8 +38,7 @@ "entities_per_page" : "{{ entities_per_page }}", "search" : "{{ search }}", "sort_by" : "{{ sort_by }}", - "sort_order" : "{{ sort_order }}", - "render_partial" : "false", + "sort_order" : "{{ sort_order }}" "page" : "{{ page }}" }' hx-boost="true" hx-push-url="true" hx-indicator="#loading" class="button is-link is-light" href="{{ base_path }}/list"> diff --git a/src/templates/list.html b/src/templates/list.html index 67196b2..f80741b 100644 --- a/src/templates/list.html +++ b/src/templates/list.html @@ -29,8 +29,7 @@
+ hx-target="#{{ entity_name }}table" hx-trigger="reload_table from:#entities_per_page">
@@ -66,7 +65,7 @@
{% include "loader.html" %} + hx-target="#{{ entity_name }}table"> @@ -118,8 +117,7 @@ "entities_per_page" : "{{ entities_per_page }}", "search" : "{{ search }}", "sort_by" : "{{ sort_by }}", - "sort_order" : "{{ sort_order }}", - "render_partial" : "true" + "sort_order" : "{{ sort_order }}" }' hx-target="#content"> {{ entity.primary_key }} @@ -142,8 +140,7 @@ "entities_per_page" : "{{ entities_per_page }}", "search" : "{{ search }}", "sort_by" : "{{ sort_by }}", - "sort_order" : "{{ sort_order }}", - "render_partial" : "false" + "sort_order" : "{{ sort_order }}" }'> @@ -167,8 +164,7 @@ "entities_per_page" : "{{ entities_per_page }}", "search" : "{{ search }}", "sort_by" : "{{ sort_by }}", - "sort_order" : "{{ sort_order }}", - "render_partial" : "true" + "sort_order" : "{{ sort_order }}" }' hx-indicator="#loading" class="pagination is-rounded is-centered" role="pagination" aria-label="pagination"> {% if page > 1 %}
-{% if not render_partial or render_partial == false %} - -{% endif %} - {% endblock content %} \ No newline at end of file diff --git a/src/templates/show.html b/src/templates/show.html index 8ffcba7..d30e2d8 100644 --- a/src/templates/show.html +++ b/src/templates/show.html @@ -26,8 +26,7 @@ "entities_per_page" : "{{ entities_per_page }}", "search" : "{{ search }}", "sort_by" : "{{ sort_by }}", - "sort_order" : "{{ sort_order }}", - "render_partial" : "false", + "sort_order" : "{{ sort_order }}" "page" : "{{ page }}" }' hx-boost="true" hx-push-url="true" hx-indicator="#loading" class="button is-link is-light" href="{{ base_path }}/list">Back