refactor menu element to allow adding arbitrary elements to the navbar

This commit is contained in:
Manuel Gugger 2022-09-29 16:23:49 +02:00
parent 5729ecee29
commit 0b293b5807
5 changed files with 56 additions and 19 deletions

View File

@ -121,6 +121,7 @@ fn create_actix_admin_builder() -> ActixAdminBuilder {
let some_category = "Some Category"; let some_category = "Some Category";
admin_builder.add_entity_to_category::<AppState, Comment>(&comment_view_model, 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>( admin_builder.add_custom_handler_for_entity_in_category::<AppState, Comment>(
"My custom handler",
"/custom_handler", "/custom_handler",
web::get().to(custom_handler::<AppState, Comment>), web::get().to(custom_handler::<AppState, Comment>),
some_category some_category

View File

@ -1,6 +1,6 @@
use actix_web::{ web, Route }; use actix_web::{ web, Route };
use std::collections::HashMap; use std::collections::HashMap;
use crate::prelude::*; use crate::{prelude::*, ActixAdminMenuElement};
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};
@ -25,11 +25,13 @@ pub trait ActixAdminBuilderTrait {
); );
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,
menu_element_name: &str,
path: &str, path: &str,
route: Route route: Route
); );
fn add_custom_handler_for_entity_in_category<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>( fn add_custom_handler_for_entity_in_category<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>(
&mut self, &mut self,
menu_element_name: &str,
path: &str, path: &str,
route: Route, route: Route,
category_name: &str category_name: &str
@ -81,11 +83,18 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
); );
let category = self.actix_admin.entity_names.get_mut(category_name); let category = self.actix_admin.entity_names.get_mut(category_name);
let menu_element = ActixAdminMenuElement {
name: E::get_entity_name(),
link: E::get_entity_name(),
is_custom_handler: false
};
match category { match category {
Some(entity_list) => entity_list.push(E::get_entity_name()), Some(entity_list) => {
entity_list.push(menu_element)
},
None => { None => {
let mut entity_list = Vec::new(); let mut entity_list = Vec::new();
entity_list.push(E::get_entity_name()); entity_list.push(menu_element);
self.actix_admin.entity_names.insert(category_name.to_string(), entity_list); self.actix_admin.entity_names.insert(category_name.to_string(), entity_list);
} }
} }
@ -103,53 +112,60 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
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,
menu_element_name: &str,
path: &str, path: &str,
route: Route route: Route
) { ) {
let _ = &self.add_custom_handler_for_entity_in_category::<T,E>(path, route, ""); let _ = &self.add_custom_handler_for_entity_in_category::<T,E>(menu_element_name ,path, route, "");
} }
fn add_custom_handler_for_entity_in_category<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>( fn add_custom_handler_for_entity_in_category<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>(
&mut self, &mut self,
menu_element_name: &str,
path: &str, path: &str,
route: Route, route: Route,
category_name: &str category_name: &str
) { ) {
let menu_element = ActixAdminMenuElement {
name: menu_element_name.to_string(),
link: format!("{}{}", E::get_entity_name(), path),
is_custom_handler: true
};
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 {
Some(scope) => { Some(scope) => {
let existing_scope = scope.route(path, route); let existing_scope = scope.route(path, route);
self.scopes.insert(E::get_entity_name(), existing_scope); self.scopes.insert(menu_element.link.to_string(), existing_scope);
}, },
_ => { _ => {
let new_scope = let new_scope =
web::scope(&format!("/{}", E::get_entity_name())) web::scope(&format!("/{}", E::get_entity_name()))
.route(path, route); .route(path, route);
self.scopes.insert(E::get_entity_name(), new_scope); self.scopes.insert(menu_element.link.to_string(), new_scope);
} }
} }
let category = self.actix_admin.entity_names.get_mut(category_name); let category = self.actix_admin.entity_names.get_mut(category_name);
match category { match category {
Some(entity_list) => { Some(entity_list) => {
if !entity_list.contains(&E::get_entity_name()) { if !entity_list.contains(&menu_element) {
entity_list.push(E::get_entity_name()); entity_list.push(menu_element);
} }
} }
_ => (), _ => (),
} }
} }
fn get_scope<T: ActixAdminAppDataTrait + 'static>(mut self) -> actix_web::Scope { fn get_scope<T: ActixAdminAppDataTrait + 'static>(self) -> actix_web::Scope {
let index_handler = match self.custom_index { let index_handler = match self.custom_index {
Some(handler) => handler, Some(handler) => handler,
_ => 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);
let entities = self.actix_admin.entity_names.into_iter().map(|(_k, v)| v).flatten();
for entity_name in entities { for (_entity, scope) in self.scopes {
let scope = self.scopes.remove(&entity_name).unwrap();
admin_scope = admin_scope.service(scope); admin_scope = admin_scope.service(scope);
} }

View File

@ -116,6 +116,7 @@
use lazy_static::lazy_static; use lazy_static::lazy_static;
use sea_orm::DatabaseConnection; use sea_orm::DatabaseConnection;
use serde::Serialize;
use std::collections::HashMap; use std::collections::HashMap;
use tera::{Tera, Result, to_value, try_get_value }; use tera::{Tera, Result, to_value, try_get_value };
use std::{ hash::BuildHasher}; use std::{ hash::BuildHasher};
@ -224,7 +225,14 @@ pub struct ActixAdminConfiguration {
#[derive(Clone)] #[derive(Clone)]
pub struct ActixAdmin { pub struct ActixAdmin {
pub entity_names: HashMap<String, Vec<String>>, pub entity_names: HashMap<String, Vec<ActixAdminMenuElement>>,
pub view_models: HashMap<String, ActixAdminViewModel>, pub view_models: HashMap<String, ActixAdminViewModel>,
pub configuration: ActixAdminConfiguration pub configuration: ActixAdminConfiguration
} }
#[derive(PartialEq, Eq, Clone, Serialize)]
pub struct ActixAdminMenuElement {
pub name: String,
pub link: String,
pub is_custom_handler: bool
}

View File

@ -15,8 +15,12 @@
<div class="navbar-start"> <div class="navbar-start">
{% for category, entities in entity_names %} {% for category, entities in entity_names %}
{% if category == "" %} {% if category == "" %}
{% for name in entities %} {% for menu_element in entities %}
<a href="/admin/{{ name }}/list" class="navbar-item {% if entity_name and entity_name == name %}is-active{% endif %}">{{ name | title }}</a> {% if menu_element.is_custom_handler %}
<a href="/admin/{{ menu_element.link }}" class="navbar-item {% if entity_name and entity_name == menu_element.name %}is-active{% endif %}">{{ menu_element.name }}</a>
{% else %}
<a href="/admin/{{ menu_element.link }}/list" class="navbar-item {% if entity_name and entity_name == menu_element.name %}is-active{% endif %}">{{ menu_element.name | title }}</a>
{% endif %}
{%- endfor %} {%- endfor %}
{% else %} {% else %}
<div class="navbar-item has-dropdown is-hoverable"> <div class="navbar-item has-dropdown is-hoverable">
@ -24,8 +28,12 @@
{{ category }} {{ category }}
</a> </a>
<div class="navbar-dropdown"> <div class="navbar-dropdown">
{% for name in entities %} {% for menu_element in entities %}
<a href="/admin/{{ name }}/list" class="navbar-item {% if entity_name and entity_name == name %}is-active{% endif %}">{{ name | title }}</a> {% if menu_element.is_custom_handler %}
<a href="/admin/{{ menu_element.link }}" class="navbar-item {% if entity_name and entity_name == menu_element.name %}is-active{% endif %}">{{ menu_element.name }}</a>
{% else %}
<a href="/admin/{{ menu_element.link }}/list" class="navbar-item {% if entity_name and entity_name == menu_element.name %}is-active{% endif %}">{{ menu_element.name | title }}</a>
{% endif %}
{%- endfor %} {%- endfor %}
</div> </div>
</div> </div>

View File

@ -48,18 +48,22 @@ pub fn create_actix_admin_builder() -> ActixAdminBuilder {
admin_builder.add_entity::<AppState, Comment>(&comment_view_model); admin_builder.add_entity::<AppState, Comment>(&comment_view_model);
admin_builder.add_custom_handler_for_entity::<AppState, Comment>( admin_builder.add_custom_handler_for_entity::<AppState, Comment>(
"Create Post From Plaintext",
"/create_post_from_plaintext", "/create_post_from_plaintext",
web::post().to(create_post_from_plaintext::<AppState, Comment>)); web::post().to(create_post_from_plaintext::<AppState, Comment>));
admin_builder.add_custom_handler_for_entity::<AppState, Post>( admin_builder.add_custom_handler_for_entity::<AppState, Post>(
"Create Post From Plaintext",
"/create_post_from_plaintext", "/create_post_from_plaintext",
web::post().to(create_post_from_plaintext::<AppState, Post>)); web::post().to(create_post_from_plaintext::<AppState, Post>));
admin_builder.add_custom_handler_for_entity::<AppState, Post>( admin_builder.add_custom_handler_for_entity::<AppState, Post>(
"Create Post From Plaintext",
"/edit_post_from_plaintext/{id}", "/edit_post_from_plaintext/{id}",
web::post().to(edit_post_from_plaintext::<AppState, Post>)); web::post().to(edit_post_from_plaintext::<AppState, Post>));
admin_builder.add_custom_handler_for_entity::<AppState, Comment>( admin_builder.add_custom_handler_for_entity::<AppState, Comment>(
"Create Post From Plaintext",
"/edit_post_from_plaintext/{id}", "/edit_post_from_plaintext/{id}",
web::post().to(edit_post_from_plaintext::<AppState, Comment>)); web::post().to(edit_post_from_plaintext::<AppState, Comment>));