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 | |
| 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;
pub mod domain;
pub mod example;
pub mod state;
pub mod views;

View File

@ -36,32 +36,48 @@ impl AdminRegistry {
.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 {
name: name.to_owned(),
key: node.key.to_owned(),
app_url: name.to_owned().to_lowercase(),
models: vec![],
name: key.to_owned(),
key: node.name.to_owned(),
app_url: key.to_owned(),
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);
self.apps.insert(
key.to_owned(),
internal::AdminApp {
key: key,
key: key.to_owned(),
name: name.to_owned(),
},
);
key
}
fn get_key(&self, name: &str) -> String {
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> {
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> {
@ -69,13 +85,7 @@ impl AdminRegistry {
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.
Some(AdminModel {
key: internal_model.model_key.clone(),
name: internal_model.model_key.clone(),
admin_url: "".to_owned(),
view_only: false,
add_url: None,
})
Some(self.model_from_internal(internal_model))
}
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) {
return Err(format!("Model {} already exists", local_config_name));
}
if let Some(local_config) = self.models.insert(local_config_name, local_config) {
return Ok(local_config.model_key);
}
Err("Model could not be added!".to_owned())
let model_key = local_config.model_key.clone();
self.models.insert(local_config_name, local_config);
Ok(model_key)
}
pub fn register_model<R: AdminRepository + 'static>(

View File

@ -62,45 +62,12 @@ impl Default for AdminContext {
pub async fn index(
templates: State<templates::Templates>,
administration: State<Arc<state::AdminRegistry>>,
registry: State<Arc<state::AdminRegistry>>,
) -> 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(
"admin/index.html",
AdminContext {
available_apps: available,
available_apps: registry.get_apps(),
..Default::default()
},
)

View File

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