add dropdown for enums
This commit is contained in:
parent
2b653510b2
commit
e0da08ef73
@ -10,7 +10,7 @@ actix-web = "4.0.1"
|
|||||||
actix-rt = "2.7.0"
|
actix-rt = "2.7.0"
|
||||||
actix-session = "0.5.0"
|
actix-session = "0.5.0"
|
||||||
tera = "1.15.0"
|
tera = "1.15.0"
|
||||||
|
itertools = "0.10.3"
|
||||||
oauth2 = "4.1"
|
oauth2 = "4.1"
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
async-trait = "0.1.53"
|
async-trait = "0.1.53"
|
||||||
|
@ -19,7 +19,6 @@ bae = "0.1.7"
|
|||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
syn = { version = "1.0", features = ["full", "extra-traits"] }
|
syn = { version = "1.0", features = ["full", "extra-traits"] }
|
||||||
proc-macro2 = { version = "1.0.36", default-features = false }
|
proc-macro2 = { version = "1.0.36", default-features = false }
|
||||||
|
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
url = "2.2.2"
|
url = "2.2.2"
|
||||||
http = "0.2.6"
|
http = "0.2.6"
|
||||||
|
@ -11,7 +11,8 @@ pub mod derive_attr {
|
|||||||
)]
|
)]
|
||||||
pub struct ActixAdmin {
|
pub struct ActixAdmin {
|
||||||
pub primary_key: Option<()>,
|
pub primary_key: Option<()>,
|
||||||
pub html_input_type: Option<syn::LitStr>
|
pub html_input_type: Option<syn::LitStr>,
|
||||||
|
pub select_list: Option<syn::LitStr>
|
||||||
//pub inner_type: Option<syn::Type>,
|
//pub inner_type: Option<syn::Type>,
|
||||||
|
|
||||||
// Anything that implements `syn::parse::Parse` is supported.
|
// Anything that implements `syn::parse::Parse` is supported.
|
||||||
|
@ -2,23 +2,47 @@ use proc_macro;
|
|||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
mod struct_fields;
|
mod struct_fields;
|
||||||
use struct_fields::{ get_fields_for_tokenstream, get_fields_for_edit_model, get_fields_for_from_model, get_actix_admin_fields_html_input, get_fields_for_create_model, get_actix_admin_fields, get_field_for_primary_key, get_primary_key_field_name};
|
use struct_fields::{
|
||||||
|
get_fields_for_tokenstream,
|
||||||
|
get_fields_for_edit_model,
|
||||||
|
get_fields_for_from_model,
|
||||||
|
get_actix_admin_fields_html_input,
|
||||||
|
get_fields_for_create_model,
|
||||||
|
get_actix_admin_fields,
|
||||||
|
get_field_for_primary_key,
|
||||||
|
get_primary_key_field_name,
|
||||||
|
get_actix_admin_fields_select_list
|
||||||
|
};
|
||||||
|
|
||||||
|
mod selectlist_fields;
|
||||||
|
use selectlist_fields::{
|
||||||
|
get_select_list,
|
||||||
|
get_select_lists
|
||||||
|
};
|
||||||
|
|
||||||
mod model_fields;
|
mod model_fields;
|
||||||
mod attributes;
|
mod attributes;
|
||||||
|
|
||||||
|
#[proc_macro_derive(DeriveActixAdminSelectList, attributes(actix_admin))]
|
||||||
|
pub fn derive_actix_admin_select_list(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
get_select_list(input)
|
||||||
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(DeriveActixAdminModel, attributes(actix_admin))]
|
#[proc_macro_derive(DeriveActixAdminModel, attributes(actix_admin))]
|
||||||
pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
let fields = get_fields_for_tokenstream(input);
|
let fields = get_fields_for_tokenstream(input);
|
||||||
|
|
||||||
let field_names = get_actix_admin_fields(&fields);
|
let field_names = get_actix_admin_fields(&fields);
|
||||||
let field_html_input_type = get_actix_admin_fields_html_input(&fields);
|
let field_html_input_type = get_actix_admin_fields_html_input(&fields);
|
||||||
|
let field_select_list = get_actix_admin_fields_select_list(&fields);
|
||||||
let name_primary_field_str = get_primary_key_field_name(&fields);
|
let name_primary_field_str = get_primary_key_field_name(&fields);
|
||||||
let fields_for_create_model = get_fields_for_create_model(&fields);
|
let fields_for_create_model = get_fields_for_create_model(&fields);
|
||||||
let fields_for_edit_model = get_fields_for_edit_model(&fields);
|
let fields_for_edit_model = get_fields_for_edit_model(&fields);
|
||||||
let fields_for_from_model = get_fields_for_from_model(&fields);
|
let fields_for_from_model = get_fields_for_from_model(&fields);
|
||||||
let field_for_primary_key = get_field_for_primary_key(&fields);
|
let field_for_primary_key = get_field_for_primary_key(&fields);
|
||||||
|
|
||||||
|
let select_lists = get_select_lists(&fields);
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::iter::zip;
|
use std::iter::zip;
|
||||||
@ -30,6 +54,7 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
|
|||||||
use sea_orm::{entity::*, query::*};
|
use sea_orm::{entity::*, query::*};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use sea_orm::EntityTrait;
|
use sea_orm::EntityTrait;
|
||||||
|
use itertools::izip;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
impl From<Entity> for ActixAdminViewModel {
|
impl From<Entity> for ActixAdminViewModel {
|
||||||
@ -109,6 +134,12 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_select_lists(db: &DatabaseConnection) -> HashMap<String, Vec<(String, String)>> {
|
||||||
|
hashmap![
|
||||||
|
#(#select_lists),*
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
fn get_entity_name() -> String {
|
fn get_entity_name() -> String {
|
||||||
Entity.table_name().to_string()
|
Entity.table_name().to_string()
|
||||||
}
|
}
|
||||||
@ -136,8 +167,9 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
|
|||||||
(num_pages, model_entities)
|
(num_pages, model_entities)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_fields() -> Vec<(String, String)> {
|
fn get_fields() -> Vec<ActixAdminViewModelField> {
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
|
|
||||||
let field_names = stringify!(
|
let field_names = stringify!(
|
||||||
#(#field_names),*
|
#(#field_names),*
|
||||||
).split(",")
|
).split(",")
|
||||||
@ -148,23 +180,18 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
|
|||||||
).split(",")
|
).split(",")
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let mut names_and_input_type = zip(field_names, html_input_types);
|
let field_select_lists = stringify!(
|
||||||
|
#(#field_select_list),*
|
||||||
names_and_input_type
|
).split(",")
|
||||||
.for_each( |field_name_and_type_tuple|
|
.collect::<Vec<_>>();
|
||||||
vec.push((
|
|
||||||
field_name_and_type_tuple.0
|
for (field_name, html_input_type, select_list) in izip!(&field_names, &html_input_types, &field_select_lists) {
|
||||||
.replace('"', "")
|
vec.push(ActixAdminViewModelField {
|
||||||
.replace(' ', "")
|
field_name: field_name.replace('"', "").replace(' ', "").to_string(),
|
||||||
.to_string(),
|
html_input_type: html_input_type.replace('"', "").replace(' ', "").to_string(),
|
||||||
// TODO: match correct ActixAdminField Value
|
select_list: select_list.replace('"', "").replace(' ', "").to_string()
|
||||||
field_name_and_type_tuple.1
|
});
|
||||||
.replace('"', "")
|
}
|
||||||
.replace(' ', "")
|
|
||||||
.to_string()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
vec
|
vec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,8 @@ pub struct ModelField {
|
|||||||
// struct field is option<>
|
// struct field is option<>
|
||||||
pub inner_type: Option<Type>,
|
pub inner_type: Option<Type>,
|
||||||
pub primary_key: bool,
|
pub primary_key: bool,
|
||||||
pub html_input_type: String
|
pub html_input_type: String,
|
||||||
|
pub select_list: String
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModelField {
|
impl ModelField {
|
||||||
|
38
actix_admin/actix_admin_macros/src/selectlist_fields.rs
Normal file
38
actix_admin/actix_admin_macros/src/selectlist_fields.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
use syn::{
|
||||||
|
DeriveInput, Ident
|
||||||
|
};
|
||||||
|
use quote::quote;
|
||||||
|
use crate::model_fields::{ ModelField };
|
||||||
|
use proc_macro2::{Span};
|
||||||
|
|
||||||
|
pub fn get_select_list(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
let ast: DeriveInput = syn::parse(input).unwrap();
|
||||||
|
let (_vis, ty, _generics) = (&ast.vis, &ast.ident, &ast.generics);
|
||||||
|
|
||||||
|
let expanded = quote! {
|
||||||
|
impl ActixAdminSelectListTrait for #ty {
|
||||||
|
fn get_key_value() -> Vec<(String, String)> {
|
||||||
|
let mut fields = Vec::new();
|
||||||
|
for field in #ty::iter() {
|
||||||
|
fields.push((field.to_string(), field.to_string()));
|
||||||
|
}
|
||||||
|
fields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
proc_macro::TokenStream::from(expanded)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_select_lists(fields: &Vec<ModelField>) -> Vec<proc_macro2::TokenStream> {
|
||||||
|
fields
|
||||||
|
.iter()
|
||||||
|
.filter(|model_field| model_field.select_list != "")
|
||||||
|
.map(|model_field| {
|
||||||
|
let ident_name = model_field.ident.to_string();
|
||||||
|
let select_list_ident = Ident::new(&(model_field.select_list), Span::call_site());
|
||||||
|
quote! {
|
||||||
|
#ident_name => #select_list_ident::get_key_value()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
@ -9,7 +9,7 @@ use crate::model_fields::{ ModelField };
|
|||||||
pub fn get_fields_for_tokenstream(input: proc_macro::TokenStream) -> std::vec::Vec<ModelField> {
|
pub fn get_fields_for_tokenstream(input: proc_macro::TokenStream) -> std::vec::Vec<ModelField> {
|
||||||
let ast: DeriveInput = syn::parse(input).unwrap();
|
let ast: DeriveInput = syn::parse(input).unwrap();
|
||||||
let (_vis, ty, _generics) = (&ast.vis, &ast.ident, &ast.generics);
|
let (_vis, ty, _generics) = (&ast.vis, &ast.ident, &ast.generics);
|
||||||
let _names_struct_ident = Ident::new(&(ty.to_string() + "FieldStaticStr"), Span::call_site());
|
//let _names_struct_ident = Ident::new(&(ty.to_string() + "FieldStaticStr"), Span::call_site());
|
||||||
|
|
||||||
let fields = filter_fields(match ast.data {
|
let fields = filter_fields(match ast.data {
|
||||||
syn::Data::Struct(ref s) => &s.fields,
|
syn::Data::Struct(ref s) => &s.fields,
|
||||||
@ -31,6 +31,9 @@ pub fn filter_fields(fields: &Fields) -> Vec<ModelField> {
|
|||||||
let inner_type = extract_type_from_option(&field.ty);
|
let inner_type = extract_type_from_option(&field.ty);
|
||||||
let field_ty = field.ty.to_owned();
|
let field_ty = field.ty.to_owned();
|
||||||
let is_primary_key = actix_admin_attr.clone().map_or(false, |attr| attr.primary_key.is_some());
|
let is_primary_key = actix_admin_attr.clone().map_or(false, |attr| attr.primary_key.is_some());
|
||||||
|
let select_list = actix_admin_attr.clone().map_or("".to_string(), |attr| attr.select_list.map_or("".to_string(),
|
||||||
|
|attr_field| (LitStr::from(attr_field)).value()
|
||||||
|
));
|
||||||
let html_input_type = actix_admin_attr.map_or("text".to_string(), |attr| attr.html_input_type.map_or("text".to_string(),
|
let html_input_type = actix_admin_attr.map_or("text".to_string(), |attr| attr.html_input_type.map_or("text".to_string(),
|
||||||
|attr_field| (LitStr::from(attr_field)).value()
|
|attr_field| (LitStr::from(attr_field)).value()
|
||||||
));
|
));
|
||||||
@ -41,7 +44,8 @@ pub fn filter_fields(fields: &Fields) -> Vec<ModelField> {
|
|||||||
ty: field_ty,
|
ty: field_ty,
|
||||||
inner_type: inner_type,
|
inner_type: inner_type,
|
||||||
primary_key: is_primary_key,
|
primary_key: is_primary_key,
|
||||||
html_input_type: html_input_type
|
html_input_type: html_input_type,
|
||||||
|
select_list: select_list
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(model_field)
|
Some(model_field)
|
||||||
@ -124,6 +128,21 @@ pub fn get_actix_admin_fields_html_input(fields: &Vec<ModelField>) -> Vec<TokenS
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_actix_admin_fields_select_list(fields: &Vec<ModelField>) -> Vec<TokenStream> {
|
||||||
|
fields
|
||||||
|
.iter()
|
||||||
|
.filter(|model_field| !model_field.primary_key)
|
||||||
|
.map(|model_field| {
|
||||||
|
let select_list = model_field.select_list.to_string();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#select_list
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn get_field_for_primary_key(fields: &Vec<ModelField>) -> TokenStream {
|
pub fn get_field_for_primary_key(fields: &Vec<ModelField>) -> TokenStream {
|
||||||
let primary_key_model_field = fields
|
let primary_key_model_field = fields
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -2,7 +2,6 @@ use lazy_static::lazy_static;
|
|||||||
use sea_orm::DatabaseConnection;
|
use sea_orm::DatabaseConnection;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use tera::{Tera};
|
use tera::{Tera};
|
||||||
use serde::{Serialize};
|
|
||||||
|
|
||||||
pub mod view_model;
|
pub mod view_model;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
@ -12,10 +11,10 @@ pub mod builder;
|
|||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::builder::{ ActixAdminBuilder, ActixAdminBuilderTrait};
|
pub use crate::builder::{ ActixAdminBuilder, ActixAdminBuilderTrait};
|
||||||
pub use crate::model::{ ActixAdminModel, ActixAdminModelTrait};
|
pub use crate::model::{ ActixAdminModel, ActixAdminModelTrait};
|
||||||
pub use crate::view_model::{ ActixAdminViewModel, ActixAdminViewModelTrait};
|
pub use crate::view_model::{ ActixAdminViewModel, ActixAdminViewModelTrait, ActixAdminViewModelField};
|
||||||
pub use actix_admin_macros::{ DeriveActixAdminModel };
|
pub use actix_admin_macros::{ DeriveActixAdminModel, DeriveActixAdminSelectList };
|
||||||
pub use crate::{ ActixAdminAppDataTrait, ActixAdmin};
|
pub use crate::{ ActixAdminAppDataTrait, ActixAdmin};
|
||||||
pub use crate::{ hashmap };
|
pub use crate::{ hashmap, ActixAdminSelectListTrait };
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
@ -24,7 +23,7 @@ use crate::prelude::*;
|
|||||||
macro_rules! hashmap {
|
macro_rules! hashmap {
|
||||||
($( $key: expr => $val: expr ),*) => {{
|
($( $key: expr => $val: expr ),*) => {{
|
||||||
let mut map = ::std::collections::HashMap::new();
|
let mut map = ::std::collections::HashMap::new();
|
||||||
$( map.insert($key.to_string(), $val.to_string()); )*
|
$( map.insert($key.to_string(), $val); )*
|
||||||
map
|
map
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -41,8 +40,12 @@ pub trait ActixAdminAppDataTrait {
|
|||||||
fn get_actix_admin(&self) -> &ActixAdmin;
|
fn get_actix_admin(&self) -> &ActixAdmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ActixAdminModel
|
// SelectListTrait
|
||||||
|
pub trait ActixAdminSelectListTrait {
|
||||||
|
fn get_key_value() -> Vec<(String, String)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActixAdminModel
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ActixAdmin {
|
pub struct ActixAdmin {
|
||||||
pub entity_names: Vec<String>,
|
pub entity_names: Vec<String>,
|
||||||
|
@ -2,6 +2,7 @@ use async_trait::async_trait;
|
|||||||
use sea_orm::DatabaseConnection;
|
use sea_orm::DatabaseConnection;
|
||||||
use serde::{Serialize};
|
use serde::{Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use crate::ActixAdminViewModelField;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait ActixAdminModelTrait {
|
pub trait ActixAdminModelTrait {
|
||||||
@ -10,7 +11,7 @@ pub trait ActixAdminModelTrait {
|
|||||||
page: usize,
|
page: usize,
|
||||||
posts_per_page: usize,
|
posts_per_page: usize,
|
||||||
) -> (usize, Vec<ActixAdminModel>);
|
) -> (usize, Vec<ActixAdminModel>);
|
||||||
fn get_fields() -> Vec<(String, String)>;
|
fn get_fields() -> Vec<ActixAdminViewModelField>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
@ -37,6 +38,7 @@ impl From<String> for ActixAdminModel {
|
|||||||
|
|
||||||
impl ActixAdminModel {
|
impl ActixAdminModel {
|
||||||
pub fn get_value<T: std::str::FromStr>(&self, key: &str) -> Option<T> {
|
pub fn get_value<T: std::str::FromStr>(&self, key: &str) -> Option<T> {
|
||||||
|
println!("{:?}", self.values);
|
||||||
let value = self.values.get(key).unwrap().to_string().parse::<T>();
|
let value = self.values.get(key).unwrap().to_string().parse::<T>();
|
||||||
match value {
|
match value {
|
||||||
Ok(val) => Some(val),
|
Ok(val) => Some(val),
|
||||||
|
@ -22,7 +22,7 @@ pub async fn create_get<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
|||||||
let mut ctx = Context::new();
|
let mut ctx = Context::new();
|
||||||
ctx.insert("entity_names", &entity_names);
|
ctx.insert("entity_names", &entity_names);
|
||||||
ctx.insert("view_model", &view_model);
|
ctx.insert("view_model", &view_model);
|
||||||
ctx.insert("model_fields", &view_model.fields);
|
ctx.insert("select_lists", &E::get_select_lists(_db).await);
|
||||||
|
|
||||||
let body = TERA
|
let body = TERA
|
||||||
.render("create.html", &ctx)
|
.render("create.html", &ctx)
|
||||||
|
@ -26,6 +26,7 @@ pub async fn edit_get<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
|||||||
ctx.insert("entity_names", &entity_names);
|
ctx.insert("entity_names", &entity_names);
|
||||||
ctx.insert("view_model", &view_model);
|
ctx.insert("view_model", &view_model);
|
||||||
ctx.insert("model", &model);
|
ctx.insert("model", &model);
|
||||||
|
ctx.insert("select_lists", &E::get_select_lists(db).await);
|
||||||
|
|
||||||
let body = TERA
|
let body = TERA
|
||||||
.render("edit.html", &ctx)
|
.render("edit.html", &ctx)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use sea_orm::DatabaseConnection;
|
use sea_orm::DatabaseConnection;
|
||||||
use serde::{Serialize};
|
use serde::{Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
use crate::ActixAdminModel;
|
use crate::ActixAdminModel;
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
@ -17,7 +17,8 @@ pub trait ActixAdminViewModelTrait {
|
|||||||
async fn delete_entity(db: &DatabaseConnection, id: i32) -> bool;
|
async fn delete_entity(db: &DatabaseConnection, id: i32) -> bool;
|
||||||
async fn get_entity(db: &DatabaseConnection, id: i32) -> ActixAdminModel;
|
async fn get_entity(db: &DatabaseConnection, id: i32) -> ActixAdminModel;
|
||||||
async fn edit_entity(db: &DatabaseConnection, id: i32, model: ActixAdminModel) -> ActixAdminModel;
|
async fn edit_entity(db: &DatabaseConnection, id: i32, model: ActixAdminModel) -> ActixAdminModel;
|
||||||
|
async fn get_select_lists(db: &DatabaseConnection) -> HashMap<String, Vec<(String, String)>>;
|
||||||
|
|
||||||
fn get_entity_name() -> String;
|
fn get_entity_name() -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,5 +26,12 @@ pub trait ActixAdminViewModelTrait {
|
|||||||
pub struct ActixAdminViewModel {
|
pub struct ActixAdminViewModel {
|
||||||
pub entity_name: String,
|
pub entity_name: String,
|
||||||
pub primary_key: String,
|
pub primary_key: String,
|
||||||
pub fields: Vec<(String, String)>,
|
pub fields: Vec<ActixAdminViewModelField>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
pub struct ActixAdminViewModelField {
|
||||||
|
pub field_name: String,
|
||||||
|
pub html_input_type: String,
|
||||||
|
pub select_list: String
|
||||||
}
|
}
|
@ -4,7 +4,16 @@
|
|||||||
<form method="post">
|
<form method="post">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
{% for model_field in view_model.fields -%}
|
{% for model_field in view_model.fields -%}
|
||||||
<input type="{{ model_field[1] }}" name="{{ model_field[0] }}" placeholder="{{ model_field[0] }}" aria-label="{{ model_field[0] }}"><!-- required="" -->
|
{% if model_field.select_list != "" %}
|
||||||
|
<select name="{{ model_field.field_name }}">
|
||||||
|
<option value="" selected>Select</option>
|
||||||
|
{% for select_list_item in select_lists[model_field.field_name] -%}
|
||||||
|
<option value="{{ select_list_item[0] }}">{{ select_list_item[1] }}</option>
|
||||||
|
{%- endfor %}
|
||||||
|
</select>
|
||||||
|
{% else %}
|
||||||
|
<input type="{{ model_field.html_input_type }}" name="{{ model_field.field_name }}" placeholder="{{ model_field.field_name }}" aria-label="{{ model_field.field_name }}"><!-- required="" -->
|
||||||
|
{% endif %}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
<button type="submit">Save</button>
|
<button type="submit">Save</button>
|
||||||
<button onclick="history.back()">Cancel</button>
|
<button onclick="history.back()">Cancel</button>
|
||||||
|
@ -3,8 +3,17 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
{% for key, value in model.values -%}
|
{% for model_field in view_model.fields -%}
|
||||||
<input type="text" value="{{ value }}" name="{{ key }}" placeholder="{{ key }}" aria-label="{{ key }}"><!-- required="" -->
|
{% if model_field.select_list != "" %}
|
||||||
|
<select name="{{ model_field.field_name }}">
|
||||||
|
<option value="" selected>Select</option>
|
||||||
|
{% for select_list_item in select_lists[model_field.field_name] -%}
|
||||||
|
<option {% if select_list_item[0] == model.values | get(key=model_field.field_name) %} selected {% endif %} value="{{ select_list_item[0] }}">{{ select_list_item[1] }}</option>
|
||||||
|
{%- endfor %}
|
||||||
|
</select>
|
||||||
|
{% else %}
|
||||||
|
<input type="{{ model_field.html_input_type }}" value="{{ model.values | get(key=model_field.field_name) }}" name="{{ model_field.field_name }}" placeholder="{{ model_field.field_name }}" aria-label="{{ model_field.field_name }}"><!-- required="" -->
|
||||||
|
{% endif %}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
<button type="submit">Save</button>
|
<button type="submit">Save</button>
|
||||||
<button onclick="history.back()">Cancel</button>
|
<button onclick="history.back()">Cancel</button>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>{{ view_model.primary_key }}</th>
|
<th>{{ view_model.primary_key }}</th>
|
||||||
{% for model_field in view_model.fields -%}
|
{% for model_field in view_model.fields -%}
|
||||||
<th>{{ model_field[0] }}</th>
|
<th>{{ model_field.field_name }}</th>
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
<th>
|
<th>
|
||||||
<!-- Edit Action -->
|
<!-- Edit Action -->
|
||||||
@ -20,7 +20,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{{ entity.primary_key }}</td>
|
<td>{{ entity.primary_key }}</td>
|
||||||
{% for model_field in view_model.fields -%}
|
{% for model_field in view_model.fields -%}
|
||||||
<td>{{ entity.values | get(key=model_field[0]) }}</td>
|
<td>{{ entity.values | get(key=model_field.field_name) }}</td>
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
<td>
|
<td>
|
||||||
<a href="edit/{{ entity.primary_key }}">✎</a>
|
<a href="edit/{{ entity.primary_key }}">✎</a>
|
||||||
|
BIN
database.db
BIN
database.db
Binary file not shown.
BIN
database.db-wal
BIN
database.db-wal
Binary file not shown.
@ -15,8 +15,9 @@ pub struct Model {
|
|||||||
pub title: String,
|
pub title: String,
|
||||||
#[sea_orm(column_type = "Text")]
|
#[sea_orm(column_type = "Text")]
|
||||||
pub text: String,
|
pub text: String,
|
||||||
|
#[actix_admin(select_list="Tea")]
|
||||||
pub tea_mandatory: Tea,
|
pub tea_mandatory: Tea,
|
||||||
#[actix_admin()]
|
#[actix_admin(select_list="Tea")]
|
||||||
pub tea_optional: Option<Tea>,
|
pub tea_optional: Option<Tea>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +26,7 @@ pub enum Relation {}
|
|||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Deserialize, Serialize)]
|
#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Deserialize, Serialize, DeriveActixAdminSelectList)]
|
||||||
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "tea")]
|
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "tea")]
|
||||||
pub enum Tea {
|
pub enum Tea {
|
||||||
#[sea_orm(string_value = "EverydayTea")]
|
#[sea_orm(string_value = "EverydayTea")]
|
||||||
|
Loading…
Reference in New Issue
Block a user