refactor: starting refactor to extract into rear crate
This commit is contained in:
@@ -0,0 +1,319 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::extract::Path;
|
||||
use axum::http::HeaderMap;
|
||||
use axum::Form;
|
||||
use axum::{extract::State, response::IntoResponse};
|
||||
use log::info;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::admin::domain::{AdminApp, AdminModel};
|
||||
use crate::admin::state;
|
||||
use crate::service::templates;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::domain::{LookupKey, RepositoryInfo, RepositoryItem, RepositoryList};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AdminRequest {
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct AdminContext {
|
||||
pub base: Option<String>,
|
||||
pub language_code: Option<String>,
|
||||
pub language_bidi: Option<bool>,
|
||||
pub user: Option<String>, // Todo: user type
|
||||
pub admin_url: String,
|
||||
pub site_url: Option<String>,
|
||||
pub docsroot: Option<String>,
|
||||
pub messages: Vec<String>, // Todo: message type
|
||||
pub title: Option<String>,
|
||||
pub subtitle: Option<String>,
|
||||
pub content: String,
|
||||
|
||||
pub request: AdminRequest,
|
||||
pub available_apps: Vec<AdminApp>,
|
||||
pub item_model: Option<AdminModel>,
|
||||
pub item_info: Option<RepositoryInfo>,
|
||||
pub item_list: RepositoryList,
|
||||
pub item: Option<RepositoryItem>,
|
||||
}
|
||||
|
||||
impl Default for AdminContext {
|
||||
fn default() -> Self {
|
||||
AdminContext {
|
||||
base: None,
|
||||
language_code: Some("en-us".to_string()), // Default language code
|
||||
language_bidi: Some(false), // Default language bidi
|
||||
user: None, //UserType::default(), // Assuming UserType has a Default impl
|
||||
admin_url: "/admin".to_owned(),
|
||||
site_url: None,
|
||||
docsroot: None,
|
||||
messages: Vec::new(), // Empty vector for messages
|
||||
title: None,
|
||||
subtitle: None,
|
||||
content: String::new(), // Empty string for content
|
||||
available_apps: Vec::new(),
|
||||
request: AdminRequest {
|
||||
path: "".to_owned(),
|
||||
},
|
||||
item_model: None,
|
||||
item_info: None,
|
||||
item_list: RepositoryList::Empty,
|
||||
item: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base_template(headers: &HeaderMap) -> Option<String> {
|
||||
let hx_request = headers.get("HX-Request").is_some();
|
||||
if hx_request {
|
||||
Some("admin/base_hx.jinja".to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn index(
|
||||
templates: State<templates::Templates>,
|
||||
registry: State<Arc<state::AdminRegistry>>,
|
||||
headers: HeaderMap,
|
||||
) -> impl IntoResponse {
|
||||
templates.render_html(
|
||||
"admin/index.html",
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Index Action is POST to the index site. We can anchor some general business code here.
|
||||
pub async fn index_action() -> impl IntoResponse {
|
||||
"There is your answer!".to_owned()
|
||||
}
|
||||
|
||||
pub async fn list_app(
|
||||
templates: State<templates::Templates>,
|
||||
Path(app_key): Path<String>,
|
||||
) -> impl IntoResponse {
|
||||
templates.render_html("admin/app_list.jinja", ())
|
||||
}
|
||||
|
||||
// List Items renders the entire list item page.
|
||||
pub async fn list_item_collection(
|
||||
templates: State<templates::Templates>,
|
||||
registry: State<Arc<state::AdminRegistry>>,
|
||||
headers: HeaderMap,
|
||||
Path((app_key, model_key)): Path<(String, String)>,
|
||||
) -> impl IntoResponse {
|
||||
info!("list_item_collection {} for model {}", app_key, model_key);
|
||||
|
||||
let context = if let Ok(repo) = registry.get_repository(&app_key, &model_key) {
|
||||
let repo = repo.lock().await;
|
||||
let admin_model = registry
|
||||
.get_model(&app_key, &model_key)
|
||||
.expect("Admin Model not found?");
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
item_info: Some(repo.info(&admin_model).await),
|
||||
item_list: repo.list(&admin_model).await,
|
||||
item_model: Some(admin_model),
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
..Default::default()
|
||||
}
|
||||
};
|
||||
templates.render_html("admin/items/item_list.jinja", context)
|
||||
}
|
||||
|
||||
// Items Action is a POST to an item list. By default these are actions, that work on a list of items as input.
|
||||
pub async fn item_collection_action(
|
||||
Path((app_key, model_key)): Path<(String, String)>,
|
||||
) -> impl IntoResponse {
|
||||
"There is your answer!".to_owned()
|
||||
}
|
||||
|
||||
// Item Details shows one single dataset.
|
||||
pub async fn view_item_details(
|
||||
templates: State<templates::Templates>,
|
||||
registry: State<Arc<state::AdminRegistry>>,
|
||||
headers: HeaderMap,
|
||||
Path((app_key, model_key, id)): Path<(String, String, String)>,
|
||||
) -> impl IntoResponse {
|
||||
let context = if let Ok(repo) = registry.get_repository(&app_key, &model_key) {
|
||||
let repo = repo.lock().await;
|
||||
let admin_model = registry
|
||||
.get_model(&app_key, &model_key)
|
||||
.expect("Admin Model not found?");
|
||||
let key: LookupKey = id.into();
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
item_info: Some(repo.info(&admin_model).await),
|
||||
item_list: repo.list(&admin_model).await,
|
||||
item: repo.get(&admin_model, key).await,
|
||||
item_model: Some(admin_model),
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
..Default::default()
|
||||
}
|
||||
};
|
||||
templates.render_html("admin/items/item_detail.jinja", context)
|
||||
}
|
||||
|
||||
pub async fn new_item(
|
||||
templates: State<templates::Templates>,
|
||||
registry: State<Arc<state::AdminRegistry>>,
|
||||
headers: HeaderMap,
|
||||
Path((app_key, model_key)): Path<(String, String)>,
|
||||
) -> impl IntoResponse {
|
||||
let context = if let Ok(repo) = registry.get_repository(&app_key, &model_key) {
|
||||
let repo = repo.lock().await;
|
||||
let admin_model = registry
|
||||
.get_model(&app_key, &model_key)
|
||||
.expect("Admin Model not found?");
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
item_info: Some(repo.info(&admin_model).await),
|
||||
item_list: repo.list(&admin_model).await,
|
||||
item_model: Some(admin_model),
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
..Default::default()
|
||||
}
|
||||
};
|
||||
templates.render_html("admin/items/item_create.jinja", context)
|
||||
}
|
||||
|
||||
pub async fn create_item(
|
||||
templates: State<templates::Templates>,
|
||||
registry: State<Arc<state::AdminRegistry>>,
|
||||
headers: HeaderMap,
|
||||
Path((app_key, model_key)): Path<(String, String)>,
|
||||
Form(form): Form<Value>,
|
||||
) -> impl IntoResponse {
|
||||
let context = if let Ok(repo) = registry.get_repository(&app_key, &model_key) {
|
||||
let mut repo = repo.lock().await;
|
||||
let admin_model = registry
|
||||
.get_model(&app_key, &model_key)
|
||||
.expect("Admin Model not found?");
|
||||
|
||||
// create our item.
|
||||
let result = repo.create(&admin_model, form).await;
|
||||
|
||||
// TODO: refactor run over these views, way too much repetition.
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
item_info: Some(repo.info(&admin_model).await),
|
||||
item_list: repo.list(&admin_model).await,
|
||||
item_model: Some(admin_model),
|
||||
item: result,
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
..Default::default()
|
||||
}
|
||||
};
|
||||
templates.render_html("admin/items/item_create.jinja", context)
|
||||
}
|
||||
|
||||
/// Change is the GET version.
|
||||
pub async fn change_item(
|
||||
templates: State<templates::Templates>,
|
||||
registry: State<Arc<state::AdminRegistry>>,
|
||||
headers: HeaderMap,
|
||||
Path((app_key, model_key, id)): Path<(String, String, String)>,
|
||||
) -> impl IntoResponse {
|
||||
let context = if let Ok(repo) = registry.get_repository(&app_key, &model_key) {
|
||||
let repo = repo.lock().await;
|
||||
let admin_model = registry
|
||||
.get_model(&app_key, &model_key)
|
||||
.expect("Admin Model not found?");
|
||||
let key: LookupKey = id.into();
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
item_info: Some(repo.info(&admin_model).await),
|
||||
item_list: repo.list(&admin_model).await,
|
||||
item: repo.get(&admin_model, key).await,
|
||||
item_model: Some(admin_model),
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
..Default::default()
|
||||
}
|
||||
};
|
||||
templates.render_html("admin/items/item_change.jinja", context)
|
||||
}
|
||||
|
||||
pub async fn update_item(
|
||||
templates: State<templates::Templates>,
|
||||
registry: State<Arc<state::AdminRegistry>>,
|
||||
headers: HeaderMap,
|
||||
Path((app_key, model_key, id)): Path<(String, String, String)>,
|
||||
Form(form): Form<Value>,
|
||||
) -> impl IntoResponse {
|
||||
let context = if let Ok(repo) = registry.get_repository(&app_key, &model_key) {
|
||||
let mut repo = repo.lock().await;
|
||||
let admin_model = registry
|
||||
.get_model(&app_key, &model_key)
|
||||
.expect("Admin Model not found?");
|
||||
let key: LookupKey = id.into();
|
||||
|
||||
let result = repo.update(&admin_model, key, form).await;
|
||||
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
item_info: Some(repo.info(&admin_model).await),
|
||||
item_list: repo.list(&admin_model).await,
|
||||
item: result,
|
||||
item_model: Some(admin_model),
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
..Default::default()
|
||||
}
|
||||
};
|
||||
templates.render_html("admin/items/item_change.jinja", context)
|
||||
}
|
||||
|
||||
// Item Action allows running an action on one single dataset.
|
||||
pub async fn item_action(
|
||||
Path((app_key, model_key, model_id)): Path<(String, String, String)>,
|
||||
) -> impl IntoResponse {
|
||||
"There is your answer!".to_owned()
|
||||
}
|
||||
|
||||
pub async fn debug_view(Path(data): Path<String>) -> impl IntoResponse {
|
||||
println!("debug: {}", data);
|
||||
"Debug!".to_owned()
|
||||
}
|
||||
Reference in New Issue
Block a user