add categories to group entities in a dropdown in the navbar

This commit is contained in:
manuel 2022-09-12 21:22:25 +02:00
parent 4fc35d0e97
commit f64a0a5003
5 changed files with 75 additions and 15 deletions

View File

@ -113,14 +113,17 @@ fn create_actix_admin_builder() -> ActixAdminBuilder {
}; };
let mut admin_builder = ActixAdminBuilder::new(configuration); let mut admin_builder = ActixAdminBuilder::new(configuration);
admin_builder.add_entity::<AppState, Post>(&post_view_model);
admin_builder.add_entity::<AppState, Comment>(&comment_view_model);
admin_builder.add_custom_handler_for_index::<AppState>( admin_builder.add_custom_handler_for_index::<AppState>(
web::get().to(custom_index::<AppState>) web::get().to(custom_index::<AppState>)
); );
admin_builder.add_custom_handler_for_entity::<AppState, Comment>( admin_builder.add_entity::<AppState, Post>(&post_view_model);
let some_category = "Some Category";
admin_builder.add_entity_to_category::<AppState, Comment>(&comment_view_model, some_category);
admin_builder.add_custom_handler_for_entity_in_category::<AppState, Comment>(
"/custom_handler", "/custom_handler",
web::get().to(custom_handler::<AppState, Comment>) web::get().to(custom_handler::<AppState, Comment>),
some_category
); );
admin_builder admin_builder

View File

@ -1,6 +1,5 @@
use actix_web::{ web, Route }; use actix_web::{ web, Route };
use std::collections::HashMap; use std::collections::HashMap;
use crate::prelude::*; use crate::prelude::*;
use crate::routes::{create_get, create_post, delete, delete_many, edit_get, edit_post, index, list, show}; use crate::routes::{create_get, create_post, delete, delete_many, edit_get, edit_post, index, list, show};
@ -19,11 +18,22 @@ pub trait ActixAdminBuilderTrait {
&mut self, &mut self,
view_model: &ActixAdminViewModel, view_model: &ActixAdminViewModel,
); );
fn add_entity_to_category<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>(
&mut self,
view_model: &ActixAdminViewModel,
category_name: &str
);
fn add_custom_handler_for_entity<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>( fn add_custom_handler_for_entity<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>(
&mut self, &mut self,
path: &str, path: &str,
route: Route route: Route
); );
fn add_custom_handler_for_entity_in_category<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>(
&mut self,
path: &str,
route: Route,
category_name: &str
);
fn add_custom_handler_for_index<T: ActixAdminAppDataTrait + 'static>( fn add_custom_handler_for_index<T: ActixAdminAppDataTrait + 'static>(
&mut self, &mut self,
route: Route route: Route
@ -36,7 +46,7 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
fn new(configuration: ActixAdminConfiguration) -> Self { fn new(configuration: ActixAdminConfiguration) -> Self {
ActixAdminBuilder { ActixAdminBuilder {
actix_admin: ActixAdmin { actix_admin: ActixAdmin {
entity_names: Vec::new(), entity_names: HashMap::new(),
view_models: HashMap::new(), view_models: HashMap::new(),
configuration: configuration configuration: configuration
}, },
@ -48,6 +58,14 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
fn add_entity<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>( fn add_entity<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>(
&mut self, &mut self,
view_model: &ActixAdminViewModel, view_model: &ActixAdminViewModel,
) {
let _ = &self.add_entity_to_category::<T, E>(view_model, "");
}
fn add_entity_to_category<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>(
&mut self,
view_model: &ActixAdminViewModel,
category_name: &str
) { ) {
self.scopes.insert( self.scopes.insert(
E::get_entity_name(), E::get_entity_name(),
@ -62,7 +80,16 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
.route("/show/{id}", web::get().to(show::<T, E>)) .route("/show/{id}", web::get().to(show::<T, E>))
); );
self.actix_admin.entity_names.push(E::get_entity_name()); let category = self.actix_admin.entity_names.get_mut(category_name);
match category {
Some(entity_list) => entity_list.push(E::get_entity_name()),
None => {
let mut entity_list = Vec::new();
entity_list.push(E::get_entity_name());
self.actix_admin.entity_names.insert(category_name.to_string(), entity_list);
}
}
let key = E::get_entity_name(); let key = E::get_entity_name();
self.actix_admin.view_models.insert(key, view_model.clone()); self.actix_admin.view_models.insert(key, view_model.clone());
} }
@ -78,6 +105,15 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
&mut self, &mut self,
path: &str, path: &str,
route: Route route: Route
) {
let _ = &self.add_custom_handler_for_entity_in_category::<T,E>(path, route, "");
}
fn add_custom_handler_for_entity_in_category<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>(
&mut self,
path: &str,
route: Route,
category_name: &str
) { ) {
let existing_scope = self.scopes.remove(&E::get_entity_name()); let existing_scope = self.scopes.remove(&E::get_entity_name());
match existing_scope { match existing_scope {
@ -93,8 +129,14 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
} }
} }
if !self.actix_admin.entity_names.contains(&E::get_entity_name()) { let category = self.actix_admin.entity_names.get_mut(category_name);
self.actix_admin.entity_names.push(E::get_entity_name()); match category {
Some(entity_list) => {
if !entity_list.contains(&E::get_entity_name()) {
entity_list.push(E::get_entity_name());
}
}
_ => (),
} }
} }
@ -104,7 +146,9 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
_ => web::get().to(index::<T>) _ => web::get().to(index::<T>)
}; };
let mut admin_scope = web::scope("/admin").route("/", index_handler); let mut admin_scope = web::scope("/admin").route("/", index_handler);
for entity_name in self.actix_admin.entity_names { let entities = self.actix_admin.entity_names.into_iter().map(|(_k, v)| v).flatten();
for entity_name in entities {
let scope = self.scopes.remove(&entity_name).unwrap(); let scope = self.scopes.remove(&entity_name).unwrap();
admin_scope = admin_scope.service(scope); admin_scope = admin_scope.service(scope);
} }

