Reshape pull commits tab
- SHA
a32da09e768c8dbc456d23423692eb7a338b59d3- Parents
-
04b0fef - Tree
91a802c
a32da09
a32da09e768c8dbc456d23423692eb7a338b59d304b0fef
91a802c| Status | File | + | - |
|---|---|---|---|
| M |
internal/web/handlers/repo/pulls.go
|
65 | 1 |
| M |
internal/web/static/css/shithub.css
|
101 | 4 |
| M |
internal/web/templates/repo/pull_view.html
|
36 | 9 |
internal/web/handlers/repo/pulls.gomodified@@ -11,6 +11,7 @@ import ( | ||
| 11 | 11 | "sort" |
| 12 | 12 | "strconv" |
| 13 | 13 | "strings" |
| 14 | + "time" | |
| 14 | 15 | |
| 15 | 16 | "github.com/go-chi/chi/v5" |
| 16 | 17 | "github.com/jackc/pgx/v5" |
@@ -23,6 +24,7 @@ import ( | ||
| 23 | 24 | "github.com/tenseleyFlow/shithub/internal/pulls" |
| 24 | 25 | pullsdb "github.com/tenseleyFlow/shithub/internal/pulls/sqlc" |
| 25 | 26 | repogit "github.com/tenseleyFlow/shithub/internal/repos/git" |
| 27 | + "github.com/tenseleyFlow/shithub/internal/repos/identity" | |
| 26 | 28 | reposdb "github.com/tenseleyFlow/shithub/internal/repos/sqlc" |
| 27 | 29 | "github.com/tenseleyFlow/shithub/internal/social" |
| 28 | 30 | "github.com/tenseleyFlow/shithub/internal/web/middleware" |
@@ -58,6 +60,20 @@ type pullFileView struct { | ||
| 58 | 60 | Name string |
| 59 | 61 | } |
| 60 | 62 | |
| 63 | +type pullCommitView struct { | |
| 64 | + C pullsdb.PullRequestCommit | |
| 65 | + Author identity.Resolved | |
| 66 | + ShortSHA string | |
| 67 | + When time.Time | |
| 68 | + HasWhen bool | |
| 69 | + AuthorLabel string | |
| 70 | +} | |
| 71 | + | |
| 72 | +type pullCommitGroup struct { | |
| 73 | + Title string | |
| 74 | + Commits []pullCommitView | |
| 75 | +} | |
| 76 | + | |
| 61 | 77 | // MountPulls registers /{owner}/{repo}/pulls* routes. Reads are |
| 62 | 78 | // public (subject to policy.Can(ActionPullRead)); writes require auth. |
| 63 | 79 | // The merge route runs synchronously inside the request: pulls.Merge |
@@ -538,11 +554,59 @@ func (h *Handlers) pullCommits(w http.ResponseWriter, r *http.Request) { | ||
| 538 | 554 | return |
| 539 | 555 | } |
| 540 | 556 | commits, _ := pullsdb.New().ListPullRequestCommits(r.Context(), h.d.Pool, pr.IID) |
| 557 | + commitGroups := pullCommitGroups(r.Context(), commits, identity.New(h.d.Pool)) | |
| 541 | 558 | h.renderPullPage(w, r, "commits", map[string]any{ |
| 542 | - "Commits": commits, | |
| 559 | + "CommitGroups": commitGroups, | |
| 543 | 560 | }) |
| 544 | 561 | } |
| 545 | 562 | |
| 563 | +func pullCommitGroups(ctx context.Context, commits []pullsdb.PullRequestCommit, resolver *identity.Resolver) []pullCommitGroup { | |
| 564 | + groups := make([]pullCommitGroup, 0, 2) | |
| 565 | + for _, commit := range commits { | |
| 566 | + when, hasWhen := pullCommitWhen(commit) | |
| 567 | + title := "Commits" | |
| 568 | + if hasWhen { | |
| 569 | + title = "Commits on " + when.Format("January 2, 2006") | |
| 570 | + } | |
| 571 | + if len(groups) == 0 || groups[len(groups)-1].Title != title { | |
| 572 | + groups = append(groups, pullCommitGroup{Title: title}) | |
| 573 | + } | |
| 574 | + author := identity.Resolved{} | |
| 575 | + if resolver != nil { | |
| 576 | + author = resolver.Resolve(ctx, commit.AuthorEmail) | |
| 577 | + } | |
| 578 | + authorLabel := commit.AuthorName | |
| 579 | + if author.User && author.DisplayName != "" { | |
| 580 | + authorLabel = author.DisplayName | |
| 581 | + } else if author.User { | |
| 582 | + authorLabel = author.Username | |
| 583 | + } | |
| 584 | + shortSHA := commit.Sha | |
| 585 | + if len(shortSHA) > 7 { | |
| 586 | + shortSHA = shortSHA[:7] | |
| 587 | + } | |
| 588 | + groups[len(groups)-1].Commits = append(groups[len(groups)-1].Commits, pullCommitView{ | |
| 589 | + C: commit, | |
| 590 | + Author: author, | |
| 591 | + ShortSHA: shortSHA, | |
| 592 | + When: when, | |
| 593 | + HasWhen: hasWhen, | |
| 594 | + AuthorLabel: authorLabel, | |
| 595 | + }) | |
| 596 | + } | |
| 597 | + return groups | |
| 598 | +} | |
| 599 | + | |
| 600 | +func pullCommitWhen(commit pullsdb.PullRequestCommit) (time.Time, bool) { | |
| 601 | + if commit.CommittedAt.Valid { | |
| 602 | + return commit.CommittedAt.Time, true | |
| 603 | + } | |
| 604 | + if commit.AuthoredAt.Valid { | |
| 605 | + return commit.AuthoredAt.Time, true | |
| 606 | + } | |
| 607 | + return time.Time{}, false | |
| 608 | +} | |
| 609 | + | |
| 546 | 610 | // pullFiles renders the Files Changed tab. Uses the existing diff |
| 547 | 611 | // renderer fed from base..head (three-dot via FromMergeBase). |
| 548 | 612 | func (h *Handlers) pullFiles(w http.ResponseWriter, r *http.Request) { |
internal/web/static/css/shithub.cssmodified@@ -3095,10 +3095,107 @@ button.shithub-repo-action { | ||
| 3095 | 3095 | .shithub-pull-refs { display: flex; gap: 0.4rem; align-items: flex-end; } |
| 3096 | 3096 | .shithub-pull-refs label { flex: 1; } |
| 3097 | 3097 | .shithub-pull-arrow { font-size: 1.4rem; padding: 0 0.4rem; align-self: center; } |
| 3098 | -.shithub-pull-commits { list-style: none; padding: 0; } | |
| 3099 | -.shithub-pull-commits li { | |
| 3100 | - padding: 0.4rem 0; border-bottom: 1px solid var(--border-default); | |
| 3101 | - display: flex; gap: 0.6rem; align-items: baseline; | |
| 3098 | +.shithub-sr-only { | |
| 3099 | + position: absolute; | |
| 3100 | + width: 1px; | |
| 3101 | + height: 1px; | |
| 3102 | + padding: 0; | |
| 3103 | + margin: -1px; | |
| 3104 | + overflow: hidden; | |
| 3105 | + clip: rect(0, 0, 0, 0); | |
| 3106 | + white-space: nowrap; | |
| 3107 | + border: 0; | |
| 3108 | +} | |
| 3109 | +.shithub-pull-commits { | |
| 3110 | + display: flex; | |
| 3111 | + flex-direction: column; | |
| 3112 | + gap: 1rem; | |
| 3113 | + max-width: 56rem; | |
| 3114 | + margin-top: 1rem; | |
| 3115 | +} | |
| 3116 | +.shithub-pull-commit-group { | |
| 3117 | + display: grid; | |
| 3118 | + grid-template-columns: 2rem minmax(0, 1fr); | |
| 3119 | + gap: 0.75rem; | |
| 3120 | + position: relative; | |
| 3121 | +} | |
| 3122 | +.shithub-pull-commit-group::before { | |
| 3123 | + content: ""; | |
| 3124 | + position: absolute; | |
| 3125 | + top: 2rem; | |
| 3126 | + bottom: -1rem; | |
| 3127 | + left: 1rem; | |
| 3128 | + width: 1px; | |
| 3129 | + background: var(--border-default); | |
| 3130 | +} | |
| 3131 | +.shithub-pull-commit-group:last-child::before { display: none; } | |
| 3132 | +.shithub-pull-commit-badge { | |
| 3133 | + position: relative; | |
| 3134 | + z-index: 1; | |
| 3135 | + display: inline-flex; | |
| 3136 | + align-items: center; | |
| 3137 | + justify-content: center; | |
| 3138 | + width: 2rem; | |
| 3139 | + height: 2rem; | |
| 3140 | + border: 1px solid var(--border-default); | |
| 3141 | + border-radius: 50%; | |
| 3142 | + color: var(--fg-muted); | |
| 3143 | + background: var(--canvas-default); | |
| 3144 | +} | |
| 3145 | +.shithub-pull-commit-group-body { min-width: 0; } | |
| 3146 | +.shithub-pull-commit-group h3 { | |
| 3147 | + margin: 0.3rem 0 0.65rem; | |
| 3148 | + font-size: 0.95rem; | |
| 3149 | + font-weight: 400; | |
| 3150 | +} | |
| 3151 | +.shithub-pull-commit-panel { | |
| 3152 | + list-style: none; | |
| 3153 | + padding: 0; | |
| 3154 | + margin: 0; | |
| 3155 | + border: 1px solid var(--border-default); | |
| 3156 | + border-radius: 6px; | |
| 3157 | + background: var(--canvas-default); | |
| 3158 | +} | |
| 3159 | +.shithub-pull-commit-row { | |
| 3160 | + display: grid; | |
| 3161 | + grid-template-columns: minmax(0, 1fr) auto; | |
| 3162 | + gap: 1rem; | |
| 3163 | + align-items: center; | |
| 3164 | + padding: 0.75rem; | |
| 3165 | + border-bottom: 1px solid var(--border-default); | |
| 3166 | +} | |
| 3167 | +.shithub-pull-commit-row:last-child { border-bottom: 0; } | |
| 3168 | +.shithub-pull-commit-main { min-width: 0; } | |
| 3169 | +.shithub-pull-commit-title { | |
| 3170 | + display: block; | |
| 3171 | + overflow: hidden; | |
| 3172 | + color: var(--fg-default); | |
| 3173 | + font-weight: 600; | |
| 3174 | + text-overflow: ellipsis; | |
| 3175 | + white-space: nowrap; | |
| 3176 | +} | |
| 3177 | +.shithub-pull-commit-meta { | |
| 3178 | + display: flex; | |
| 3179 | + align-items: center; | |
| 3180 | + flex-wrap: wrap; | |
| 3181 | + gap: 0.25rem; | |
| 3182 | + margin-top: 0.3rem; | |
| 3183 | + color: var(--fg-muted); | |
| 3184 | + font-size: 0.84rem; | |
| 3185 | +} | |
| 3186 | +.shithub-pull-commit-meta .shithub-avatar-sm { width: 16px; height: 16px; margin-right: 0.15rem; } | |
| 3187 | +.shithub-pull-commit-actions { | |
| 3188 | + display: flex; | |
| 3189 | + align-items: center; | |
| 3190 | + gap: 0.25rem; | |
| 3191 | +} | |
| 3192 | +.shithub-pull-commit-sha { | |
| 3193 | + font-family: var(--mono, monospace); | |
| 3194 | + color: var(--fg-muted); | |
| 3195 | +} | |
| 3196 | +@media (max-width: 640px) { | |
| 3197 | + .shithub-pull-commit-row { grid-template-columns: 1fr; } | |
| 3198 | + .shithub-pull-commit-actions { justify-content: flex-start; } | |
| 3102 | 3199 | } |
| 3103 | 3200 | |
| 3104 | 3201 | /* ========== PR Reviews (S23) ========== */ |
internal/web/templates/repo/pull_view.htmlmodified@@ -468,17 +468,44 @@ | ||
| 468 | 468 | </aside> |
| 469 | 469 | </div> |
| 470 | 470 | {{ else if eq .Tab "commits" }} |
| 471 | - <ul class="shithub-pull-commits"> | |
| 472 | - {{ range .Commits }} | |
| 473 | - <li> | |
| 474 | - <a href="/{{ $.Owner }}/{{ $.Repo.Name }}/commit/{{ .Sha }}"><code>{{ slice .Sha 0 7 }}</code></a> | |
| 475 | - {{ .Subject }} | |
| 476 | - <small>by {{ .AuthorName }}</small> | |
| 477 | - </li> | |
| 471 | + <section class="shithub-pull-commits" aria-labelledby="pull-commits-heading"> | |
| 472 | + <h2 id="pull-commits-heading" class="shithub-sr-only">Commits</h2> | |
| 473 | + {{ range .CommitGroups }} | |
| 474 | + <div class="shithub-pull-commit-group"> | |
| 475 | + <span class="shithub-pull-commit-badge">{{ octicon "git-commit" }}</span> | |
| 476 | + <div class="shithub-pull-commit-group-body"> | |
| 477 | + <h3>{{ .Title }}</h3> | |
| 478 | + <ul class="shithub-pull-commit-panel"> | |
| 479 | + {{ range .Commits }} | |
| 480 | + <li class="shithub-pull-commit-row"> | |
| 481 | + <div class="shithub-pull-commit-main"> | |
| 482 | + <a class="shithub-pull-commit-title" href="/{{ $.Owner }}/{{ $.Repo.Name }}/pulls/{{ $.PR.INumber }}/commits/{{ .C.Sha }}">{{ .C.Subject }}</a> | |
| 483 | + <div class="shithub-pull-commit-meta"> | |
| 484 | + {{ if .Author.User }} | |
| 485 | + <a href="/{{ .Author.Username }}"><img src="{{ .Author.AvatarURL }}" alt="" class="shithub-avatar-sm"></a> | |
| 486 | + <a href="/{{ .Author.Username }}">{{ .AuthorLabel }}</a> | |
| 487 | + {{ else }} | |
| 488 | + <span class="shithub-avatar-sm shithub-identicon" data-seed="{{ .Author.IdenticonSeed }}" aria-hidden="true"></span> | |
| 489 | + <span>{{ .AuthorLabel }}</span> | |
| 490 | + {{ end }} | |
| 491 | + <span>committed</span> | |
| 492 | + {{ if .HasWhen }}<time datetime="{{ .When.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .When }}</time>{{ end }} | |
| 493 | + </div> | |
| 494 | + </div> | |
| 495 | + <div class="shithub-pull-commit-actions"> | |
| 496 | + <a class="shithub-button shithub-button-compact shithub-pull-commit-sha" href="/{{ $.Owner }}/{{ $.Repo.Name }}/commit/{{ .C.Sha }}">{{ .ShortSHA }}</a> | |
| 497 | + <button type="button" class="shithub-icon-button" aria-label="Copy full SHA for {{ .ShortSHA }}">{{ octicon "copy" }}</button> | |
| 498 | + <a class="shithub-icon-button" aria-label="Browse repository at {{ .ShortSHA }}" href="/{{ $.Owner }}/{{ $.Repo.Name }}/tree/{{ .C.Sha }}">{{ octicon "code" }}</a> | |
| 499 | + </div> | |
| 500 | + </li> | |
| 501 | + {{ end }} | |
| 502 | + </ul> | |
| 503 | + </div> | |
| 504 | + </div> | |
| 478 | 505 | {{ else }} |
| 479 | - <li class="shithub-muted">No commits.</li> | |
| 506 | + <p class="shithub-muted">No commits.</p> | |
| 480 | 507 | {{ end }} |
| 481 | - </ul> | |
| 508 | + </section> | |
| 482 | 509 | {{ else if eq .Tab "files" }} |
| 483 | 510 | <section class="shithub-pull-files"> |
| 484 | 511 | <div class="shithub-pull-files-toolbar"> |