fix(graph): sort drive in "natural" order

Instead of doing a lexical sort we sort the drive/space in a more
"natural" order so that e.g. "Space 2" is sorted before "Space 10".

Related: https://github.com/opencloud-eu/web/issues/2430
This commit is contained in:
Ralf Haferkamp
2026-04-23 08:44:13 +02:00
committed by Ralf Haferkamp
parent 907cc6d766
commit e2f322791a
16 changed files with 76091 additions and 1 deletions
+5 -1
View File
@@ -27,6 +27,8 @@ import (
"github.com/pkg/errors"
merrors "go-micro.dev/v4/errors"
"golang.org/x/sync/errgroup"
"golang.org/x/text/collate"
"golang.org/x/text/language"
"google.golang.org/protobuf/proto"
"github.com/opencloud-eu/opencloud/pkg/l10n"
@@ -1143,8 +1145,10 @@ func sortSpaces(req *godata.GoDataRequest, spaces []*libregraph.Drive) ([]*libre
switch req.Query.OrderBy.OrderByItems[0].Field.Value {
case "name":
// Natural / numeric-aware ordering so e.g. "Project 2" < "Project 10".
c := collate.New(language.Und, collate.Numeric, collate.IgnoreCase)
less = func(i, j int) bool {
return strings.ToLower(spaces[i].GetName()) < strings.ToLower(spaces[j].GetName())
return c.CompareString(spaces[i].GetName(), spaces[j].GetName()) < 0
}
case "lastModifiedDateTime":
less = func(i, j int) bool {
@@ -123,6 +123,44 @@ func TestSort(t *testing.T) {
}
}
// TestSortNameNatural verifies that sorting drives by name uses a natural
// (numeric-aware) order, so "Project 10" sorts after "Project 2".
func TestSortNameNatural(t *testing.T) {
input := []*libregraph.Drive{
drive("a", "project", "Project 10", nil),
drive("b", "project", "Project 2", nil),
drive("c", "project", "Project 1", nil),
drive("d", "project", "Project 10a", nil),
}
want := []string{"Project 1", "Project 2", "Project 10", "Project 10a"}
query := godata.GoDataRequest{
Query: &godata.GoDataQuery{
OrderBy: &godata.GoDataOrderByQuery{
OrderByItems: []*godata.OrderByItem{
{Field: &godata.Token{Value: "name"}, Order: "asc"},
},
},
},
}
sorted, err := sortSpaces(&query, input)
require.NoError(t, err)
got := make([]string, 0, len(sorted))
for _, d := range sorted {
got = append(got, d.GetName())
}
assert.Equal(t, want, got)
// Descending must invert the natural order.
query.Query.OrderBy.OrderByItems[0].Order = _sortDescending
sortedDesc, err := sortSpaces(&query, input)
require.NoError(t, err)
gotDesc := make([]string, 0, len(sortedDesc))
for _, d := range sortedDesc {
gotDesc = append(gotDesc, d.GetName())
}
assert.Equal(t, []string{"Project 10a", "Project 10", "Project 2", "Project 1"}, gotDesc)
}
func TestSpaceNameValidation(t *testing.T) {
// set max length
_maxSpaceNameLength = 10