code: moving static example into a repository, and implementing app/model listing.

This commit is contained in:
Gabor Körber 2024-01-04 17:51:08 +01:00
parent eef65cfdd0
commit 94845ecb0e
6 changed files with 74 additions and 56 deletions

View File

@ -130,3 +130,8 @@ As I started by quickly using a django admin template with CSS to jump start the
| object_name\|lower | key, app_key, model_key | | | object_name\|lower | key, app_key, model_key | |
| app_label | key, app_key | | | app_label | key, app_key | |
### Next Steps:
- implement views for app
- implement a static implementation for repository

36
src/admin/example.rs Normal file
View File

@ -0,0 +1,36 @@
// implementation of static repository
use super::state::{config::AdminModelConfig, AdminRegistry, AdminRepository};
use serde_json::{json, Value};
struct MyStaticRepository {}
impl AdminRepository for MyStaticRepository {
fn get_item(&self, id: usize) -> Option<Value> {
Some(json!({
"name": "Adam",
"age": id,
}))
}
fn get_list(&self) -> Value {
json!([
{"name": "Strange", "age": 150 },
{"name": "Adam", "age": 12}
])
}
}
pub fn register_example(registry: &mut AdminRegistry) {
let app_key = registry.register_app("Example App");
let repo = MyStaticRepository {};
let model_config = AdminModelConfig {
app_key: app_key,
name: "ExampleModel".to_owned(),
};
let model_result = registry.register_model(model_config, repo);
match model_result {
Err(err) => panic!("{}", err),
_ => (),
}
}

View File

@ -3,6 +3,7 @@ use axum::{routing::get, Router};
use crate::state::AppState; use crate::state::AppState;
pub mod domain; pub mod domain;
pub mod example;
pub mod state; pub mod state;
pub mod views; pub mod views;

View File

@ -36,32 +36,48 @@ impl AdminRegistry {
.collect() .collect()
} }
fn get_app(&self, name: &str, node: &internal::AdminApp) -> AdminApp { fn get_app(&self, key: &str, node: &internal::AdminApp) -> AdminApp {
let my_models = self.get_models(key);
AdminApp { AdminApp {
name: name.to_owned(), name: key.to_owned(),
key: node.key.to_owned(), key: node.name.to_owned(),
app_url: name.to_owned().to_lowercase(), app_url: key.to_owned(),
models: vec![], models: my_models,
} }
} }
pub fn register_app(&mut self, name: &str, app_label: &str, app_url: &str) { pub fn register_app(&mut self, name: &str) -> String {
let key = self.get_key(name); let key = self.get_key(name);
self.apps.insert( self.apps.insert(
key.to_owned(), key.to_owned(),
internal::AdminApp { internal::AdminApp {
key: key, key: key.to_owned(),
name: name.to_owned(), name: name.to_owned(),
}, },
); );
key
} }
fn get_key(&self, name: &str) -> String { fn get_key(&self, name: &str) -> String {
slug::slugify(name) slug::slugify(name)
} }
fn model_from_internal(&self, internal_model: &internal::AdminModel) -> AdminModel {
AdminModel {
key: internal_model.model_key.clone(),
name: internal_model.model_key.clone(),
admin_url: "".to_owned(),
view_only: false,
add_url: None,
}
}
pub fn get_models(&self, app_key: &str) -> Vec<AdminModel> { pub fn get_models(&self, app_key: &str) -> Vec<AdminModel> {
vec![] self.models
.iter()
.filter(|(key, _)| key.starts_with(&format!("{}.", app_key)))
.map(|(_, model)| self.model_from_internal(model))
.collect()
} }
pub fn get_model(&self, app_key: &str, model_key: &str) -> Option<AdminModel> { pub fn get_model(&self, app_key: &str, model_key: &str) -> Option<AdminModel> {
@ -69,13 +85,7 @@ impl AdminRegistry {
let internal_model = self.models.get(&full_model_key)?; let internal_model = self.models.get(&full_model_key)?;
// unfinished: we need to think about model_key vs. model_id vs. entry_id, as "name" is ambiguous. // unfinished: we need to think about model_key vs. model_id vs. entry_id, as "name" is ambiguous.
Some(AdminModel { Some(self.model_from_internal(internal_model))
key: internal_model.model_key.clone(),
name: internal_model.model_key.clone(),
admin_url: "".to_owned(),
view_only: false,
add_url: None,
})
} }
fn register_model_config(&mut self, model: config::AdminModelConfig) -> Result<String, String> { fn register_model_config(&mut self, model: config::AdminModelConfig) -> Result<String, String> {
@ -87,10 +97,9 @@ impl AdminRegistry {
if self.models.contains_key(&local_config_name) { if self.models.contains_key(&local_config_name) {
return Err(format!("Model {} already exists", local_config_name)); return Err(format!("Model {} already exists", local_config_name));
} }
if let Some(local_config) = self.models.insert(local_config_name, local_config) { let model_key = local_config.model_key.clone();
return Ok(local_config.model_key); self.models.insert(local_config_name, local_config);
} Ok(model_key)
Err("Model could not be added!".to_owned())
} }
pub fn register_model<R: AdminRepository + 'static>( pub fn register_model<R: AdminRepository + 'static>(

View File

@ -62,45 +62,12 @@ impl Default for AdminContext {
pub async fn index( pub async fn index(
templates: State<templates::Templates>, templates: State<templates::Templates>,
administration: State<Arc<state::AdminRegistry>>, registry: State<Arc<state::AdminRegistry>>,
) -> impl IntoResponse { ) -> impl IntoResponse {
let models = vec![
AdminModel {
name: "User".to_owned(),
key: "user".to_owned(),
admin_url: "/admin/app/users/user".to_owned(),
view_only: false,
add_url: Some("/admin/users/user/add".to_owned()),
},
AdminModel {
name: "Group".to_owned(),
key: "group".to_owned(),
admin_url: "/admin/users/group".to_owned(),
view_only: false,
add_url: None,
},
AdminModel {
name: "Permission".to_owned(),
key: "permission".to_owned(),
admin_url: "/admin/users/permission".to_owned(),
view_only: true,
add_url: None,
},
];
let core_app = AdminApp {
name: "Admin".to_owned(),
key: "admin".to_owned(),
app_url: "/admin/users/".to_owned(),
models: models,
};
let mut available = vec![core_app];
available.extend(administration.get_apps());
templates.render_html( templates.render_html(
"admin/index.html", "admin/index.html",
AdminContext { AdminContext {
available_apps: available, available_apps: registry.get_apps(),
..Default::default() ..Default::default()
}, },
) )

View File

@ -3,6 +3,7 @@ mod howto;
mod service; mod service;
mod state; mod state;
use crate::admin::example;
use crate::service::{handlers, templates}; use crate::service::{handlers, templates};
use crate::state::AppState; use crate::state::AppState;
use axum::{ use axum::{
@ -32,8 +33,7 @@ async fn main() {
// Prepare App State // Prepare App State
let tmpl = templates::Templates::initialize().expect("Template Engine could not be loaded."); let tmpl = templates::Templates::initialize().expect("Template Engine could not be loaded.");
let mut admin = admin::state::AdminRegistry::new("admin"); let mut admin = admin::state::AdminRegistry::new("admin");
admin.register_app("auth", "Authorities", "auth"); example::register_example(&mut admin);
//let admin_router = admin.generate_router();
let state: AppState = AppState { let state: AppState = AppState {
templates: tmpl, templates: tmpl,