feat(10.1-01): render header and form partials into an allowlisted node tree
- fields.yaml type: partial with a bare path name and config_list.yaml
headerPartial resolve to {ConfigDir}/_{name}.htm, parsed at boot; the
controller must implement pact.AdminPartialData
- html/template render against a curated view model, then x/net/html
ParseFragment and a tag, attribute and URL allowlist with 64 KiB, 2000-node
and depth-32 caps; the model type and trusted template types are refused
- GET .../partials/{name} with optional ?id= loaded through the form scope
- golang.org/x/net becomes a direct requirement (D-18), no new module
This commit is contained in:
@@ -39,6 +39,7 @@ type listDocument struct {
|
||||
Toolbar *listToolbar `yaml:"toolbar"`
|
||||
Filter string `yaml:"filter"`
|
||||
Messages *listMessageKeys `yaml:"messages"`
|
||||
HeaderPartial string `yaml:"headerPartial"`
|
||||
}
|
||||
|
||||
type listSortDocument struct {
|
||||
@@ -137,6 +138,9 @@ func compileList(pluginID string, ctl pact.AdminController, fsys fs.FS) (*ListSc
|
||||
if doc.ShowSorting != nil {
|
||||
showSorting = *doc.ShowSorting
|
||||
}
|
||||
if doc.HeaderPartial != "" && !identifier(doc.HeaderPartial) {
|
||||
return nil, bootErr(pluginID, ctl.ID(), cfgPath, fmt.Errorf("headerPartial %q: %s", doc.HeaderPartial, partialPathHint))
|
||||
}
|
||||
rowActions := []RowAction{}
|
||||
if doc.RecordURL != "" {
|
||||
rowActions = append(rowActions, RowAction{
|
||||
@@ -172,6 +176,7 @@ func compileList(pluginID string, ctl pact.AdminController, fsys fs.FS) (*ListSc
|
||||
DefaultSort: sort,
|
||||
ToolbarButtons: buttons,
|
||||
ToolbarActions: toolbarActions,
|
||||
HeaderPartial: doc.HeaderPartial,
|
||||
Columns: columns,
|
||||
Filters: filters,
|
||||
RowActions: rowActions,
|
||||
|
||||
Reference in New Issue
Block a user