add option for html input type on column
This commit is contained in:
parent
96b069042e
commit
2b653510b2
@ -6,10 +6,12 @@ pub mod derive_attr {
|
|||||||
Eq,
|
Eq,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
FromAttributes,
|
FromAttributes,
|
||||||
Default
|
Default,
|
||||||
|
Clone
|
||||||
)]
|
)]
|
||||||
pub struct ActixAdmin {
|
pub struct ActixAdmin {
|
||||||
pub primary_key: Option<()>
|
pub primary_key: Option<()>,
|
||||||
|
pub html_input_type: 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,17 +2,17 @@ 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_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 model_fields;
|
||||||
|
|
||||||
mod attributes;
|
mod attributes;
|
||||||
|
|
||||||
#[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 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 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);
|
||||||
@ -21,6 +21,7 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
|
|||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
|
use std::iter::zip;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use actix_web::{web, HttpResponse, HttpRequest, Error};
|
use actix_web::{web, HttpResponse, HttpRequest, Error};
|
||||||
use actix_admin::prelude::*;
|
use actix_admin::prelude::*;
|
||||||
@ -135,21 +136,32 @@ 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, ActixAdminField)> {
|
fn get_fields() -> Vec<(String, String)> {
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
let field_names = stringify!(
|
let field_names = stringify!(
|
||||||
#(#names_const_fields_str),*
|
#(#field_names),*
|
||||||
).split(",")
|
).split(",")
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>();
|
||||||
.into_iter()
|
|
||||||
.for_each( |field_name|
|
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((
|
vec.push((
|
||||||
field_name
|
field_name_and_type_tuple.0
|
||||||
.replace('"', "")
|
.replace('"', "")
|
||||||
.replace(' ', "")
|
.replace(' ', "")
|
||||||
.to_string(),
|
.to_string(),
|
||||||
// TODO: match correct ActixAdminField Value
|
// TODO: match correct ActixAdminField Value
|
||||||
ActixAdminField::Text
|
field_name_and_type_tuple.1
|
||||||
|
.replace('"', "")
|
||||||
|
.replace(' ', "")
|
||||||
|
.to_string()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -8,7 +8,8 @@ pub struct ModelField {
|
|||||||
pub ty: Type,
|
pub ty: Type,
|
||||||
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModelField {
|
impl ModelField {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use proc_macro2::{Span, Ident, TokenStream};
|
use proc_macro2::{Span, Ident, TokenStream};
|
||||||
use syn::{
|
use syn::{
|
||||||
Fields, DeriveInput
|
Fields, DeriveInput, LitStr
|
||||||
};
|
};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use crate::attributes::derive_attr;
|
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 field_ident = field.ident.as_ref().unwrap().clone();
|
||||||
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.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 {
|
let model_field = ModelField {
|
||||||
visibility: field_vis,
|
visibility: field_vis,
|
||||||
ident: field_ident,
|
ident: field_ident,
|
||||||
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
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(model_field)
|
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
|
fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|model_field| !model_field.primary_key)
|
.filter(|model_field| !model_field.primary_key)
|
||||||
.map(|model_field| {
|
.map(|model_field| {
|
||||||
let ident_name = model_field.ident.to_string();
|
let ident_name = model_field.ident.to_string();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#ident_name
|
#ident_name
|
||||||
}
|
}
|
||||||
@ -105,6 +110,20 @@ pub fn get_field_names(fields: &Vec<ModelField>) -> Vec<TokenStream> {
|
|||||||
.collect::<Vec<_>>()
|
.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 {
|
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()
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use sea_orm::DatabaseConnection;
|
use sea_orm::DatabaseConnection;
|
||||||
use serde::{Serialize};
|
|
||||||
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;
|
||||||
@ -16,7 +16,6 @@ pub mod prelude {
|
|||||||
pub use actix_admin_macros::{ DeriveActixAdminModel };
|
pub use actix_admin_macros::{ DeriveActixAdminModel };
|
||||||
pub use crate::{ ActixAdminAppDataTrait, ActixAdmin};
|
pub use crate::{ ActixAdminAppDataTrait, ActixAdmin};
|
||||||
pub use crate::{ hashmap };
|
pub use crate::{ hashmap };
|
||||||
pub use crate::{ ActixAdminField };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
@ -36,12 +35,6 @@ lazy_static! {
|
|||||||
Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap();
|
Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fields
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
|
||||||
pub enum ActixAdminField {
|
|
||||||
Text,
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppDataTrait
|
// AppDataTrait
|
||||||
pub trait ActixAdminAppDataTrait {
|
pub trait ActixAdminAppDataTrait {
|
||||||
fn get_db(&self) -> &DatabaseConnection;
|
fn get_db(&self) -> &DatabaseConnection;
|
||||||
|
@ -3,8 +3,6 @@ use sea_orm::DatabaseConnection;
|
|||||||
use serde::{Serialize};
|
use serde::{Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::ActixAdminField;
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait ActixAdminModelTrait {
|
pub trait ActixAdminModelTrait {
|
||||||
async fn list_model(
|
async fn list_model(
|
||||||
@ -12,7 +10,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, ActixAdminField)>;
|
fn get_fields() -> Vec<(String, String)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
@ -3,7 +3,6 @@ use sea_orm::DatabaseConnection;
|
|||||||
use serde::{Serialize};
|
use serde::{Serialize};
|
||||||
|
|
||||||
use crate::ActixAdminModel;
|
use crate::ActixAdminModel;
|
||||||
use crate::ActixAdminField;
|
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
pub trait ActixAdminViewModelTrait {
|
pub trait ActixAdminViewModelTrait {
|
||||||
@ -26,5 +25,5 @@ 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, ActixAdminField)>,
|
pub fields: Vec<(String, String)>,
|
||||||
}
|
}
|
@ -4,9 +4,10 @@
|
|||||||
<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="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 %}
|
{%- endfor %}
|
||||||
<button type="submit">Save</button>
|
<button type="submit">Save</button>
|
||||||
|
<button onclick="history.back()">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
@ -7,6 +7,7 @@
|
|||||||
<input type="text" value="{{ value }}" name="{{ key }}" placeholder="{{ key }}" aria-label="{{ key }}"><!-- required="" -->
|
<input type="text" value="{{ value }}" name="{{ key }}" placeholder="{{ key }}" aria-label="{{ key }}"><!-- required="" -->
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
<button type="submit">Save</button>
|
<button type="submit">Save</button>
|
||||||
|
<button onclick="history.back()">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
BIN
database.db-wal
BIN
database.db-wal
Binary file not shown.
@ -12,6 +12,9 @@ pub struct Model {
|
|||||||
pub comment: String,
|
pub comment: String,
|
||||||
#[sea_orm(column_type = "Text")]
|
#[sea_orm(column_type = "Text")]
|
||||||
pub user: String,
|
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)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
@ -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::Comment).string().not_null())
|
||||||
.col(ColumnDef::new(comment::Column::User).string().not_null())
|
.col(ColumnDef::new(comment::Column::User).string().not_null())
|
||||||
|
.col(ColumnDef::new(comment::Column::InsertDate).date_time().not_null())
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
create_table(db, &stmt).await
|
create_table(db, &stmt).await
|
||||||
|
Loading…
Reference in New Issue
Block a user