From b29d401233a912b613a06fe7befaff83a9821813 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Thu, 3 Apr 2025 02:58:35 +0000 Subject: [PATCH 1/9] Complete the grouping design within the existing table. --- modules/templates/util_date.go | 6 ++++++ templates/repo/commits_list.tmpl | 6 ++++++ web_src/css/repo.css | 6 +++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/modules/templates/util_date.go b/modules/templates/util_date.go index fc3f3f2339ae6..6fe7dc424a339 100644 --- a/modules/templates/util_date.go +++ b/modules/templates/util_date.go @@ -20,6 +20,12 @@ func NewDateUtils() *DateUtils { return (*DateUtils)(nil) // the util is stateless, and we do not need to create an instance } +func (du *DateUtils) DaysInterval(t1, t2 time.Time) int { + t1 = time.Date(t1.Year(), t1.Month(), t1.Day(), 0, 0, 0, 0, t1.Location()) + t2 = time.Date(t2.Year(), t2.Month(), t2.Day(), 0, 0, 0, 0, t2.Location()) + return int(t2.Sub(t1).Hours() / 24) +} + // AbsoluteShort renders in "Jan 01, 2006" format func (du *DateUtils) AbsoluteShort(time any) template.HTML { return dateTimeFormat("short", time) diff --git a/templates/repo/commits_list.tmpl b/templates/repo/commits_list.tmpl index e1bd6b73aedca..b5787363360bd 100644 --- a/templates/repo/commits_list.tmpl +++ b/templates/repo/commits_list.tmpl @@ -11,7 +11,13 @@ {{$commitRepoLink := $.RepoLink}}{{if $.CommitRepoLink}}{{$commitRepoLink = $.CommitRepoLink}}{{end}} + {{$groupDate := DateUtils.ParseLegacy ""}} {{range .Commits}} + {{$commitDate := ""}}{{if .Committer}}{{$commitDate = .Committer.When}}{{else}}{{$commitDate = .Author.When}}{{end}} + {{if ne (DateUtils.DaysInterval $groupDate $commitDate) 0}} + {{$groupDate = $commitDate}} + Commits on {{DateUtils.AbsoluteShort $groupDate}} + {{end}}
diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 87af299dad9fb..284103567c702 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -916,7 +916,11 @@ td .commit-summary { width: 200px; } -.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n) { +.repository #commits-table.ui.basic.striped.table tbody tr { + background-color: inherit !important; +} + +.repository #commits-table.ui.basic.striped.table tbody tr:not(.header):nth-child(2n) { background-color: var(--color-light) !important; } From 073c5933698a30f84aeb5a853d91b65be1dcdcfa Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 7 Apr 2025 00:36:42 +0000 Subject: [PATCH 2/9] revert --- modules/templates/util_date.go | 6 ------ templates/repo/commits_list.tmpl | 6 ------ web_src/css/repo.css | 6 +----- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/modules/templates/util_date.go b/modules/templates/util_date.go index 6fe7dc424a339..fc3f3f2339ae6 100644 --- a/modules/templates/util_date.go +++ b/modules/templates/util_date.go @@ -20,12 +20,6 @@ func NewDateUtils() *DateUtils { return (*DateUtils)(nil) // the util is stateless, and we do not need to create an instance } -func (du *DateUtils) DaysInterval(t1, t2 time.Time) int { - t1 = time.Date(t1.Year(), t1.Month(), t1.Day(), 0, 0, 0, 0, t1.Location()) - t2 = time.Date(t2.Year(), t2.Month(), t2.Day(), 0, 0, 0, 0, t2.Location()) - return int(t2.Sub(t1).Hours() / 24) -} - // AbsoluteShort renders in "Jan 01, 2006" format func (du *DateUtils) AbsoluteShort(time any) template.HTML { return dateTimeFormat("short", time) diff --git a/templates/repo/commits_list.tmpl b/templates/repo/commits_list.tmpl index adf8ceec88781..17c7240ee479e 100644 --- a/templates/repo/commits_list.tmpl +++ b/templates/repo/commits_list.tmpl @@ -11,13 +11,7 @@ {{$commitRepoLink := $.RepoLink}}{{if $.CommitRepoLink}}{{$commitRepoLink = $.CommitRepoLink}}{{end}} - {{$groupDate := DateUtils.ParseLegacy ""}} {{range .Commits}} - {{$commitDate := ""}}{{if .Committer}}{{$commitDate = .Committer.When}}{{else}}{{$commitDate = .Author.When}}{{end}} - {{if ne (DateUtils.DaysInterval $groupDate $commitDate) 0}} - {{$groupDate = $commitDate}} - Commits on {{DateUtils.AbsoluteShort $groupDate}} - {{end}}
diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 84d879b7b350e..91c1ee8607c6e 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -916,11 +916,7 @@ td .commit-summary { width: 200px; } -.repository #commits-table.ui.basic.striped.table tbody tr { - background-color: inherit !important; -} - -.repository #commits-table.ui.basic.striped.table tbody tr:not(.header):nth-child(2n) { +.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n) { background-color: var(--color-light) !important; } From 0581b27659c0ab7490461cb42f73d4f2e41429c5 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 7 Apr 2025 01:49:49 +0000 Subject: [PATCH 3/9] Refactor the structure of the commit list page to grouping by date. --- routers/web/repo/commit.go | 45 ++++++- routers/web/repo/compare.go | 2 +- routers/web/repo/pull.go | 2 +- .../repo/commits_list_group_by_date.tmpl | 113 ++++++++++++++++++ templates/repo/commits_table.tmpl | 4 +- tests/integration/git_general_test.go | 2 +- tests/integration/pull_status_test.go | 6 +- tests/integration/repo_commits_search_test.go | 2 +- tests/integration/repo_commits_test.go | 16 +-- tests/integration/view_test.go | 12 +- web_src/css/repo.css | 107 +++++++++++++++++ 11 files changed, 285 insertions(+), 26 deletions(-) create mode 100644 templates/repo/commits_list_group_by_date.tmpl diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 3569a356d1523..5ed6d06e5e232 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -11,6 +11,7 @@ import ( "net/http" "path" "strings" + "time" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" @@ -82,11 +83,12 @@ func Commits(ctx *context.Context) { ctx.ServerError("CommitsByRange", err) return } - ctx.Data["Commits"], err = processGitCommits(ctx, commits) + processedCommits, err := processGitCommits(ctx, commits) if err != nil { ctx.ServerError("processGitCommits", err) return } + ctx.Data["GroupCommits"] = GroupCommitsByDate(processedCommits) commitIDs := make([]string, 0, len(commits)) for _, c := range commits { commitIDs = append(commitIDs, c.ID.String()) @@ -198,11 +200,12 @@ func SearchCommits(ctx *context.Context) { return } ctx.Data["CommitCount"] = len(commits) - ctx.Data["Commits"], err = processGitCommits(ctx, commits) + processedCommits, err := processGitCommits(ctx, commits) if err != nil { ctx.ServerError("processGitCommits", err) return } + ctx.Data["GroupCommits"] = GroupCommitsByDate(processedCommits) ctx.Data["Keyword"] = query if all { @@ -244,11 +247,12 @@ func FileHistory(ctx *context.Context) { ctx.ServerError("CommitsByFileAndRange", err) return } - ctx.Data["Commits"], err = processGitCommits(ctx, commits) + processedCommits, err := processGitCommits(ctx, commits) if err != nil { ctx.ServerError("processGitCommits", err) return } + ctx.Data["GroupCommits"] = GroupCommitsByDate(processedCommits) ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name @@ -458,3 +462,38 @@ func processGitCommits(ctx *context.Context, gitCommits []*git.Commit) ([]*git_m } return commits, nil } + +// GroupedCommits defines the structure for grouped commits. +type GroupedCommits struct { + Date time.Time + Commits []*git_model.SignCommitWithStatuses +} + +// GroupCommitsByDate groups the commits by date (in days). +func GroupCommitsByDate(commits []*git_model.SignCommitWithStatuses) []GroupedCommits { + grouped := make(map[string][]*git_model.SignCommitWithStatuses) + + for _, commit := range commits { + var sigTime time.Time + if commit.Committer != nil { + sigTime = commit.Committer.When + } else if commit.Author != nil { + sigTime = commit.Author.When + } + + // Extract the date part + date := sigTime.Format("2006-01-02") + grouped[date] = append(grouped[date], commit) + } + + result := make([]GroupedCommits, 0, len(grouped)) + for dateStr, commitsGroup := range grouped { + date, _ := time.Parse("2006-01-02", dateStr) + result = append(result, GroupedCommits{ + Date: date, + Commits: commitsGroup, + }) + } + + return result +} diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 2c36477e6a85f..adc359954adc9 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -661,7 +661,7 @@ func PrepareCompareDiff( ctx.ServerError("processGitCommits", err) return false } - ctx.Data["Commits"] = commits + ctx.Data["GroupCommits"] = GroupCommitsByDate(commits) ctx.Data["CommitCount"] = len(commits) title := ci.HeadBranch diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index c72664f8e9035..77baaf86d0c60 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -627,7 +627,7 @@ func ViewPullCommits(ctx *context.Context) { ctx.ServerError("processGitCommits", err) return } - ctx.Data["Commits"] = commits + ctx.Data["GroupCommits"] = GroupCommitsByDate(commits) ctx.Data["CommitCount"] = len(commits) ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) diff --git a/templates/repo/commits_list_group_by_date.tmpl b/templates/repo/commits_list_group_by_date.tmpl new file mode 100644 index 0000000000000..d573a8bfb754c --- /dev/null +++ b/templates/repo/commits_list_group_by_date.tmpl @@ -0,0 +1,113 @@ +{{$index := 0}} +{{range .GroupCommits}} +{{$index = Eval $index "+" 1}} +
+ +
+
+ {{svg "octicon-git-commit"}} +
+
+ +
+

+ Commits on {{DateUtils.AbsoluteShort .Date}} +

+
+
    + {{range .Commits}} + {{$commitRepoLink := $.RepoLink}}{{if $.CommitRepoLink}}{{$commitRepoLink = $.CommitRepoLink}}{{end}} +
  • +
    +

    + + {{if $.PageIsWiki}} + {{.Summary | ctx.RenderUtils.RenderEmoji}} + {{else}} + {{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}} + {{ctx.RenderUtils.RenderCommitMessageLinkSubject .Message $commitLink ($.Repository.ComposeMetas ctx)}} + {{end}} + + {{if IsMultilineCommitMessage .Message}} + + {{end}} + {{if IsMultilineCommitMessage .Message}} +
    {{ctx.RenderUtils.RenderCommitBody .Message ($.Repository.ComposeMetas ctx)}}
    + {{end}} + {{if $.CommitsTagsMap}} + {{range (index $.CommitsTagsMap .ID.String)}} + {{- template "repo/tag/name" dict "RepoLink" $.Repository.Link "TagName" .TagName "IsRelease" (not .IsTag) -}} + {{end}} + {{end}} +

    +
    +
    +
    + {{$userName := .Author.Name}} + {{if .User}} + {{if and .User.FullName DefaultShowFullName}} + {{$userName = .User.FullName}} + {{end}} + {{ctx.AvatarUtils.Avatar .User 28 "tw-mr-2"}}{{$userName}} + {{else}} + {{ctx.AvatarUtils.AvatarByEmail .Author.Email .Author.Name 28 "tw-mr-2"}} + {{$userName}} + {{end}} +
    + + {{if .Committer}} + committed + {{else}} + authored + {{end}} + + {{if .Committer}} + {{DateUtils.TimeSince .Committer.When}} + {{else}} + {{DateUtils.TimeSince .Author.When}} + {{end}} + {{if .Statuses}} + ยท + {{end}} + {{template "repo/commit_statuses" dict "Status" .Status "Statuses" .Statuses}} +
    + +
  • + {{end}} +
+
+
+ +
+{{end}} diff --git a/templates/repo/commits_table.tmpl b/templates/repo/commits_table.tmpl index a0c5eacdd4b00..0da89e82ddd98 100644 --- a/templates/repo/commits_table.tmpl +++ b/templates/repo/commits_table.tmpl @@ -29,8 +29,8 @@
{{end}} -{{if and .Commits (gt .CommitCount 0)}} - {{template "repo/commits_list" .}} +{{if and .GroupCommits (gt .CommitCount 0)}} + {{template "repo/commits_list_group_by_date" .}} {{end}} {{template "base/paginate" .}} diff --git a/tests/integration/git_general_test.go b/tests/integration/git_general_test.go index 34fe212d50dc8..aa85126c204c6 100644 --- a/tests/integration/git_general_test.go +++ b/tests/integration/git_general_test.go @@ -669,7 +669,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { doc := NewHTMLParser(t, resp.Body) // Get first commit URL - commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Last().Attr("href") + commitURL, exists := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge a").Last().Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) diff --git a/tests/integration/pull_status_test.go b/tests/integration/pull_status_test.go index 63ffe9432035f..21adf807a49e9 100644 --- a/tests/integration/pull_status_test.go +++ b/tests/integration/pull_status_test.go @@ -45,7 +45,7 @@ func TestPullCreate_CommitStatus(t *testing.T) { doc := NewHTMLParser(t, resp.Body) // Get first commit URL - commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Last().Attr("href") + commitURL, exists := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge a").Last().Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) @@ -83,12 +83,12 @@ func TestPullCreate_CommitStatus(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) doc = NewHTMLParser(t, resp.Body) - commitURL, exists = doc.doc.Find("#commits-table tbody tr td.sha a").Last().Attr("href") + commitURL, exists = doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge a").Last().Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) assert.Equal(t, commitID, path.Base(commitURL)) - cls, ok := doc.doc.Find("#commits-table tbody tr td.message .commit-status").Last().Attr("class") + cls, ok := doc.doc.Find(".timeline.commits_list_group_by_date .description .commit-status").Last().Attr("class") assert.True(t, ok) assert.Contains(t, cls, statesIcons[status]) } diff --git a/tests/integration/repo_commits_search_test.go b/tests/integration/repo_commits_search_test.go index 9b05e3639912d..e0db972ee3ee1 100644 --- a/tests/integration/repo_commits_search_test.go +++ b/tests/integration/repo_commits_search_test.go @@ -22,7 +22,7 @@ func testRepoCommitsSearch(t *testing.T, query, commit string) { resp := session.MakeRequest(t, req, http.StatusOK) doc := NewHTMLParser(t, resp.Body) - sel := doc.doc.Find("#commits-table tbody tr td.sha a") + sel := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge a") assert.Equal(t, commit, strings.TrimSpace(sel.Text())) } diff --git a/tests/integration/repo_commits_test.go b/tests/integration/repo_commits_test.go index dee0aa6176097..e00eaca01e10b 100644 --- a/tests/integration/repo_commits_test.go +++ b/tests/integration/repo_commits_test.go @@ -33,7 +33,7 @@ func TestRepoCommits(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) doc := NewHTMLParser(t, resp.Body) - commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href") + commitURL, exists := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge .commit-id-short").Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) } @@ -50,7 +50,7 @@ func Test_ReposGitCommitListNotMaster(t *testing.T) { doc := NewHTMLParser(t, resp.Body) commits := []string{} - doc.doc.Find("#commits-table .commit-id-short").Each(func(i int, s *goquery.Selection) { + doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge .commit-id-short").Each(func(i int, s *goquery.Selection) { commitURL, exists := s.Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) @@ -63,7 +63,7 @@ func Test_ReposGitCommitListNotMaster(t *testing.T) { assert.Equal(t, "5099b81332712fe655e34e8dd63574f503f61811", commits[2]) userNames := []string{} - doc.doc.Find("#commits-table .author-wrapper").Each(func(i int, s *goquery.Selection) { + doc.doc.Find(".timeline.commits_list_group_by_date .description .author-wrapper").Each(func(i int, s *goquery.Selection) { userPath, exists := s.Attr("href") assert.True(t, exists) assert.NotEmpty(t, userPath) @@ -87,7 +87,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) { doc := NewHTMLParser(t, resp.Body) // Get first commit URL - commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href") + commitURL, exists := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge .commit-id-short").Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) @@ -105,7 +105,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) { doc = NewHTMLParser(t, resp.Body) // Check if commit status is displayed in message column (.tippy-target to ignore the tippy trigger) - sel := doc.doc.Find("#commits-table .message .tippy-target .commit-status") + sel := doc.doc.Find(".timeline.commits_list_group_by_date .description .tippy-target .commit-status") assert.Equal(t, 1, sel.Length()) for _, class := range classes { assert.True(t, sel.HasClass(class)) @@ -181,7 +181,7 @@ func TestRepoCommitsStatusParallel(t *testing.T) { doc := NewHTMLParser(t, resp.Body) // Get first commit URL - commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href") + commitURL, exists := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge .commit-id-short").Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) @@ -216,7 +216,7 @@ func TestRepoCommitsStatusMultiple(t *testing.T) { doc := NewHTMLParser(t, resp.Body) // Get first commit URL - commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href") + commitURL, exists := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge .commit-id-short").Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) @@ -241,6 +241,6 @@ func TestRepoCommitsStatusMultiple(t *testing.T) { doc = NewHTMLParser(t, resp.Body) // Check that the data-global-init="initCommitStatuses" (for trigger) and commit-status (svg) are present - sel := doc.doc.Find(`#commits-table .message [data-global-init="initCommitStatuses"] .commit-status`) + sel := doc.doc.Find(`.timeline.commits_list_group_by_date .description [data-global-init="initCommitStatuses"] .commit-status`) assert.Equal(t, 1, sel.Length()) } diff --git a/tests/integration/view_test.go b/tests/integration/view_test.go index 9ed3e30857522..67e2eeabffc31 100644 --- a/tests/integration/view_test.go +++ b/tests/integration/view_test.go @@ -48,9 +48,9 @@ func TestCommitListActions(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - AssertHTMLElement(t, htmlDoc, `.commit-list .copy-commit-id`, true) - AssertHTMLElement(t, htmlDoc, `.commit-list .view-single-diff`, false) - AssertHTMLElement(t, htmlDoc, `.commit-list .view-commit-path`, true) + AssertHTMLElement(t, htmlDoc, `.timeline.commits_list_group_by_date .copy-commit-id`, true) + AssertHTMLElement(t, htmlDoc, `.timeline.commits_list_group_by_date .view-single-diff`, false) + AssertHTMLElement(t, htmlDoc, `.timeline.commits_list_group_by_date .view-commit-path`, true) }) t.Run("RepoFileHistory", func(t *testing.T) { @@ -60,8 +60,8 @@ func TestCommitListActions(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - AssertHTMLElement(t, htmlDoc, `.commit-list .copy-commit-id`, true) - AssertHTMLElement(t, htmlDoc, `.commit-list .view-single-diff`, true) - AssertHTMLElement(t, htmlDoc, `.commit-list .view-commit-path`, true) + AssertHTMLElement(t, htmlDoc, `.timeline.commits_list_group_by_date .copy-commit-id`, true) + AssertHTMLElement(t, htmlDoc, `.timeline.commits_list_group_by_date .view-single-diff`, true) + AssertHTMLElement(t, htmlDoc, `.timeline.commits_list_group_by_date .view-commit-path`, true) }) } diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 91c1ee8607c6e..ebff4298d2e9d 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2282,3 +2282,110 @@ tbody.commit-list { .branch-selector-dropdown .scrolling.menu .loading-indicator { height: 4em; } + +.commits_list_group_by_date.timeline { + display: flex; + margin-left: 16px; + position: relative; + padding-bottom: 6px; +} + +.commits_list_group_by_date.timeline[data-index="1"] { + margin-top: 6px; +} + +.commits_list_group_by_date.timeline::before { + background-color: var(--color-timeline); + bottom: 0; + content: ""; + display: block; + left: 0; + position: absolute; + top: 0; + width: 2px; +} + +.commits_list_group_by_date.timeline .timeline-badge-wrapper { + position: relative; + z-index: 1; +} + +.commits_list_group_by_date.timeline .timeline-badge { + border-style: solid; + border-radius: var(--border-radius-full); + color: var(--color-text); + background-color: var(--color-box-body); + float: left; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + margin-left: -16px; + width: 34px; + height: 34px; + overflow: hidden; +} + +.commits_list_group_by_date.timeline .timeline-heading { + font-size: 15px; + font-weight: var(--font-weight-normal); + color: var(--color-text-light-2); + margin: 0; +} + +.commits_list_group_by_date.timeline .timeline-body { + max-width: 100%; + flex: auto; + padding-left: 5px; +} + +.commits_list_group_by_date.timeline .timeline-list-container { + border: 1px solid var(--color-secondary); + background: var(--color-box-body); + border-radius: var(--border-radius); +} + +.commits_list_group_by_date.timeline .commits-list { + list-style: none; + margin: 0; + padding: 0; + flex: auto; +} + +.commits_list_group_by_date.timeline .commits-list-item { + list-style: none; + display: grid; + gap: .5rem; + min-height: 2rem; + position: relative; + --core-grid-template-columns: minmax(30%, 1fr); + --last-grid-template-column: minmax(0, max-content); + grid-template-columns: var(--core-grid-template-columns) var(--last-grid-template-column); + grid-template-areas: "primary metadata" "main-content metadata"; + grid-template-rows: repeat(2, auto); +} + +.commits_list_group_by_date.timeline .commits-list-item:not(:last-child) { + border-bottom: 1px solid var(--color-secondary); +} + +.commits_list_group_by_date.timeline .commits-list-item:hover { + background-color: var(--color-hover) +} + +.commits_list_group_by_date.timeline .commits-list-item .title { + grid-area: primary; +} + +.commits_list_group_by_date.timeline .commits-list-item .description { + grid-area: main-content; +} + +.commits_list_group_by_date.timeline .commits-list-item .metadata { + grid-area: metadata; +} + +.commits_list_group_by_date.timeline .author img { + width: 16px; + height: 16px; +} From b9dfd3e329a602cd9d0944bc28542ade3dfa8a53 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 14 Apr 2025 00:48:07 +0000 Subject: [PATCH 4/9] Merge branch main into refactor-commit-list-page-group-by-date --- .../repo/commits_list_group_by_date.tmpl | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/templates/repo/commits_list_group_by_date.tmpl b/templates/repo/commits_list_group_by_date.tmpl index d573a8bfb754c..e01fd5d58a80f 100644 --- a/templates/repo/commits_list_group_by_date.tmpl +++ b/templates/repo/commits_list_group_by_date.tmpl @@ -21,18 +21,18 @@

- {{if $.PageIsWiki}} - {{.Summary | ctx.RenderUtils.RenderEmoji}} - {{else}} - {{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}} - {{ctx.RenderUtils.RenderCommitMessageLinkSubject .Message $commitLink ($.Repository.ComposeMetas ctx)}} - {{end}} + {{if $.PageIsWiki}} + {{.Summary | ctx.RenderUtils.RenderEmoji}} + {{else}} + {{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}} + {{ctx.RenderUtils.RenderCommitMessageLinkSubject .Message $commitLink ($.Repository.ComposeCommentMetas ctx)}} + {{end}} {{if IsMultilineCommitMessage .Message}} {{end}} {{if IsMultilineCommitMessage .Message}} -
{{ctx.RenderUtils.RenderCommitBody .Message ($.Repository.ComposeMetas ctx)}}
+
{{ctx.RenderUtils.RenderCommitBody .Message ($.Repository.ComposeCommentMetas ctx)}}
{{end}} {{if $.CommitsTagsMap}} {{range (index $.CommitsTagsMap .ID.String)}} @@ -90,15 +90,15 @@ {{/* at the moment, wiki doesn't support these "view" links like "view at history point" */}} {{if not $.PageIsWiki}} {{/* view single file diff */}} - {{if $.FileName}} + {{if $.FileTreePath}} {{svg "octicon-file-diff"}} {{end}} {{/* view at history point */}} {{$viewCommitLink := printf "%s/src/commit/%s" $commitRepoLink (PathEscape .ID.String)}} - {{if $.FileName}}{{$viewCommitLink = printf "%s/%s" $viewCommitLink (PathEscapeSegments $.FileName)}}{{end}} + {{if $.FileTreePath}}{{$viewCommitLink = printf "%s/%s" $viewCommitLink (PathEscapeSegments $.FileTreePath)}}{{end}} {{svg "octicon-file-code"}} {{end}}

From d63aca0075f81fe73a47bc3b29c7b4c04fbafb21 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 21 Apr 2025 00:18:35 +0000 Subject: [PATCH 5/9] fix --- .../repo/commits_list_group_by_date.tmpl | 2 +- templates/repo/commits_table.tmpl | 2 +- tests/integration/pull_status_test.go | 6 ++-- tests/integration/repo_commits_test.go | 16 +++++----- tests/integration/view_test.go | 12 +++---- web_src/css/repo.css | 32 +++++++++---------- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/templates/repo/commits_list_group_by_date.tmpl b/templates/repo/commits_list_group_by_date.tmpl index e01fd5d58a80f..4fac28a49963a 100644 --- a/templates/repo/commits_list_group_by_date.tmpl +++ b/templates/repo/commits_list_group_by_date.tmpl @@ -1,7 +1,7 @@ {{$index := 0}} {{range .GroupCommits}} {{$index = Eval $index "+" 1}} -
+
diff --git a/templates/repo/commits_table.tmpl b/templates/repo/commits_table.tmpl index 0da89e82ddd98..fc5f3f9d7deb9 100644 --- a/templates/repo/commits_table.tmpl +++ b/templates/repo/commits_table.tmpl @@ -30,7 +30,7 @@ {{end}} {{if and .GroupCommits (gt .CommitCount 0)}} - {{template "repo/commits_list_group_by_date" .}} + {{template "repo/commits-list-group-by-date" .}} {{end}} {{template "base/paginate" .}} diff --git a/tests/integration/pull_status_test.go b/tests/integration/pull_status_test.go index 21adf807a49e9..95da68f3bfd4f 100644 --- a/tests/integration/pull_status_test.go +++ b/tests/integration/pull_status_test.go @@ -45,7 +45,7 @@ func TestPullCreate_CommitStatus(t *testing.T) { doc := NewHTMLParser(t, resp.Body) // Get first commit URL - commitURL, exists := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge a").Last().Attr("href") + commitURL, exists := doc.doc.Find(".timeline.commits-list-group-by-date .commit_sign_badge a").Last().Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) @@ -83,12 +83,12 @@ func TestPullCreate_CommitStatus(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) doc = NewHTMLParser(t, resp.Body) - commitURL, exists = doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge a").Last().Attr("href") + commitURL, exists = doc.doc.Find(".timeline.commits-list-group-by-date .commit_sign_badge a").Last().Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) assert.Equal(t, commitID, path.Base(commitURL)) - cls, ok := doc.doc.Find(".timeline.commits_list_group_by_date .description .commit-status").Last().Attr("class") + cls, ok := doc.doc.Find(".timeline.commits-list-group-by-date .description .commit-status").Last().Attr("class") assert.True(t, ok) assert.Contains(t, cls, statesIcons[status]) } diff --git a/tests/integration/repo_commits_test.go b/tests/integration/repo_commits_test.go index e00eaca01e10b..c5a6132e48182 100644 --- a/tests/integration/repo_commits_test.go +++ b/tests/integration/repo_commits_test.go @@ -33,7 +33,7 @@ func TestRepoCommits(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) doc := NewHTMLParser(t, resp.Body) - commitURL, exists := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge .commit-id-short").Attr("href") + commitURL, exists := doc.doc.Find(".timeline.commits-list-group-by-date .commit_sign_badge .commit-id-short").Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) } @@ -50,7 +50,7 @@ func Test_ReposGitCommitListNotMaster(t *testing.T) { doc := NewHTMLParser(t, resp.Body) commits := []string{} - doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge .commit-id-short").Each(func(i int, s *goquery.Selection) { + doc.doc.Find(".timeline.commits-list-group-by-date .commit_sign_badge .commit-id-short").Each(func(i int, s *goquery.Selection) { commitURL, exists := s.Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) @@ -63,7 +63,7 @@ func Test_ReposGitCommitListNotMaster(t *testing.T) { assert.Equal(t, "5099b81332712fe655e34e8dd63574f503f61811", commits[2]) userNames := []string{} - doc.doc.Find(".timeline.commits_list_group_by_date .description .author-wrapper").Each(func(i int, s *goquery.Selection) { + doc.doc.Find(".timeline.commits-list-group-by-date .description .author-wrapper").Each(func(i int, s *goquery.Selection) { userPath, exists := s.Attr("href") assert.True(t, exists) assert.NotEmpty(t, userPath) @@ -87,7 +87,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) { doc := NewHTMLParser(t, resp.Body) // Get first commit URL - commitURL, exists := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge .commit-id-short").Attr("href") + commitURL, exists := doc.doc.Find(".timeline.commits-list-group-by-date .commit_sign_badge .commit-id-short").Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) @@ -105,7 +105,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) { doc = NewHTMLParser(t, resp.Body) // Check if commit status is displayed in message column (.tippy-target to ignore the tippy trigger) - sel := doc.doc.Find(".timeline.commits_list_group_by_date .description .tippy-target .commit-status") + sel := doc.doc.Find(".timeline.commits-list-group-by-date .description .tippy-target .commit-status") assert.Equal(t, 1, sel.Length()) for _, class := range classes { assert.True(t, sel.HasClass(class)) @@ -181,7 +181,7 @@ func TestRepoCommitsStatusParallel(t *testing.T) { doc := NewHTMLParser(t, resp.Body) // Get first commit URL - commitURL, exists := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge .commit-id-short").Attr("href") + commitURL, exists := doc.doc.Find(".timeline.commits-list-group-by-date .commit_sign_badge .commit-id-short").Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) @@ -216,7 +216,7 @@ func TestRepoCommitsStatusMultiple(t *testing.T) { doc := NewHTMLParser(t, resp.Body) // Get first commit URL - commitURL, exists := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge .commit-id-short").Attr("href") + commitURL, exists := doc.doc.Find(".timeline.commits-list-group-by-date .commit_sign_badge .commit-id-short").Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) @@ -241,6 +241,6 @@ func TestRepoCommitsStatusMultiple(t *testing.T) { doc = NewHTMLParser(t, resp.Body) // Check that the data-global-init="initCommitStatuses" (for trigger) and commit-status (svg) are present - sel := doc.doc.Find(`.timeline.commits_list_group_by_date .description [data-global-init="initCommitStatuses"] .commit-status`) + sel := doc.doc.Find(`.timeline.commits-list-group-by-date .description [data-global-init="initCommitStatuses"] .commit-status`) assert.Equal(t, 1, sel.Length()) } diff --git a/tests/integration/view_test.go b/tests/integration/view_test.go index 67e2eeabffc31..8891ca432c1a8 100644 --- a/tests/integration/view_test.go +++ b/tests/integration/view_test.go @@ -48,9 +48,9 @@ func TestCommitListActions(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - AssertHTMLElement(t, htmlDoc, `.timeline.commits_list_group_by_date .copy-commit-id`, true) - AssertHTMLElement(t, htmlDoc, `.timeline.commits_list_group_by_date .view-single-diff`, false) - AssertHTMLElement(t, htmlDoc, `.timeline.commits_list_group_by_date .view-commit-path`, true) + AssertHTMLElement(t, htmlDoc, `.timeline.commits-list-group-by-date .copy-commit-id`, true) + AssertHTMLElement(t, htmlDoc, `.timeline.commits-list-group-by-date .view-single-diff`, false) + AssertHTMLElement(t, htmlDoc, `.timeline.commits-list-group-by-date .view-commit-path`, true) }) t.Run("RepoFileHistory", func(t *testing.T) { @@ -60,8 +60,8 @@ func TestCommitListActions(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - AssertHTMLElement(t, htmlDoc, `.timeline.commits_list_group_by_date .copy-commit-id`, true) - AssertHTMLElement(t, htmlDoc, `.timeline.commits_list_group_by_date .view-single-diff`, true) - AssertHTMLElement(t, htmlDoc, `.timeline.commits_list_group_by_date .view-commit-path`, true) + AssertHTMLElement(t, htmlDoc, `.timeline.commits-list-group-by-date .copy-commit-id`, true) + AssertHTMLElement(t, htmlDoc, `.timeline.commits-list-group-by-date .view-single-diff`, true) + AssertHTMLElement(t, htmlDoc, `.timeline.commits-list-group-by-date .view-commit-path`, true) }) } diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 53da2072baed2..9970a01580c98 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2280,18 +2280,18 @@ tbody.commit-list { height: 4em; } -.commits_list_group_by_date.timeline { +.commits-list-group-by-date.timeline { display: flex; margin-left: 16px; position: relative; padding-bottom: 6px; } -.commits_list_group_by_date.timeline[data-index="1"] { +.commits-list-group-by-date.timeline[data-index="1"] { margin-top: 6px; } -.commits_list_group_by_date.timeline::before { +.commits-list-group-by-date.timeline::before { background-color: var(--color-timeline); bottom: 0; content: ""; @@ -2302,12 +2302,12 @@ tbody.commit-list { width: 2px; } -.commits_list_group_by_date.timeline .timeline-badge-wrapper { +.commits-list-group-by-date.timeline .timeline-badge-wrapper { position: relative; z-index: 1; } -.commits_list_group_by_date.timeline .timeline-badge { +.commits-list-group-by-date.timeline .timeline-badge { border-style: solid; border-radius: var(--border-radius-full); color: var(--color-text); @@ -2323,33 +2323,33 @@ tbody.commit-list { overflow: hidden; } -.commits_list_group_by_date.timeline .timeline-heading { +.commits-list-group-by-date.timeline .timeline-heading { font-size: 15px; font-weight: var(--font-weight-normal); color: var(--color-text-light-2); margin: 0; } -.commits_list_group_by_date.timeline .timeline-body { +.commits-list-group-by-date.timeline .timeline-body { max-width: 100%; flex: auto; padding-left: 5px; } -.commits_list_group_by_date.timeline .timeline-list-container { +.commits-list-group-by-date.timeline .timeline-list-container { border: 1px solid var(--color-secondary); background: var(--color-box-body); border-radius: var(--border-radius); } -.commits_list_group_by_date.timeline .commits-list { +.commits-list-group-by-date.timeline .commits-list { list-style: none; margin: 0; padding: 0; flex: auto; } -.commits_list_group_by_date.timeline .commits-list-item { +.commits-list-group-by-date.timeline .commits-list-item { list-style: none; display: grid; gap: .5rem; @@ -2362,27 +2362,27 @@ tbody.commit-list { grid-template-rows: repeat(2, auto); } -.commits_list_group_by_date.timeline .commits-list-item:not(:last-child) { +.commits-list-group-by-date.timeline .commits-list-item:not(:last-child) { border-bottom: 1px solid var(--color-secondary); } -.commits_list_group_by_date.timeline .commits-list-item:hover { +.commits-list-group-by-date.timeline .commits-list-item:hover { background-color: var(--color-hover) } -.commits_list_group_by_date.timeline .commits-list-item .title { +.commits-list-group-by-date.timeline .commits-list-item .title { grid-area: primary; } -.commits_list_group_by_date.timeline .commits-list-item .description { +.commits-list-group-by-date.timeline .commits-list-item .description { grid-area: main-content; } -.commits_list_group_by_date.timeline .commits-list-item .metadata { +.commits-list-group-by-date.timeline .commits-list-item .metadata { grid-area: metadata; } -.commits_list_group_by_date.timeline .author img { +.commits-list-group-by-date.timeline .author img { width: 16px; height: 16px; } From 69e05054cda04a09acaf0654cbaaf64f3922c26a Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 21 Apr 2025 00:38:02 +0000 Subject: [PATCH 6/9] fix --- templates/repo/commits_list_group_by_date.tmpl | 4 +--- templates/repo/commits_table.tmpl | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/templates/repo/commits_list_group_by_date.tmpl b/templates/repo/commits_list_group_by_date.tmpl index 4fac28a49963a..9f7c1698624e2 100644 --- a/templates/repo/commits_list_group_by_date.tmpl +++ b/templates/repo/commits_list_group_by_date.tmpl @@ -1,7 +1,5 @@ -{{$index := 0}} {{range .GroupCommits}} -{{$index = Eval $index "+" 1}} -
+
diff --git a/templates/repo/commits_table.tmpl b/templates/repo/commits_table.tmpl index fc5f3f9d7deb9..0da89e82ddd98 100644 --- a/templates/repo/commits_table.tmpl +++ b/templates/repo/commits_table.tmpl @@ -30,7 +30,7 @@ {{end}} {{if and .GroupCommits (gt .CommitCount 0)}} - {{template "repo/commits-list-group-by-date" .}} + {{template "repo/commits_list_group_by_date" .}} {{end}} {{template "base/paginate" .}} From 22f9a514ea156f2cbcccea994121a0099a5b49ec Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 21 Apr 2025 00:50:07 +0000 Subject: [PATCH 7/9] fix --- templates/repo/commits_list_group_by_date.tmpl | 8 ++++---- web_src/css/repo.css | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/repo/commits_list_group_by_date.tmpl b/templates/repo/commits_list_group_by_date.tmpl index 9f7c1698624e2..f129f0c10a114 100644 --- a/templates/repo/commits_list_group_by_date.tmpl +++ b/templates/repo/commits_list_group_by_date.tmpl @@ -1,5 +1,5 @@ -{{range .GroupCommits}} -
+{{range $index, $groupCommit := .GroupCommits}} +
@@ -9,11 +9,11 @@

- Commits on {{DateUtils.AbsoluteShort .Date}} + Commits on {{DateUtils.AbsoluteShort $groupCommit.Date}}

    - {{range .Commits}} + {{range $groupCommit.Commits}} {{$commitRepoLink := $.RepoLink}}{{if $.CommitRepoLink}}{{$commitRepoLink = $.CommitRepoLink}}{{end}}
  • diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 9970a01580c98..fa41e1f1f083d 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2287,7 +2287,7 @@ tbody.commit-list { padding-bottom: 6px; } -.commits-list-group-by-date.timeline[data-index="1"] { +.commits-list-group-by-date.timeline[data-index="0"] { margin-top: 6px; } From fca09922bb7d9f4dc827131bc8bf99cc59b3952d Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 21 Apr 2025 09:03:48 +0800 Subject: [PATCH 8/9] fix --- tests/integration/git_general_test.go | 2 +- tests/integration/repo_commits_search_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/git_general_test.go b/tests/integration/git_general_test.go index aa85126c204c6..2f4f464964b46 100644 --- a/tests/integration/git_general_test.go +++ b/tests/integration/git_general_test.go @@ -669,7 +669,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { doc := NewHTMLParser(t, resp.Body) // Get first commit URL - commitURL, exists := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge a").Last().Attr("href") + commitURL, exists := doc.doc.Find(".timeline.commits-list-group-by-date .commit_sign_badge a").Last().Attr("href") assert.True(t, exists) assert.NotEmpty(t, commitURL) diff --git a/tests/integration/repo_commits_search_test.go b/tests/integration/repo_commits_search_test.go index e0db972ee3ee1..aa0b840ded145 100644 --- a/tests/integration/repo_commits_search_test.go +++ b/tests/integration/repo_commits_search_test.go @@ -22,7 +22,7 @@ func testRepoCommitsSearch(t *testing.T, query, commit string) { resp := session.MakeRequest(t, req, http.StatusOK) doc := NewHTMLParser(t, resp.Body) - sel := doc.doc.Find(".timeline.commits_list_group_by_date .commit_sign_badge a") + sel := doc.doc.Find(".timeline.commits-list-group-by-date .commit_sign_badge a") assert.Equal(t, commit, strings.TrimSpace(sel.Text())) } From 948ff41b1ac1d9a485107ba60772976421d26286 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 21 Apr 2025 01:58:33 +0000 Subject: [PATCH 9/9] fix --- routers/web/repo/commit.go | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 810aa0ca7abd7..575386b5f7ca4 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -10,6 +10,7 @@ import ( "html/template" "net/http" "path" + "sort" "strings" "time" @@ -28,6 +29,7 @@ import ( "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" asymkey_service "code.gitea.io/gitea/services/asymkey" "code.gitea.io/gitea/services/context" @@ -465,13 +467,14 @@ func processGitCommits(ctx *context.Context, gitCommits []*git.Commit) ([]*git_m // GroupedCommits defines the structure for grouped commits. type GroupedCommits struct { - Date time.Time + Date timeutil.TimeStamp Commits []*git_model.SignCommitWithStatuses } // GroupCommitsByDate groups the commits by date (in days). func GroupCommitsByDate(commits []*git_model.SignCommitWithStatuses) []GroupedCommits { - grouped := make(map[string][]*git_model.SignCommitWithStatuses) + // Use Unix timestamp of date as key (truncated to day) + grouped := make(map[int64][]*git_model.SignCommitWithStatuses) for _, commit := range commits { var sigTime time.Time @@ -481,17 +484,32 @@ func GroupCommitsByDate(commits []*git_model.SignCommitWithStatuses) []GroupedCo sigTime = commit.Author.When } - // Extract the date part - date := sigTime.Format("2006-01-02") - grouped[date] = append(grouped[date], commit) + // Truncate time to date part (remove hours, minutes, seconds) + year, month, day := sigTime.Date() + dateOnly := time.Date(year, month, day, 0, 0, 0, 0, sigTime.Location()) + dateUnix := dateOnly.Unix() + + grouped[dateUnix] = append(grouped[dateUnix], commit) } + // Create result slice with pre-allocated capacity result := make([]GroupedCommits, 0, len(grouped)) - for dateStr, commitsGroup := range grouped { - date, _ := time.Parse("2006-01-02", dateStr) + + // Collect all dates and sort them + dates := make([]int64, 0, len(grouped)) + for dateUnix := range grouped { + dates = append(dates, dateUnix) + } + // Sort dates in descending order (most recent first) + sort.Slice(dates, func(i, j int) bool { + return dates[i] > dates[j] + }) + + // Build result in sorted order + for _, dateUnix := range dates { result = append(result, GroupedCommits{ - Date: date, - Commits: commitsGroup, + Date: timeutil.TimeStamp(dateUnix), + Commits: grouped[dateUnix], }) }