View File

@ -224,7 +224,7 @@ pub struct ActixAdminConfiguration {
#[derive(Clone)] #[derive(Clone)]
pub struct ActixAdmin { pub struct ActixAdmin {
pub entity_names: Vec<String>, pub entity_names: HashMap<String, Vec<String>>,
pub view_models: HashMap<String, ActixAdminViewModel>, pub view_models: HashMap<String, ActixAdminViewModel>,
pub configuration: ActixAdminConfiguration pub configuration: ActixAdminConfiguration
} }

View File

@ -13,10 +13,24 @@
<div id="navbarBasicExample" class="navbar-menu"> <div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start"> <div class="navbar-start">
{% for entity_name in entity_names -%} {% for category, entities in entity_names %}
<a href="/admin/{{ entity_name }}/list" class="navbar-item">{{ entity_name | title }}</a> {% if category == "" %}
{% for entity_name in entities %}
<a href="/admin/{{ entity_name }}/list" class="navbar-item">{{ entity_name | title }}</a>
{%- endfor %}
{% else %}
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">
{{ category }}
</a>
<div class="navbar-dropdown">
{% for entity_name in entities %}
<a href="/admin/{{ entity_name }}/list" class="navbar-item">{{ entity_name | title }}</a>
{%- endfor %}
</div>
</div>
{% endif %}
{%- endfor %} {%- endfor %}
</div> </div>
<div class="navbar-end"> <div class="navbar-end">

View File

@ -87,7 +87,6 @@ async fn edit_post_from_plaintext<
text: String, text: String,
id: web::Path<i32>, id: web::Path<i32>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
println!("ok");
let model = ActixAdminModel::from(text); let model = ActixAdminModel::from(text);
create_or_edit_post::<T, E>(&session, &data, model, Some(id.into_inner())).await create_or_edit_post::<T, E>(&session, &data, model, Some(id.into_inner())).await
} }