add option for html input type on column

This commit is contained in:
manuel 2022-07-17 22:12:18 +02:00
parent 96b069042e
commit 2b653510b2
12 changed files with 62 additions and 32 deletions

View File

@ -6,10 +6,12 @@ pub mod derive_attr {
Eq,
PartialEq,
FromAttributes,
Default
Default,
Clone
)]
pub struct ActixAdmin {
pub primary_key: Option<()>
pub primary_key: Option<()>,
pub html_input_type: Option<syn::LitStr>
//pub inner_type: Option<syn::Type>,
// Anything that implements `syn::parse::Parse` is supported.

View File

@ -2,17 +2,17 @@ use proc_macro;
use quote::quote;
mod struct_fields;
use struct_fields::{ get_fields_for_tokenstream, get_fields_for_edit_model, get_fields_for_from_model, get_fields_for_create_model, get_field_names, 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};
mod model_fields;
mod attributes;
#[proc_macro_derive(DeriveActixAdminModel, attributes(actix_admin))]
pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let fields = get_fields_for_tokenstream(input);
let names_const_fields_str = get_field_names(&fields);
let field_names = get_actix_admin_fields(&fields);
let field_html_input_type = get_actix_admin_fields_html_input(&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_edit_model = get_fields_for_edit_model(&fields);
@ -21,6 +21,7 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
let expanded = quote! {
use std::convert::From;
use std::iter::zip;
use async_trait::async_trait;
use actix_web::{web, HttpResponse, HttpRequest, Error};
use actix_admin::prelude::*;
@ -135,21 +136,32 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
(num_pages, model_entities)
}
fn get_fields() -> Vec<(String, ActixAdminField)> {
fn get_fields() -> Vec<(String, String)> {
let mut vec = Vec::new();
let field_names = stringify!(
#(#names_const_fields_str),*
).split(",")
.collect::<Vec<_>>()
.into_iter()
.for_each( |field_name|
#(#field_names),*
).split(",")
.collect::<Vec<_>>();
let html_input_types = stringify!(
#(#field_html_input_type),*
).split(",")
.collect::<Vec<_>>();
let mut names_and_input_type = zip(field_names, html_input_types);
names_and_input_type
.for_each( |field_name_and_type_tuple|
vec.push((
field_name
field_name_and_type_tuple.0
.replace('"', "")
.replace(' ', "")
.to_string(),
// TODO: match correct ActixAdminField Value
ActixAdminField::Text
field_name_and_type_tuple.1
.replace('"', "")
.replace(' ', "")
.to_string()
)
)
);

View File

@ -8,7 +8,8 @@ pub struct ModelField {
pub ty: Type,
// struct field is option<>
pub inner_type: Option<Type>,
pub primary_key: bool
pub primary_key: bool,
pub html_input_type: String
}
impl ModelField {

View File

@ -1,6 +1,6 @@
use proc_macro2::{Span, Ident, TokenStream};
use syn::{
Fields, DeriveInput
Fields, DeriveInput, LitStr
};
use quote::quote;
use crate::attributes::derive_attr;
@ -30,14 +30,18 @@ pub fn filter_fields(fields: &Fields) -> Vec<ModelField> {
let field_ident = field.ident.as_ref().unwrap().clone();
let inner_type = extract_type_from_option(&field.ty);
let field_ty = field.ty.to_owned();
let is_primary_key = actix_admin_attr.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 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()
));
let model_field = ModelField {
visibility: field_vis,
ident: field_ident,
ty: field_ty,
inner_type: inner_type,
primary_key: is_primary_key
primary_key: is_primary_key,
html_input_type: html_input_type
};
Some(model_field)
@ -92,12 +96,13 @@ fn extract_type_from_option(ty: &syn::Type) -> Option<syn::Type> {
})
}
pub fn get_field_names(fields: &Vec<ModelField>) -> Vec<TokenStream> {
pub fn get_actix_admin_fields(fields: &Vec<ModelField>) -> Vec<TokenStream> {
fields
.iter()
.filter(|model_field| !model_field.primary_key)
.map(|model_field| {
let ident_name = model_field.ident.to_string();
quote! {
#ident_name
}
@ -105,6 +110,20 @@ pub fn get_field_names(fields: &Vec<ModelField>) -> Vec<TokenStream> {
.collect::<Vec<_>>()
}
pub fn get_actix_admin_fields_html_input(fields: &Vec<ModelField>) -> Vec<TokenStream> {
fields
.iter()
.filter(|model_field| !model_field.primary_key)
.map(|model_field| {
let html_input_type = model_field.html_input_type.to_string();
quote! {
#html_input_type
}
})
.collect::<Vec<_>>()
}
pub fn get_field_for_primary_key(fields: &Vec<ModelField>) -> TokenStream {
let primary_key_model_field = fields
.iter()

View File

@ -1,8 +1,8 @@
use lazy_static::lazy_static;
use sea_orm::DatabaseConnection;
use serde::{Serialize};
use std::collections::HashMap;
use tera::{Tera};
use serde::{Serialize};
pub mod view_model;
pub mod model;
@ -16,7 +16,6 @@ pub mod prelude {
pub use actix_admin_macros::{ DeriveActixAdminModel };
pub use crate::{ ActixAdminAppDataTrait, ActixAdmin};
pub use crate::{ hashmap };
pub use crate::{ ActixAdminField };
}
use crate::prelude::*;
@ -36,12 +35,6 @@ lazy_static! {
Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap();
}
// Fields
#[derive(Clone, Debug, Serialize)]
pub enum ActixAdminField {
Text,
}
// AppDataTrait
pub trait ActixAdminAppDataTrait {
fn get_db(&self) -> &DatabaseConnection;

View File

@ -3,8 +3,6 @@ use sea_orm::DatabaseConnection;
use serde::{Serialize};
use std::collections::HashMap;
use crate::ActixAdminField;
#[async_trait]
pub trait ActixAdminModelTrait {
async fn list_model(
@ -12,7 +10,7 @@ pub trait ActixAdminModelTrait {
page: usize,
posts_per_page: usize,
) -> (usize, Vec<ActixAdminModel>);
fn get_fields() -> Vec<(String, ActixAdminField)>;
fn get_fields() -> Vec<(String, String)>;
}
#[derive(Clone, Debug, Serialize)]

View File

@ -3,7 +3,6 @@ use sea_orm::DatabaseConnection;
use serde::{Serialize};
use crate::ActixAdminModel;
use crate::ActixAdminField;
#[async_trait(?Send)]
pub trait ActixAdminViewModelTrait {
@ -26,5 +25,5 @@ pub trait ActixAdminViewModelTrait {
pub struct ActixAdminViewModel {
pub entity_name: String,
pub primary_key: String,
pub fields: Vec<(String, ActixAdminField)>,
pub fields: Vec<(String, String)>,
}

View File

@ -4,9 +4,10 @@
<form method="post">
<div class="grid">
{% for model_field in view_model.fields -%}
<input type="text" name="{{ model_field[0] }}" placeholder="{{ model_field[0] }}" aria-label="{{ model_field[0] }}"><!-- required="" -->
<input type="{{ model_field[1] }}" name="{{ model_field[0] }}" placeholder="{{ model_field[0] }}" aria-label="{{ model_field[0] }}"><!-- required="" -->
{%- endfor %}
<button type="submit">Save</button>
<button onclick="history.back()">Cancel</button>
</div>
</form>
{% endblock content %}

View File

@ -7,6 +7,7 @@
<input type="text" value="{{ value }}" name="{{ key }}" placeholder="{{ key }}" aria-label="{{ key }}"><!-- required="" -->
{%- endfor %}
<button type="submit">Save</button>
<button onclick="history.back()">Cancel</button>
</div>
</form>
{% endblock content %}

Binary file not shown.

View File

@ -12,6 +12,9 @@ pub struct Model {
pub comment: String,
#[sea_orm(column_type = "Text")]
pub user: String,
#[sea_orm(column_type = "DateTime")]
#[actix_admin(html_input_type = "datetime-local")]
pub insert_date: DateTimeWithTimeZone
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

View File

@ -43,6 +43,7 @@ pub async fn create_post_table(db: &DbConn) -> Result<ExecResult, DbErr> {
)
.col(ColumnDef::new(comment::Column::Comment).string().not_null())
.col(ColumnDef::new(comment::Column::User).string().not_null())
.col(ColumnDef::new(comment::Column::InsertDate).date_time().not_null())
.to_owned();
create_table(db, &stmt).await