Flat file database editor and browser with web interface
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
rocket-inv/src/store/form.rs

179 lines
5.7 KiB

use crate::store::model::FieldKind;
use serde_json::Value;
use std::borrow::Cow;
use crate::store::{model, Indexes, Store};
use lazy_static::lazy_static;
lazy_static! {
/// This is an example for using doc comment attributes
static ref EMPTY_VEC: Vec<String> = vec![];
}
#[derive(Serialize, Debug, Default)]
pub struct RenderedField<'a> {
pub key: Cow<'a, str>,
pub label: Cow<'a, str>,
pub kind: &'static str,
pub step: &'static str,
pub min: String,
pub max: String,
pub all_tags_json: String,
pub tags_json: String,
pub options: Option<&'a Vec<String>>,
pub value: Cow<'a, str>,
pub checked: bool,
}
impl<'a> RenderedField<'a> {
pub fn from_template_field<'i>(
key: &'i String,
field: &'i model::Field,
value: Option<&'i Value>,
index: &'i Indexes
) -> RenderedField<'i> {
let mut rendered = RenderedField::default();
rendered.key = key.as_str().into();
rendered.label = if field.label.is_empty() {
titlecase::titlecase(&key.replace('_', " ")).into()
} else {
field.label.as_str().into()
};
match &field.kind {
FieldKind::String => {
rendered.kind = "string";
}
FieldKind::Text => {
rendered.kind = "text";
}
FieldKind::Bool { default } => {
rendered.kind = "bool";
rendered.checked = if let Some(Value::Bool(v)) = value {
*v
} else {
*default
}
}
FieldKind::Int { min, max, default } => {
rendered.kind = "number";
let num = if let Some(Value::Number(n)) = value {
n.as_i64().expect("Error parsing number")
} else {
*default
};
if let Some(n) = min {
rendered.min = n.to_string();
}
if let Some(n) = max {
rendered.max = n.to_string();
}
rendered.value = Cow::Owned(num.to_string());
rendered.step = "1";
}
FieldKind::Float { min, max, default } => {
rendered.kind = "number";
let num = if let Some(Value::Number(n)) = value {
n.as_f64().expect("Error parsing number")
} else {
*default
};
if let Some(n) = min {
rendered.min = n.to_string();
}
if let Some(n) = max {
rendered.max = n.to_string();
}
rendered.value = Cow::Owned(num.to_string());
rendered.step = "any";
}
FieldKind::Enum { options, default } => {
rendered.kind = "select";
rendered.options = Some(options);
if let Some(Value::String(s)) = value {
rendered.value = Cow::Borrowed(&s.as_str());
} else if let Some(def) = default {
rendered.value = def.to_owned().into();
}
}
FieldKind::FreeEnum { enum_group } => {
rendered.kind = "free_select";
let group = enum_group.as_ref().unwrap_or(key);
let options = index.free_enums.get(group).unwrap_or(&EMPTY_VEC);
rendered.options = Some(options);
}
FieldKind::Tags { options } => {
rendered.kind = "tags";
rendered.options = Some(options);
rendered.all_tags_json = serde_json::to_string(options).unwrap();
}
FieldKind::FreeTags { tag_group } => {
rendered.kind = "free_tags";
let group = tag_group.as_ref().unwrap_or(key);
let options = index.free_tags.get(group).unwrap_or(&EMPTY_VEC);
rendered.options = Some(options);
rendered.all_tags_json = "[]".into();
}
}
// Shared code by multiple variants
match field.kind {
FieldKind::Text | FieldKind::String => {
if let Some(Value::String(s)) = value {
rendered.value = Cow::Borrowed(&s.as_str());
}
},
FieldKind::Enum { .. } | FieldKind::FreeEnum { .. } => {
if let Some(Value::String(s)) = value {
rendered.value = Cow::Borrowed(&s.as_str());
}
},
FieldKind::Tags { .. } | FieldKind::FreeTags { .. } => {
if let Some(v) = value {
rendered.value = serde_json::from_value::<Vec<String>>(v.clone())
.unwrap().join(" ").into();
rendered.tags_json = serde_json::to_string(v).unwrap();
} else {
rendered.tags_json = "[]".into();
}
},
_ => {}
}
rendered
}
}
#[derive(Serialize,Debug)]
pub struct RenderedCard<'a> {
pub fields : Vec<RenderedField<'a>>,
pub id : usize,
}
pub fn render_empty_fields(store : &Store) -> Vec<RenderedField> {
let indexes = &store.index;
store.model.fields.iter().map(|(key, field)| {
RenderedField::from_template_field(key, field, None, indexes)
}).collect()
}
pub fn render_card_fields<'a>(store : &'a Store, values : &'a serde_json::Map<String, Value>) -> Vec<RenderedField<'a>> {
let indexes = &store.index;
store.model.fields.iter().map(|(key, field)| {
RenderedField::from_template_field(key, field, values.get(key), indexes)
}).collect()
}