miniweb/src/admin/views.rs

153 lines
4.7 KiB
Rust

use std::sync::Arc;
use axum::extract::Path;
use axum::{extract::State, response::IntoResponse, Form};
use log::info;
use crate::admin::domain::{AdminApp, AdminModel};
use crate::admin::state;
use crate::service::templates;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use super::domain::{RepositoryInfo, RepositoryList};
#[derive(Deserialize)]
pub struct Question {
question: String,
}
#[derive(Deserialize)]
pub struct ExampleData {
title: String,
content: String,
}
#[derive(Serialize, Deserialize)]
pub struct AdminRequest {
pub path: String,
}
#[derive(Serialize)]
pub struct AdminContext {
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_info: Option<RepositoryInfo>,
pub item_list: RepositoryList,
pub item: Option<Value>,
}
impl Default for AdminContext {
fn default() -> Self {
AdminContext {
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_info: None,
item_list: RepositoryList::Empty,
item: None,
}
}
}
pub async fn index(
templates: State<templates::Templates>,
registry: State<Arc<state::AdminRegistry>>,
) -> impl IntoResponse {
templates.render_html(
"admin/index.html",
AdminContext {
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(Form(example_data): Form<ExampleData>) -> 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>>,
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(&model_key) {
// we should consider using Vec<Value> instead in get_list.
AdminContext {
available_apps: registry.get_apps(),
content: model_key.to_owned(),
item_info: Some(repo.get_repo_info()),
item_list: repo.get_list(),
..Default::default()
}
} else {
AdminContext {
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(
Form(question): Form<Question>,
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 item_details(
templates: State<templates::Templates>,
Path((app_key, model_key, id)): Path<(String, String, String)>,
) -> impl IntoResponse {
templates.render_html("admin/items/item_detail.jinja", ())
}
// Item Action allows running an action on one single dataset.
pub async fn item_action(
Form(question): Form<Question>,
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()
}