use maud::Markup;
use crate::components::{HtmlAttrs, InputFile, input_file};
use crate::html_form::{
FieldRender, FormCtx, FormWidget, Upload, html_form,
widgets::{File, ForeignKey, Kind, Text},
};
const _: fn() = || {
let _: Kind = Kind;
let _: FilePrefillName = FilePrefillName;
};
pub struct FilePrefillName;
impl FormWidget for FilePrefillName {
fn render(_ctx: &FormCtx<'_>, field: &FieldRender<'_>) -> Markup {
input_file(InputFile {
label: field.label,
name: field.name,
required: field.required,
multiple: field.spec.multiple,
accept: field.spec.accept.unwrap_or(""),
attrs: HtmlAttrs::new().set(
"onchange",
"const n=this.form&&this.form.querySelector('[name=Name]');if(n&&this.files&&this.files[0])n.value=this.files[0].name",
),
..Default::default()
})
}
}
#[html_form(default)]
pub struct MoveForm {
#[form(
label = "Destination Folder",
widget = ForeignKey,
swap_key = "fk-vnode-destination",
display = "destination",
placeholder = "Filesystem root"
)]
pub destination_id: i64,
}
#[html_form(default)]
pub enum VNodeKind {
#[form(label = "Directory")]
Directory,
#[form(label = "File")]
File {
#[form(label = "File", widget = FilePrefillName, required)]
file: Upload,
},
}
#[html_form(default)]
pub struct VNodeForm {
#[form(label = "Name", required, widget = Text)]
pub name: String,
#[form(widget = Kind)] pub kind: VNodeKind,
#[form(
label = "Parent Folder",
widget = ForeignKey,
url = "/filesystem/select",
swap_key = "fk-vnode-parent",
display = "parent",
when = "create_mode",
placeholder = "Filesystem root"
)]
pub parent_id: Option<i64>,
}
#[html_form(default)]
pub struct VNodeEditForm {
#[form(label = "Name", required, widget = Text)]
pub name: String,
#[form(label = "File", widget = File, when = "show_file")]
pub file: Option<Upload>,
}
#[html_form(default)]
pub struct VNodeMultiUploadForm {
#[form(
label = "Destination Folder",
widget = ForeignKey,
url = "/filesystem/select",
swap_key = "fk-vnode-parent",
display = "parent",
placeholder = "Filesystem root"
)]
pub parent_id: Option<i64>,
#[form(label = "Files", widget = File, multiple, required)]
pub files: Vec<Upload>,
}
#[html_form(default)]
pub struct VNodeZipUploadForm {
#[form(
label = "Destination Folder",
widget = ForeignKey,
url = "/filesystem/select",
swap_key = "fk-vnode-parent",
display = "parent",
placeholder = "Filesystem root"
)]
pub parent_id: Option<i64>,
#[form(label = "Zip File", widget = File, accept = ".zip", required)]
pub zip_file: Upload,
}
#[html_form]
pub struct VNodeNameFilterForm {
#[form(label = "Name", widget = Text)]
pub name: String,
}
#[cfg(test)]
mod tests {
use super::{VNodeForm, VNodeFormField, VNodeFormFlag, VNodeKind};
use crate::html_form::{FormCtx, HtmlForm, HtmlKind};
#[test]
fn vnode_kind_variants() {
let variants = VNodeKind::variants();
assert_eq!(variants.len(), 2);
assert_eq!(variants[0].value, "Directory");
assert!(variants[0].fields.is_empty());
assert_eq!(variants[1].value, "File");
assert_eq!(variants[1].fields[0].name, "File");
}
#[test]
fn vnode_form_create_renders_kind_radios() {
let ctx = FormCtx::form::<VNodeForm>()
.flag(VNodeFormFlag::CreateMode, true)
.kind::<VNodeKind>("File");
let html = VNodeForm::render_inputs(&ctx).into_string();
assert!(html.contains("type=\"radio\""), "{html}");
assert!(html.contains("name=\"Kind\""), "{html}");
assert!(html.contains("x-model=\"kind\""), "{html}");
assert!(html.contains("name=\"ParentID\""), "{html}");
assert!(html.contains("type=\"file\""), "{html}");
assert!(html.contains("onchange="), "{html}");
assert!(html.contains("[name=Name]"), "{html}");
assert!(html.contains("files[0].name"), "{html}");
assert!(
html.contains("x-bind:disabled=\"!(kind === 'File')\""),
"{html}"
);
assert!(
html.contains("x-bind:disabled=\"!(kind === 'Directory')\""),
"{html}"
);
}
#[test]
fn vnode_form_edit_locks_kind() {
let ctx = FormCtx::form::<VNodeForm>()
.flag(VNodeFormFlag::CreateMode, false)
.lock_kind(true)
.kind::<VNodeKind>("Directory")
.value(VNodeFormField::Name, "docs");
let html = VNodeForm::render_inputs(&ctx).into_string();
assert!(!html.contains("type=\"radio\""), "{html}");
assert!(!html.contains("type=\"file\""), "{html}");
assert!(!html.contains("name=\"ParentID\""), "{html}");
assert!(html.contains("name=\"Name\""), "{html}");
}
}