code: basic create view and HX-Header integration (first htmx)
This commit is contained in:
@@ -200,8 +200,8 @@ pub mod repository {
|
||||
fn info(&self, model: &AdminModel) -> RepositoryInfo;
|
||||
fn list(&self, model: &AdminModel) -> RepositoryList;
|
||||
fn get(&self, model: &AdminModel, id: LookupKey) -> Option<RepositoryItem>;
|
||||
fn create(&self, model: &AdminModel, data: Value) -> Option<Value>;
|
||||
fn update(&self, model: &AdminModel, id: LookupKey, data: Value) -> Option<Value>;
|
||||
fn create(&self, model: &AdminModel, data: Value) -> Option<RepositoryItem>;
|
||||
fn update(&self, model: &AdminModel, id: LookupKey, data: Value) -> Option<RepositoryItem>;
|
||||
fn delete(&self, model: &AdminModel, id: LookupKey) -> Option<Value>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,12 +75,12 @@ impl AdminRepository for MyStaticRepository {
|
||||
.into()
|
||||
}
|
||||
|
||||
fn create(&self, model: &AdminModel, data: Value) -> Option<Value> {
|
||||
fn create(&self, model: &AdminModel, data: Value) -> Option<RepositoryItem> {
|
||||
println!("I would now create: {}", data);
|
||||
None
|
||||
}
|
||||
|
||||
fn update(&self, model: &AdminModel, id: LookupKey, data: Value) -> Option<Value> {
|
||||
fn update(&self, model: &AdminModel, id: LookupKey, data: Value) -> Option<RepositoryItem> {
|
||||
println!("I would now update: {}, {}", id, data);
|
||||
None
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use axum::{routing::get, Router};
|
||||
use axum::{routing::get, routing::post, Router};
|
||||
|
||||
use crate::state::AppState;
|
||||
|
||||
@@ -12,7 +12,10 @@ pub fn routes() -> Router<AppState> {
|
||||
.route("/", get(views::index).post(views::index_action))
|
||||
.route("/app/:app", get(views::list_app))
|
||||
.route("/app/:app/model/:model", get(views::list_item_collection))
|
||||
.route("/app/:app/model/:model/add", get(views::create_item))
|
||||
.route(
|
||||
"/app/:app/model/:model/add",
|
||||
get(views::new_item).post(views::create_item),
|
||||
)
|
||||
.route(
|
||||
"/app/:app/model/:model/detail/:id",
|
||||
get(views::item_details),
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
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;
|
||||
@@ -18,6 +21,7 @@ pub struct AdminRequest {
|
||||
|
||||
#[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
|
||||
@@ -40,6 +44,7 @@ pub struct AdminContext {
|
||||
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
|
||||
@@ -62,13 +67,25 @@ impl Default for AdminContext {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base_template(headers: &HeaderMap) -> Option<String> {
|
||||
let hx_request = headers.get("HX-Request").is_some();
|
||||
if hx_request {
|
||||
println!("HX.");
|
||||
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()
|
||||
},
|
||||
@@ -91,9 +108,11 @@ pub async fn list_app(
|
||||
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 admin_model = registry
|
||||
.get_model(&app_key, &model_key)
|
||||
@@ -101,8 +120,8 @@ pub async fn list_item_collection(
|
||||
// Note: AdminModel contains Registry Data, while Repository only contains user data; however, both could be retrieved more reliably from each other.
|
||||
// Another solution would be a clear "AdminRepositoryContext", that contains information about the current model.
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
content: model_key.to_owned(),
|
||||
item_info: Some(repo.info(&admin_model)),
|
||||
item_list: repo.list(&admin_model),
|
||||
item_model: Some(admin_model),
|
||||
@@ -110,6 +129,7 @@ pub async fn list_item_collection(
|
||||
}
|
||||
} else {
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
..Default::default()
|
||||
}
|
||||
@@ -128,6 +148,7 @@ pub async fn item_collection_action(
|
||||
pub async fn 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) {
|
||||
@@ -138,8 +159,8 @@ pub async fn item_details(
|
||||
// Another solution would be a clear "AdminRepositoryContext", that contains information about the current model.
|
||||
let key: LookupKey = id.into();
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
content: model_key.to_owned(),
|
||||
item_info: Some(repo.info(&admin_model)),
|
||||
item_list: repo.list(&admin_model),
|
||||
item: repo.get(&admin_model, key),
|
||||
@@ -148,6 +169,7 @@ pub async fn item_details(
|
||||
}
|
||||
} else {
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
..Default::default()
|
||||
}
|
||||
@@ -155,9 +177,10 @@ pub async fn item_details(
|
||||
templates.render_html("admin/items/item_detail.jinja", context)
|
||||
}
|
||||
|
||||
pub async fn create_item(
|
||||
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) {
|
||||
@@ -165,8 +188,8 @@ pub async fn create_item(
|
||||
.get_model(&app_key, &model_key)
|
||||
.expect("Admin Model not found?");
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
content: model_key.to_owned(),
|
||||
item_info: Some(repo.info(&admin_model)),
|
||||
item_list: repo.list(&admin_model),
|
||||
item_model: Some(admin_model),
|
||||
@@ -174,6 +197,42 @@ pub async fn create_item(
|
||||
}
|
||||
} 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 admin_model = registry
|
||||
.get_model(&app_key, &model_key)
|
||||
.expect("Admin Model not found?");
|
||||
|
||||
// create our item.
|
||||
let result = repo.create(&admin_model, form);
|
||||
|
||||
// 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)),
|
||||
item_list: repo.list(&admin_model),
|
||||
item_model: Some(admin_model),
|
||||
item: result,
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
AdminContext {
|
||||
base: base_template(&headers),
|
||||
available_apps: registry.get_apps(),
|
||||
..Default::default()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user