fix(09): WR-07 keep relation column order from the YAML itself, not a fixed indentation
This commit is contained in:
@@ -7,7 +7,6 @@ import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.golem15.com/golem15/summercms/modules/lagoon"
|
||||
@@ -212,7 +211,7 @@ func compileRelations(pluginID string, ctl pact.AdminController, fsys fs.FS, for
|
||||
return nil, bootErr(pluginID, ctl.ID(), file, err)
|
||||
}
|
||||
var root yaml.MapSlice
|
||||
if err := decodeStrict(raw, &root); err != nil {
|
||||
if err := decodeStrictOrdered(raw, &root); err != nil {
|
||||
return nil, bootErr(pluginID, ctl.ID(), file, err)
|
||||
}
|
||||
out := map[string]*CompiledRelation{}
|
||||
@@ -247,8 +246,6 @@ func compileRelations(pluginID string, ctl pact.AdminController, fsys fs.FS, for
|
||||
if err != nil {
|
||||
return nil, bootErr(pluginID, ctl.ID(), file, fmt.Errorf("relation %s manage: %w", name, err))
|
||||
}
|
||||
orderRelationColumns(raw, &view)
|
||||
orderRelationColumns(raw, &manage)
|
||||
schema := &RelationSchema{Name: name, Label: doc.Label, View: view, Manage: manage}
|
||||
if doc.Messages != nil {
|
||||
schema.messageKeys = *doc.Messages
|
||||
@@ -274,24 +271,6 @@ func compileRelations(pluginID string, ctl pact.AdminController, fsys fs.FS, for
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func orderRelationColumns(raw []byte, panel *RelationPanel) {
|
||||
if panel == nil || len(panel.List.Columns) < 2 {
|
||||
return
|
||||
}
|
||||
source := string(raw)
|
||||
sort.SliceStable(panel.List.Columns, func(i, j int) bool {
|
||||
left := strings.Index(source, "\n "+panel.List.Columns[i].Key+":")
|
||||
right := strings.Index(source, "\n "+panel.List.Columns[j].Key+":")
|
||||
if left < 0 {
|
||||
left = len(source)
|
||||
}
|
||||
if right < 0 {
|
||||
right = len(source)
|
||||
}
|
||||
return left < right
|
||||
})
|
||||
}
|
||||
|
||||
func compileRelationPanel(doc relationPanelDocument, contract RelationContract, view bool) (RelationPanel, error) {
|
||||
cols := make([]RelationColumn, 0, len(doc.List.Columns))
|
||||
seen := map[string]struct{}{}
|
||||
|
||||
@@ -115,6 +115,77 @@ func TestRelationDefaultSort(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestRelationColumnOrderIsIndependentOfIndentation pins WR-07: column order
|
||||
// is the file's order in each panel, whatever the indentation, and the view and
|
||||
// manage panels do not share one order.
|
||||
func TestRelationColumnOrderIsIndependentOfIndentation(t *testing.T) {
|
||||
const twoSpace = `editors:
|
||||
label: demo.editors
|
||||
view:
|
||||
list:
|
||||
columns:
|
||||
username:
|
||||
label: demo.username
|
||||
email:
|
||||
label: demo.email
|
||||
toolbarButtons: link|unlink
|
||||
manage:
|
||||
list:
|
||||
columns:
|
||||
username:
|
||||
label: demo.username
|
||||
email:
|
||||
label: demo.email
|
||||
`
|
||||
for name, yamlText := range map[string]string{"two-space": twoSpace, "four-space": validRelationYAML} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
ctl := relationTestController{}
|
||||
fsys := relationTestFS(yamlText)
|
||||
form, err := CompileForm("acme.demo", ctl, fsys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
relations, err := compileRelations("acme.demo", ctl, fsys, form)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
schema := relations["editors"].Schema
|
||||
for panel, cols := range map[string][]RelationColumn{"view": schema.View.List.Columns, "manage": schema.Manage.List.Columns} {
|
||||
if len(cols) != 2 || cols[0].Key != "username" || cols[1].Key != "email" {
|
||||
t.Fatalf("%s columns = %+v, want username then email (file order, not alphabetical)", panel, cols)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const reversed = `editors:
|
||||
view:
|
||||
list:
|
||||
columns:
|
||||
username: {label: demo.username}
|
||||
email: {label: demo.email}
|
||||
manage:
|
||||
list:
|
||||
columns:
|
||||
email: {label: demo.email}
|
||||
username: {label: demo.username}
|
||||
`
|
||||
ctl := relationTestController{}
|
||||
fsys := relationTestFS(reversed)
|
||||
form, err := CompileForm("acme.demo", ctl, fsys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
relations, err := compileRelations("acme.demo", ctl, fsys, form)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
schema := relations["editors"].Schema
|
||||
if v, m := schema.View.List.Columns, schema.Manage.List.Columns; v[0].Key != "username" || m[0].Key != "email" {
|
||||
t.Fatalf("view=%+v manage=%+v, want each panel in its own file order", v, m)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRelationCandidateExclusions(t *testing.T) {
|
||||
contract := relationTestController{}.AdminRelationContracts()[0]
|
||||
ids, err := contract.ExcludedRelatedIDs(&relationTestOwner{OwnerID: 41})
|
||||
|
||||
@@ -18,6 +18,14 @@ func decodeStrict(raw []byte, dest any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// decodeStrictOrdered is decodeStrict with every nested mapping kept as an
|
||||
// ordered yaml.MapSlice, so a file that is decoded, re-marshalled per entry and
|
||||
// decoded again keeps its key order at any depth and any indentation.
|
||||
func decodeStrictOrdered(raw []byte, dest any) error {
|
||||
dec := yaml.NewDecoder(bytes.NewReader(raw), yaml.DisallowUnknownField(), yaml.UseOrderedMap())
|
||||
return dec.Decode(dest)
|
||||
}
|
||||
|
||||
func readAsset(fsys fs.FS, name string) ([]byte, error) {
|
||||
name = path.Clean(name)
|
||||
if name == "." || strings.HasPrefix(name, "..") || strings.Contains(name, "..") {
|
||||
|
||||
Reference in New Issue
Block a user