package cabana import "encoding/json" // ListSort is the compiled default sort. Direction is exactly asc or desc. type ListSort struct { Column string `json:"column"` Direction string `json:"direction"` } // ListColumn is one compiled columns.yaml entry, in file order. // Omitted sortable defaults to true, matching Winter; searchable defaults to false. type ListColumn struct { Key string `json:"key"` Label string `json:"label"` Searchable bool `json:"searchable"` Sortable bool `json:"sortable"` Type string `json:"type,omitempty"` Relation string `json:"relation,omitempty"` Select string `json:"select,omitempty"` } // ListFilter is one compiled config_filter scope. Values stay typed scalars. type ListFilter struct { Name string `json:"name"` Label string `json:"label,omitempty"` Type string `json:"type"` Column string `json:"column,omitempty"` Scope string `json:"scope,omitempty"` ModelClass string `json:"modelClass,omitempty"` NameFrom string `json:"nameFrom,omitempty"` Options []FormOption `json:"options,omitempty"` } // RowAction is a per-record link derived from recordUrl. type RowAction struct { Name string `json:"name"` Label string `json:"label,omitempty"` URL string `json:"url,omitempty"` } // BulkAction is a checkbox action. It carries no SQL. type BulkAction struct { Name string `json:"name"` Label string `json:"label,omitempty"` } // ListSchema is the boot-compiled list contract for one controller. // Labels stay as source keys until a request localizes a copy. type ListSchema struct { Title string `json:"title,omitempty"` ModelClass string `json:"modelClass,omitempty"` RecordURL string `json:"recordUrl,omitempty"` NoRecordsMessage string `json:"noRecordsMessage,omitempty"` RecordsPerPage int `json:"recordsPerPage"` PerPageOptions []int `json:"perPageOptions"` ShowSearch bool `json:"showSearch"` ShowSetup bool `json:"showSetup"` ShowCheckboxes bool `json:"showCheckboxes"` ShowSorting bool `json:"showSorting"` SearchTerm string `json:"searchTerm"` SearchPrompt string `json:"searchPrompt,omitempty"` DefaultSort *ListSort `json:"defaultSort,omitempty"` ToolbarButtons []string `json:"toolbarButtons"` Columns []ListColumn `json:"columns"` Filters []ListFilter `json:"filters"` RowActions []RowAction `json:"rowActions"` BulkActions []BulkAction `json:"bulkActions"` } // MarshalJSON keeps omitted collections as arrays so a partial copy cannot emit null. func (s ListSchema) MarshalJSON() ([]byte, error) { type alias ListSchema out := alias(s) if out.PerPageOptions == nil { out.PerPageOptions = []int{} } if out.ToolbarButtons == nil { out.ToolbarButtons = []string{} } if out.Columns == nil { out.Columns = []ListColumn{} } if out.Filters == nil { out.Filters = []ListFilter{} } if out.RowActions == nil { out.RowActions = []RowAction{} } if out.BulkActions == nil { out.BulkActions = []BulkAction{} } return json.Marshal(out) } // FormSchema is the locale-neutral form contract compiled once at boot. // Display strings stay as source keys until a request localizes a copy. type FormSchema struct { Name string `json:"name,omitempty"` ModelClass string `json:"modelClass,omitempty"` Fields []FormField `json:"fields"` } // FormView is one request's localized form, including the locale actually used. type FormView struct { Name string `json:"name,omitempty"` ModelClass string `json:"modelClass,omitempty"` Fields []FormField `json:"fields"` Meta FormMeta `json:"meta"` } // FormMeta reports the locale selected for a schema response. type FormMeta struct { Locale string `json:"locale"` } // FormField is one Winter field in source order. JSON keys keep Winter spelling. type FormField struct { Name string `json:"name"` Type string `json:"type"` Label string `json:"label,omitempty"` Comment string `json:"comment,omitempty"` Span string `json:"span,omitempty"` Tab string `json:"tab,omitempty"` Size string `json:"size,omitempty"` Context *fieldContext `json:"context,omitempty"` NameFrom string `json:"nameFrom,omitempty"` EmptyOption string `json:"emptyOption,omitempty"` Relation string `json:"relation,omitempty"` Required bool `json:"required,omitempty"` Default *jsonScalar `json:"default,omitempty"` Attributes map[string]jsonScalar `json:"attributes,omitempty"` Options []FormOption `json:"options,omitempty"` optionsMethod string } // FormOption is one dropdown choice. Value keeps the YAML scalar's JSON type. type FormOption struct { Value jsonScalar `json:"value"` Label string `json:"label"` } // jsonScalar is a JSON scalar that still emits false, 0, and empty string. type jsonScalar struct { raw json.RawMessage } func (s jsonScalar) MarshalJSON() ([]byte, error) { if len(s.raw) == 0 { return []byte("null"), nil } return s.raw, nil } // fieldContext preserves a single Winter context string or a source-ordered list. type fieldContext struct { single bool values []string } func (c fieldContext) MarshalJSON() ([]byte, error) { if c.single { text := "" if len(c.values) > 0 { text = c.values[0] } return json.Marshal(text) } values := c.values if values == nil { values = []string{} } return json.Marshal(values) }