feat(12.2-02): add the datepicker field with server-side bounds and date list columns

- type: datepicker compiles the D-20 keys; format maps to displayFormat with WinterCMS's momentFormat table
- boot fails when the mode does not match the column's Go type (time.Time, lagoon.Date, lagoon.TimeOfDay)
- datepicker is a writable scalar field; minDate and maxDate are rechecked on save
- columns.yaml accepts type: date and type: time; Scanner/Valuer structs are columns, not relations
- conformance fixture carries date and datetime fields; README, forms and lists docs
This commit is contained in:
Jakub Zych
2026-10-02 18:19:04 +02:00
parent bbb804961e
commit 67d4c7ff13
17 changed files with 719 additions and 32 deletions

View File

@@ -23,7 +23,7 @@ var (
formFieldTypes = map[string]struct{}{
"text": {}, "textarea": {}, "number": {}, "checkbox": {},
"switch": {}, "dropdown": {}, "relation": {}, "relation-manager": {},
"widget": {}, "partial": {}, "fileupload": {},
"widget": {}, "partial": {}, "fileupload": {}, "datepicker": {},
}
formSpans = map[string]struct{}{
"left": {}, "right": {}, "full": {}, "auto": {}, "row": {},
@@ -39,6 +39,8 @@ var (
"mode": {}, "fileTypes": {}, "mimeTypes": {}, "maxFilesize": {},
"maxFiles": {}, "imageWidth": {}, "imageHeight": {},
"thumbOptions": {}, "useCaption": {}, "prompt": {},
"format": {}, "minDate": {}, "maxDate": {}, "yearRange": {},
"firstDay": {}, "twelveHour": {}, "ignoreTimezone": {},
}
// widgetKeys are valid only on `type: widget` (D-06).
widgetKeys = []string{"widget", "action", "fill"}
@@ -152,6 +154,7 @@ func (s *FormSchema) Localize(ctx context.Context, tr *phrasebook.Translator, pr
field.Fill = append([]string(nil), src.Fill...)
field.FileTypes = append([]string(nil), src.FileTypes...)
field.MimeTypes = append([]string(nil), src.MimeTypes...)
field.YearRange = append([]int(nil), src.YearRange...)
options, err := localizeOptions(ctx, tr, src, provider)
if err != nil {
return nil, err
@@ -431,6 +434,9 @@ func compileFieldNode(name string, node ast.Node) (FormField, error) {
if err := compileFileuploadKeys(typ, values, &field); err != nil {
return FormField{}, err
}
if err := compileDatepickerKeys(typ, values, &field); err != nil {
return FormField{}, err
}
if node, ok := values["required"]; ok {
field.Required, err = nodeBool(node)
if err != nil {