From 0e82048ae3aaea129b28cd0383f84c98e299dff6 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 1 Sep 2026 14:11:38 -0400 Subject: [PATCH] tui: Sort patches in a series based on patch number. When pressing space to expand a series, the patches are listed in order based on their patch ID. This does not always align with the ordering of the patches in the series. This can make it difficult to view patches in order or notice on large series that patches are missing (usually due to patchwork errors). This commit sorts the patches based on patch number. This solves the issues stated above. Signed-off-by: Mark Michelson --- tui/data.go | 4 ++ tui/data_test.go | 101 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/tui/data.go b/tui/data.go index 985dd41..546e607 100644 --- a/tui/data.go +++ b/tui/data.go @@ -427,6 +427,10 @@ func seriesToRow( }, } + sort.SliceStable(patches, func(i, j int) bool { + return patchNumber(patches[i].Name) < patchNumber(patches[j].Name) + }) + row.SubRows = make([][]string, len(patches)) row.SubRowStyles = make([]RowStyle, len(patches)) row.SubRowFetched = make([]bool, len(patches)) diff --git a/tui/data_test.go b/tui/data_test.go index 6bcc5fd..0962bac 100644 --- a/tui/data_test.go +++ b/tui/data_test.go @@ -1222,4 +1222,105 @@ func TestSeriesToRow_FetchedStatus(t *testing.T) { } } +func TestSeriesToRow_SubRowsSortedByPatchNumber(t *testing.T) { + d := time.Now().UTC().Format("2006-01-02T15:04:05") + s := db.SeriesRow{ + ID: 1, Name: "Sort test series", Date: d, TotalPatches: 4, + } + + t.Run("out of order", func(t *testing.T) { + patches := []db.PatchRow{ + {ID: 103, Name: "[PATCH 3/4] third", Date: d, State: "new"}, + {ID: 101, Name: "[PATCH 1/4] first", Date: d, State: "new"}, + {ID: 104, Name: "[PATCH 4/4] fourth", Date: d, State: "new"}, + {ID: 102, Name: "[PATCH 2/4] second", Date: d, State: "new"}, + } + row := seriesToRow(s, patches, "", nil, nil, 0, nil, nil, nil, nil) + if len(row.SubRows) != 4 { + t.Fatalf("SubRows = %d, want 4", len(row.SubRows)) + } + wantIDs := []string{"101", "102", "103", "104"} + for i, want := range wantIDs { + if row.SubRows[i][ColID] != want { + t.Errorf("SubRow[%d] ID = %q, want %q", + i, row.SubRows[i][ColID], want) + } + } + }) + + t.Run("already sorted", func(t *testing.T) { + patches := []db.PatchRow{ + {ID: 201, Name: "[PATCH 1/3] alpha", Date: d, State: "new"}, + {ID: 202, Name: "[PATCH 2/3] beta", Date: d, State: "new"}, + {ID: 203, Name: "[PATCH 3/3] gamma", Date: d, State: "new"}, + } + s3 := db.SeriesRow{ + ID: 2, Name: "Already sorted", Date: d, TotalPatches: 3, + } + row := seriesToRow(s3, patches, "", nil, nil, 0, nil, nil, nil, nil) + wantIDs := []string{"201", "202", "203"} + for i, want := range wantIDs { + if row.SubRows[i][ColID] != want { + t.Errorf("SubRow[%d] ID = %q, want %q", + i, row.SubRows[i][ColID], want) + } + } + }) + + t.Run("reverse order", func(t *testing.T) { + patches := []db.PatchRow{ + {ID: 303, Name: "[PATCH 3/3] c", Date: d, State: "new"}, + {ID: 302, Name: "[PATCH 2/3] b", Date: d, State: "new"}, + {ID: 301, Name: "[PATCH 1/3] a", Date: d, State: "new"}, + } + s3 := db.SeriesRow{ + ID: 3, Name: "Reversed", Date: d, TotalPatches: 3, + } + row := seriesToRow(s3, patches, "", nil, nil, 0, nil, nil, nil, nil) + wantIDs := []string{"301", "302", "303"} + for i, want := range wantIDs { + if row.SubRows[i][ColID] != want { + t.Errorf("SubRow[%d] ID = %q, want %q", + i, row.SubRows[i][ColID], want) + } + } + }) + + t.Run("no position marker preserves original order", func(t *testing.T) { + patches := []db.PatchRow{ + {ID: 402, Name: "second patch", Date: d, State: "new"}, + {ID: 401, Name: "first patch", Date: d, State: "new"}, + } + s2 := db.SeriesRow{ + ID: 4, Name: "No positions", Date: d, TotalPatches: 2, + } + row := seriesToRow(s2, patches, "", nil, nil, 0, nil, nil, nil, nil) + if row.SubRows[0][ColID] != "402" { + t.Errorf("SubRow[0] ID = %q, want 402 (original order preserved)", + row.SubRows[0][ColID]) + } + if row.SubRows[1][ColID] != "401" { + t.Errorf("SubRow[1] ID = %q, want 401 (original order preserved)", + row.SubRows[1][ColID]) + } + }) + + t.Run("with list prefix", func(t *testing.T) { + patches := []db.PatchRow{ + {ID: 502, Name: "[mylist,2/2] second", Date: d, State: "new"}, + {ID: 501, Name: "[mylist,1/2] first", Date: d, State: "new"}, + } + s2 := db.SeriesRow{ + ID: 5, Name: "List prefix test", Date: d, TotalPatches: 2, + } + row := seriesToRow(s2, patches, "mylist", nil, nil, 0, nil, nil, nil, nil) + if row.SubRows[0][ColID] != "501" { + t.Errorf("SubRow[0] ID = %q, want 501", row.SubRows[0][ColID]) + } + if row.SubRows[1][ColID] != "502" { + t.Errorf("SubRow[1] ID = %q, want 502", row.SubRows[1][ColID]) + } + }) +} + func boolPtr(v bool) *bool { return &v }