Add pull files navigator
- SHA
e243e551ce738f324805d953d7628d82add1b09d- Parents
-
dc31eb4 - Tree
fe7e8cf
e243e55
e243e551ce738f324805d953d7628d82add1b09ddc31eb4
fe7e8cf| Status | File | + | - |
|---|---|---|---|
| M |
internal/repos/diff/render/render.go
|
25 | 5 |
| M |
internal/web/handlers/repo/pulls.go
|
48 | 1 |
| M |
internal/web/render/octicons.go
|
2 | 0 |
| M |
internal/web/static/css/shithub.css
|
118 | 2 |
| M |
internal/web/templates/repo/pull_view.html
|
117 | 57 |
internal/repos/diff/render/render.gomodified@@ -97,7 +97,8 @@ func Diff(d *parse.Diff, opts Options) string { | ||
| 97 | 97 | func RenderFile(f *parse.File, opts Options) string { |
| 98 | 98 | opts = defaults(opts) |
| 99 | 99 | var buf bytes.Buffer |
| 100 | - buf.WriteString(`<section class="shithub-diff-file">`) | |
| 100 | + label, _ := fileLabelAction(f) | |
| 101 | + fmt.Fprintf(&buf, `<section id="%s" class="shithub-diff-file">`, html.EscapeString(diffFileAnchor(label))) | |
| 101 | 102 | buf.WriteString(renderHeader(f)) |
| 102 | 103 | switch { |
| 103 | 104 | case f.IsBinary: |
@@ -114,6 +115,14 @@ func RenderFile(f *parse.File, opts Options) string { | ||
| 114 | 115 | } |
| 115 | 116 | |
| 116 | 117 | func renderHeader(f *parse.File) string { |
| 118 | + label, action := fileLabelAction(f) | |
| 119 | + return fmt.Sprintf( | |
| 120 | + `<header class="shithub-diff-file-head"><code>%s</code><span class="shithub-diff-file-action">%s</span></header>`, | |
| 121 | + html.EscapeString(label), html.EscapeString(action), | |
| 122 | + ) | |
| 123 | +} | |
| 124 | + | |
| 125 | +func fileLabelAction(f *parse.File) (string, string) { | |
| 117 | 126 | var label, action string |
| 118 | 127 | switch { |
| 119 | 128 | case f.IsRename: |
@@ -135,10 +144,21 @@ func renderHeader(f *parse.File) string { | ||
| 135 | 144 | } |
| 136 | 145 | action = "modified" |
| 137 | 146 | } |
| 138 | - return fmt.Sprintf( | |
| 139 | - `<header class="shithub-diff-file-head"><code>%s</code><span class="shithub-diff-file-action">%s</span></header>`, | |
| 140 | - html.EscapeString(label), html.EscapeString(action), | |
| 141 | - ) | |
| 147 | + return label, action | |
| 148 | +} | |
| 149 | + | |
| 150 | +func diffFileAnchor(p string) string { | |
| 151 | + var b strings.Builder | |
| 152 | + b.WriteString("diff-") | |
| 153 | + for _, r := range p { | |
| 154 | + switch { | |
| 155 | + case r >= 'a' && r <= 'z', r >= 'A' && r <= 'Z', r >= '0' && r <= '9': | |
| 156 | + b.WriteRune(r) | |
| 157 | + default: | |
| 158 | + b.WriteByte('-') | |
| 159 | + } | |
| 160 | + } | |
| 161 | + return b.String() | |
| 142 | 162 | } |
| 143 | 163 | |
| 144 | 164 | func renderBinary(f *parse.File) string { |
internal/web/handlers/repo/pulls.gomodified@@ -51,6 +51,13 @@ type pullCheckSuiteView struct { | ||
| 51 | 51 | Runs []pullCheckRunView |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | +type pullFileView struct { | |
| 55 | + F pullsdb.PullRequestFile | |
| 56 | + Anchor string | |
| 57 | + Dir string | |
| 58 | + Name string | |
| 59 | +} | |
| 60 | + | |
| 54 | 61 | // MountPulls registers /{owner}/{repo}/pulls* routes. Reads are |
| 55 | 62 | // public (subject to policy.Can(ActionPullRead)); writes require auth. |
| 56 | 63 | // The merge route runs synchronously inside the request: pulls.Merge |
@@ -553,6 +560,17 @@ func (h *Handlers) pullFiles(w http.ResponseWriter, r *http.Request) { | ||
| 553 | 560 | return |
| 554 | 561 | } |
| 555 | 562 | files, _ := pullsdb.New().ListPullRequestFiles(r.Context(), h.d.Pool, pr.IID) |
| 563 | + fileViews := make([]pullFileView, 0, len(files)) | |
| 564 | + for _, f := range files { | |
| 565 | + label := pullFileLabel(f) | |
| 566 | + dir, name := splitPullFilePath(f.Path) | |
| 567 | + fileViews = append(fileViews, pullFileView{ | |
| 568 | + F: f, | |
| 569 | + Anchor: pullFileAnchor(label), | |
| 570 | + Dir: dir, | |
| 571 | + Name: name, | |
| 572 | + }) | |
| 573 | + } | |
| 556 | 574 | diffHTML := "" |
| 557 | 575 | if pr.BaseOid != "" && pr.HeadOid != "" { |
| 558 | 576 | patch, perr := compareSourceMergeBase(r, gitDir, pr.BaseOid, pr.HeadOid) |
@@ -587,12 +605,41 @@ func (h *Handlers) pullFiles(w http.ResponseWriter, r *http.Request) { | ||
| 587 | 605 | threadsByFile[f.Path] = out |
| 588 | 606 | } |
| 589 | 607 | h.renderPullPage(w, r, "files", map[string]any{ |
| 590 | - "Files": files, | |
| 608 | + "Files": fileViews, | |
| 591 | 609 | "DiffHTML": diffHTML, |
| 592 | 610 | "ThreadsByFile": threadsByFile, |
| 593 | 611 | }) |
| 594 | 612 | } |
| 595 | 613 | |
| 614 | +func pullFileLabel(f pullsdb.PullRequestFile) string { | |
| 615 | + if f.OldPath.Valid && f.OldPath.String != "" && f.OldPath.String != f.Path { | |
| 616 | + return f.OldPath.String + " → " + f.Path | |
| 617 | + } | |
| 618 | + return f.Path | |
| 619 | +} | |
| 620 | + | |
| 621 | +func splitPullFilePath(p string) (string, string) { | |
| 622 | + idx := strings.LastIndex(p, "/") | |
| 623 | + if idx < 0 { | |
| 624 | + return "", p | |
| 625 | + } | |
| 626 | + return p[:idx], p[idx+1:] | |
| 627 | +} | |
| 628 | + | |
| 629 | +func pullFileAnchor(p string) string { | |
| 630 | + var b strings.Builder | |
| 631 | + b.WriteString("diff-") | |
| 632 | + for _, r := range p { | |
| 633 | + switch { | |
| 634 | + case r >= 'a' && r <= 'z', r >= 'A' && r <= 'Z', r >= '0' && r <= '9': | |
| 635 | + b.WriteRune(r) | |
| 636 | + default: | |
| 637 | + b.WriteByte('-') | |
| 638 | + } | |
| 639 | + } | |
| 640 | + return b.String() | |
| 641 | +} | |
| 642 | + | |
| 596 | 643 | // pullChecks renders the Checks tab. Loads suites + runs grouped by |
| 597 | 644 | // suite for the PR's head_oid, plus the markdown-rendered output.summary |
| 598 | 645 | // for each run. |
internal/web/render/octicons.gomodified@@ -51,6 +51,8 @@ func BuiltinOcticons() OcticonResolver { | ||
| 51 | 51 | `><path d="M11.93 8.5a4.002 4.002 0 0 1-7.86 0H.75a.75.75 0 0 1 0-1.5h3.32a4.002 4.002 0 0 1 7.86 0h3.32a.75.75 0 0 1 0 1.5Zm-1.43-.75a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"/></svg>`), |
| 52 | 52 | "file-diff": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + |
| 53 | 53 | `><path d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"/></svg>`), |
| 54 | + "diff": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + | |
| 55 | + `><path d="M5.75 3.5a.75.75 0 0 1 0 1.5H3.5v2.25a.75.75 0 0 1-1.5 0V5H.75a.75.75 0 0 1 0-1.5H2V1.25a.75.75 0 0 1 1.5 0V3.5Zm4.5 8.5a.75.75 0 0 1 0-1.5h5a.75.75 0 0 1 0 1.5ZM8.5 4.25a.75.75 0 0 1 .75-.75h6a.75.75 0 0 1 0 1.5h-6a.75.75 0 0 1-.75-.75Zm-6 7a.75.75 0 0 1 .75-.75h3a.75.75 0 0 1 0 1.5h-3a.75.75 0 0 1-.75-.75Z"/></svg>`), | |
| 54 | 56 | "comment-discussion": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + |
| 55 | 57 | `><path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.75.75 0 0 1 1.06-1.06l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"/></svg>`), |
| 56 | 58 | "checklist": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + |
internal/web/static/css/shithub.cssmodified@@ -2957,7 +2957,7 @@ button.shithub-repo-action { | ||
| 2957 | 2957 | font-size: 0.85rem; |
| 2958 | 2958 | vertical-align: baseline; |
| 2959 | 2959 | } |
| 2960 | -.shithub-icon-button { | |
| 2960 | +.shithub-pull-summary .shithub-icon-button { | |
| 2961 | 2961 | display: inline-flex; |
| 2962 | 2962 | align-items: center; |
| 2963 | 2963 | justify-content: center; |
@@ -2970,7 +2970,7 @@ button.shithub-repo-action { | ||
| 2970 | 2970 | color: var(--fg-muted); |
| 2971 | 2971 | cursor: pointer; |
| 2972 | 2972 | } |
| 2973 | -.shithub-icon-button:hover { background: var(--canvas-subtle); color: var(--fg-default); } | |
| 2973 | +.shithub-pull-summary .shithub-icon-button:hover { background: var(--canvas-subtle); color: var(--fg-default); } | |
| 2974 | 2974 | .shithub-pull-tabs { |
| 2975 | 2975 | display: flex; |
| 2976 | 2976 | gap: 0.25rem; |
@@ -3121,6 +3121,122 @@ button.shithub-repo-action { | ||
| 3121 | 3121 | padding: 0.4rem; border: 1px solid var(--border-default); border-radius: 6px; font: inherit; |
| 3122 | 3122 | } |
| 3123 | 3123 | .shithub-pull-comment-form { margin-top: 1.25rem; } |
| 3124 | +.shithub-button-compact { min-height: 32px; padding: 0.25rem 0.7rem; } | |
| 3125 | +.shithub-pull-files { margin-top: 0.25rem; } | |
| 3126 | +.shithub-pull-files-toolbar { | |
| 3127 | + position: sticky; | |
| 3128 | + top: 0; | |
| 3129 | + z-index: 5; | |
| 3130 | + display: flex; | |
| 3131 | + justify-content: space-between; | |
| 3132 | + align-items: center; | |
| 3133 | + gap: 1rem; | |
| 3134 | + padding: 0.7rem 0; | |
| 3135 | + border-bottom: 1px solid var(--border-default); | |
| 3136 | + background: var(--canvas-default); | |
| 3137 | +} | |
| 3138 | +.shithub-pull-files-toolbar-left, | |
| 3139 | +.shithub-pull-files-toolbar-right { | |
| 3140 | + display: flex; | |
| 3141 | + align-items: center; | |
| 3142 | + gap: 0.5rem; | |
| 3143 | + flex-wrap: wrap; | |
| 3144 | +} | |
| 3145 | +.shithub-pull-submit-review-menu { position: relative; } | |
| 3146 | +.shithub-pull-submit-review-menu > summary { list-style: none; } | |
| 3147 | +.shithub-pull-submit-review-menu > summary::-webkit-details-marker { display: none; } | |
| 3148 | +.shithub-pull-review-popover { | |
| 3149 | + right: 0; | |
| 3150 | + top: calc(100% + 0.4rem); | |
| 3151 | + min-width: 20rem; | |
| 3152 | +} | |
| 3153 | +.shithub-pull-review-popover textarea { | |
| 3154 | + width: 100%; | |
| 3155 | + padding: 0.45rem 0.5rem; | |
| 3156 | + border: 1px solid var(--border-default); | |
| 3157 | + border-radius: 6px; | |
| 3158 | + background: var(--canvas-default); | |
| 3159 | + color: var(--fg-default); | |
| 3160 | + font: inherit; | |
| 3161 | +} | |
| 3162 | +.shithub-pull-files-layout { | |
| 3163 | + display: grid; | |
| 3164 | + grid-template-columns: 16rem minmax(0, 1fr); | |
| 3165 | + gap: 1rem; | |
| 3166 | + margin-top: 1rem; | |
| 3167 | +} | |
| 3168 | +.shithub-pull-file-nav { | |
| 3169 | + position: sticky; | |
| 3170 | + top: 3.75rem; | |
| 3171 | + align-self: start; | |
| 3172 | + max-height: calc(100vh - 5rem); | |
| 3173 | + overflow: auto; | |
| 3174 | + border: 1px solid var(--border-default); | |
| 3175 | + border-radius: 6px; | |
| 3176 | + background: var(--canvas-default); | |
| 3177 | +} | |
| 3178 | +.shithub-pull-file-filter { | |
| 3179 | + display: flex; | |
| 3180 | + align-items: center; | |
| 3181 | + gap: 0.35rem; | |
| 3182 | + padding: 0.5rem; | |
| 3183 | + border-bottom: 1px solid var(--border-default); | |
| 3184 | +} | |
| 3185 | +.shithub-pull-file-filter svg { color: var(--fg-muted); flex: 0 0 auto; } | |
| 3186 | +.shithub-pull-file-filter input { | |
| 3187 | + min-width: 0; | |
| 3188 | + width: 100%; | |
| 3189 | + border: 0; | |
| 3190 | + background: transparent; | |
| 3191 | + color: var(--fg-default); | |
| 3192 | + font: inherit; | |
| 3193 | + outline: none; | |
| 3194 | +} | |
| 3195 | +.shithub-pull-file-nav ul { | |
| 3196 | + list-style: none; | |
| 3197 | + margin: 0; | |
| 3198 | + padding: 0.4rem 0; | |
| 3199 | +} | |
| 3200 | +.shithub-pull-file-nav li a { | |
| 3201 | + display: grid; | |
| 3202 | + grid-template-columns: 1.4rem minmax(0, 1fr); | |
| 3203 | + gap: 0.45rem; | |
| 3204 | + align-items: start; | |
| 3205 | + padding: 0.45rem 0.65rem; | |
| 3206 | + color: var(--fg-default); | |
| 3207 | + text-decoration: none; | |
| 3208 | + font-size: 0.86rem; | |
| 3209 | +} | |
| 3210 | +.shithub-pull-file-nav li a:hover { background: var(--canvas-subtle); } | |
| 3211 | +.shithub-pull-file-nav small { | |
| 3212 | + display: block; | |
| 3213 | + color: var(--fg-muted); | |
| 3214 | + font-size: 0.75rem; | |
| 3215 | + overflow: hidden; | |
| 3216 | + text-overflow: ellipsis; | |
| 3217 | + white-space: nowrap; | |
| 3218 | +} | |
| 3219 | +.shithub-pull-file-status { | |
| 3220 | + display: inline-flex; | |
| 3221 | + align-items: center; | |
| 3222 | + justify-content: center; | |
| 3223 | + width: 1.1rem; | |
| 3224 | + height: 1.1rem; | |
| 3225 | + border-radius: 4px; | |
| 3226 | + font-size: 0.68rem; | |
| 3227 | + font-weight: 700; | |
| 3228 | +} | |
| 3229 | +.shithub-pull-file-status-added { color: #1a7f37; border: 1px solid rgba(26, 127, 55, 0.45); } | |
| 3230 | +.shithub-pull-file-status-deleted { color: #cf222e; border: 1px solid rgba(207, 34, 46, 0.45); } | |
| 3231 | +.shithub-pull-file-status-renamed { color: #8250df; border: 1px solid rgba(130, 80, 223, 0.45); } | |
| 3232 | +.shithub-pull-file-status-modified { color: #bf8700; border: 1px solid rgba(154, 103, 0, 0.45); } | |
| 3233 | +.shithub-pull-file-lines { margin-top: 0.1rem; } | |
| 3234 | +.shithub-pull-files-main { min-width: 0; } | |
| 3235 | +@media (max-width: 900px) { | |
| 3236 | + .shithub-pull-files-toolbar { position: static; align-items: flex-start; flex-direction: column; } | |
| 3237 | + .shithub-pull-files-layout { grid-template-columns: 1fr; } | |
| 3238 | + .shithub-pull-file-nav { position: static; max-height: none; } | |
| 3239 | +} | |
| 3124 | 3240 | .shithub-pull-threads { margin-top: 1.5rem; padding: 0.75rem; border: 1px solid var(--border-default); border-radius: 6px; } |
| 3125 | 3241 | .shithub-pull-thread-file { padding: 0.4rem 0; border-bottom: 1px solid var(--border-default); } |
| 3126 | 3242 | .shithub-pull-thread-file:last-child { border-bottom: none; } |
internal/web/templates/repo/pull_view.htmlmodified@@ -480,67 +480,127 @@ | ||
| 480 | 480 | {{ end }} |
| 481 | 481 | </ul> |
| 482 | 482 | {{ else if eq .Tab "files" }} |
| 483 | - {{ if .DiffHTML }} | |
| 484 | - <div class="shithub-diff">{{ safeHTML .DiffHTML }}</div> | |
| 485 | - {{ else }} | |
| 486 | - <p class="shithub-muted">No diff available.</p> | |
| 487 | - {{ end }} | |
| 483 | + <section class="shithub-pull-files"> | |
| 484 | + <div class="shithub-pull-files-toolbar"> | |
| 485 | + <div class="shithub-pull-files-toolbar-left"> | |
| 486 | + <button type="button" class="shithub-button shithub-button-compact">{{ octicon "diff" }} All commits</button> | |
| 487 | + <span class="shithub-muted">{{ .PullStats.Files }} file{{ if ne .PullStats.Files 1 }}s{{ end }} changed</span> | |
| 488 | + </div> | |
| 489 | + <div class="shithub-pull-files-toolbar-right"> | |
| 490 | + <span class="shithub-muted">0 / {{ .PullStats.Files }} viewed</span> | |
| 491 | + {{ if .CanReviewPull }} | |
| 492 | + <details class="shithub-pull-submit-review shithub-pull-submit-review-menu"> | |
| 493 | + <summary class="shithub-button shithub-button-primary">Submit review</summary> | |
| 494 | + <form method="post" action="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/reviews" class="shithub-popover shithub-pull-review-popover"> | |
| 495 | + <strong>Finish your review</strong> | |
| 496 | + <input type="hidden" name="csrf_token" value="{{ .CSRFToken }}"> | |
| 497 | + <textarea name="body" rows="4" placeholder="Leave a review comment (optional)"></textarea> | |
| 498 | + <select name="state"> | |
| 499 | + <option value="comment">Comment</option> | |
| 500 | + {{ if not (and .PR.IAuthorUserID.Valid (eq .PR.IAuthorUserID.Int64 .Viewer.ID)) }} | |
| 501 | + <option value="approve">Approve</option> | |
| 502 | + <option value="request_changes">Request changes</option> | |
| 503 | + {{ end }} | |
| 504 | + </select> | |
| 505 | + <button type="submit" class="shithub-button shithub-button-primary">Submit review</button> | |
| 506 | + </form> | |
| 507 | + </details> | |
| 508 | + {{ end }} | |
| 509 | + <button type="button" class="shithub-icon-button" aria-label="Files changed settings">{{ octicon "gear" }}</button> | |
| 510 | + </div> | |
| 511 | + </div> | |
| 488 | 512 | |
| 489 | - {{ if .ThreadsByFile }} | |
| 490 | - <section class="shithub-pull-threads"> | |
| 491 | - <h3>Inline comments</h3> | |
| 492 | - {{ range $path, $threads := .ThreadsByFile }} | |
| 493 | - {{ if $threads }} | |
| 494 | - <details class="shithub-pull-thread-file" open> | |
| 495 | - <summary><code>{{ $path }}</code> · {{ len $threads }}</summary> | |
| 496 | - {{ range $threads }} | |
| 497 | - <div class="shithub-pull-thread{{ if not .C.CurrentPosition.Valid }} shithub-pull-thread-outdated{{ end }}{{ if .C.ResolvedAt.Valid }} shithub-pull-thread-resolved{{ end }}"> | |
| 498 | - <div class="shithub-comment-head"> | |
| 499 | - {{ if .AuthorName }}<a href="/{{ .AuthorName }}">{{ .AuthorName }}</a>{{ end }} | |
| 500 | - line {{ .C.OriginalLine }} | |
| 501 | - <time datetime="{{ .C.CreatedAt.Time.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .C.CreatedAt.Time }}</time> | |
| 502 | - {{ if not .C.CurrentPosition.Valid }}<span class="shithub-pill">outdated</span>{{ end }} | |
| 503 | - {{ if .C.ResolvedAt.Valid }}<span class="shithub-pill">resolved</span>{{ end }} | |
| 504 | - </div> | |
| 505 | - <div class="shithub-comment-body markdown-body"> | |
| 506 | - {{ if .C.BodyHtmlCached.Valid }}{{ safeHTML .C.BodyHtmlCached.String }}{{ else }}<p>{{ .C.Body }}</p>{{ end }} | |
| 507 | - </div> | |
| 508 | - {{ if $.CanReviewPull }} | |
| 509 | - <div class="shithub-pull-thread-actions"> | |
| 510 | - <form method="post" action="/{{ $.Owner }}/{{ $.Repo.Name }}/pulls/{{ $.PR.INumber }}/review-comments/{{ .C.ID }}/reply"> | |
| 511 | - <input type="hidden" name="csrf_token" value="{{ $.CSRFToken }}"> | |
| 512 | - <textarea name="body" rows="2" placeholder="Reply..."></textarea> | |
| 513 | - <button type="submit" class="shithub-button">Reply</button> | |
| 514 | - </form> | |
| 515 | - <form method="post" action="/{{ $.Owner }}/{{ $.Repo.Name }}/pulls/{{ $.PR.INumber }}/review-comments/{{ .C.ID }}/{{ if .C.ResolvedAt.Valid }}reopen{{ else }}resolve{{ end }}"> | |
| 516 | - <input type="hidden" name="csrf_token" value="{{ $.CSRFToken }}"> | |
| 517 | - <button type="submit" class="shithub-button">{{ if .C.ResolvedAt.Valid }}Reopen{{ else }}Resolve{{ end }}</button> | |
| 518 | - </form> | |
| 519 | - </div> | |
| 520 | - {{ end }} | |
| 521 | - </div> | |
| 513 | + <div class="shithub-pull-files-layout"> | |
| 514 | + <aside class="shithub-pull-file-nav" aria-label="Changed files"> | |
| 515 | + <label class="shithub-pull-file-filter"> | |
| 516 | + {{ octicon "search" }} | |
| 517 | + <input type="search" placeholder="Filter files..." aria-label="Filter files"> | |
| 518 | + </label> | |
| 519 | + <ul> | |
| 520 | + {{ range .Files }} | |
| 521 | + <li> | |
| 522 | + <a href="#{{ .Anchor }}"> | |
| 523 | + {{ if eq (printf "%s" .F.Status) "added" }}<span class="shithub-pull-file-status shithub-pull-file-status-added">A</span> | |
| 524 | + {{ else if eq (printf "%s" .F.Status) "deleted" }}<span class="shithub-pull-file-status shithub-pull-file-status-deleted">D</span> | |
| 525 | + {{ else if eq (printf "%s" .F.Status) "renamed" }}<span class="shithub-pull-file-status shithub-pull-file-status-renamed">R</span> | |
| 526 | + {{ else }}<span class="shithub-pull-file-status shithub-pull-file-status-modified">M</span>{{ end }} | |
| 527 | + <span> | |
| 528 | + {{ if .Dir }}<small>{{ .Dir }}/</small>{{ end }}{{ .Name }} | |
| 529 | + <small class="shithub-pull-file-lines">+{{ .F.Additions }} −{{ .F.Deletions }}</small> | |
| 530 | + </span> | |
| 531 | + </a> | |
| 532 | + </li> | |
| 533 | + {{ else }} | |
| 534 | + <li class="shithub-muted">No files changed.</li> | |
| 535 | + {{ end }} | |
| 536 | + </ul> | |
| 537 | + </aside> | |
| 538 | + | |
| 539 | + <div class="shithub-pull-files-main"> | |
| 540 | + {{ if .DiffHTML }} | |
| 541 | + <div class="shithub-diff">{{ safeHTML .DiffHTML }}</div> | |
| 542 | + {{ else }} | |
| 543 | + <p class="shithub-muted">No diff available.</p> | |
| 522 | 544 | {{ end }} |
| 523 | - </details> | |
| 524 | - {{ end }} | |
| 525 | - {{ end }} | |
| 526 | 545 | |
| 527 | - {{ if .CanReviewPull }} | |
| 528 | - <details class="shithub-pull-add-comment"> | |
| 529 | - <summary class="shithub-button">Add inline comment</summary> | |
| 530 | - <form method="post" action="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/review-comments"> | |
| 531 | - <input type="hidden" name="csrf_token" value="{{ .CSRFToken }}"> | |
| 532 | - <input type="text" name="file_path" placeholder="path" required> | |
| 533 | - <input type="number" name="line" placeholder="line" required> | |
| 534 | - <input type="number" name="position" placeholder="position" required> | |
| 535 | - <input type="hidden" name="commit_sha" value="{{ .PR.HeadOid }}"> | |
| 536 | - <input type="hidden" name="side" value="right"> | |
| 537 | - <textarea name="body" rows="3" required></textarea> | |
| 538 | - <button type="submit" class="shithub-button">Add comment</button> | |
| 539 | - </form> | |
| 540 | - </details> | |
| 541 | - {{ end }} | |
| 546 | + {{ if .ThreadsByFile }} | |
| 547 | + <section class="shithub-pull-threads"> | |
| 548 | + <h3>Inline comments</h3> | |
| 549 | + {{ range $path, $threads := .ThreadsByFile }} | |
| 550 | + {{ if $threads }} | |
| 551 | + <details class="shithub-pull-thread-file" open> | |
| 552 | + <summary><code>{{ $path }}</code> · {{ len $threads }}</summary> | |
| 553 | + {{ range $threads }} | |
| 554 | + <div class="shithub-pull-thread{{ if not .C.CurrentPosition.Valid }} shithub-pull-thread-outdated{{ end }}{{ if .C.ResolvedAt.Valid }} shithub-pull-thread-resolved{{ end }}"> | |
| 555 | + <div class="shithub-comment-head"> | |
| 556 | + {{ if .AuthorName }}<a href="/{{ .AuthorName }}">{{ .AuthorName }}</a>{{ end }} | |
| 557 | + line {{ .C.OriginalLine }} | |
| 558 | + <time datetime="{{ .C.CreatedAt.Time.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .C.CreatedAt.Time }}</time> | |
| 559 | + {{ if not .C.CurrentPosition.Valid }}<span class="shithub-pill">outdated</span>{{ end }} | |
| 560 | + {{ if .C.ResolvedAt.Valid }}<span class="shithub-pill">resolved</span>{{ end }} | |
| 561 | + </div> | |
| 562 | + <div class="shithub-comment-body markdown-body"> | |
| 563 | + {{ if .C.BodyHtmlCached.Valid }}{{ safeHTML .C.BodyHtmlCached.String }}{{ else }}<p>{{ .C.Body }}</p>{{ end }} | |
| 564 | + </div> | |
| 565 | + {{ if $.CanReviewPull }} | |
| 566 | + <div class="shithub-pull-thread-actions"> | |
| 567 | + <form method="post" action="/{{ $.Owner }}/{{ $.Repo.Name }}/pulls/{{ $.PR.INumber }}/review-comments/{{ .C.ID }}/reply"> | |
| 568 | + <input type="hidden" name="csrf_token" value="{{ $.CSRFToken }}"> | |
| 569 | + <textarea name="body" rows="2" placeholder="Reply..."></textarea> | |
| 570 | + <button type="submit" class="shithub-button">Reply</button> | |
| 571 | + </form> | |
| 572 | + <form method="post" action="/{{ $.Owner }}/{{ $.Repo.Name }}/pulls/{{ $.PR.INumber }}/review-comments/{{ .C.ID }}/{{ if .C.ResolvedAt.Valid }}reopen{{ else }}resolve{{ end }}"> | |
| 573 | + <input type="hidden" name="csrf_token" value="{{ $.CSRFToken }}"> | |
| 574 | + <button type="submit" class="shithub-button">{{ if .C.ResolvedAt.Valid }}Reopen{{ else }}Resolve{{ end }}</button> | |
| 575 | + </form> | |
| 576 | + </div> | |
| 577 | + {{ end }} | |
| 578 | + </div> | |
| 579 | + {{ end }} | |
| 580 | + </details> | |
| 581 | + {{ end }} | |
| 582 | + {{ end }} | |
| 583 | + | |
| 584 | + {{ if .CanReviewPull }} | |
| 585 | + <details class="shithub-pull-add-comment"> | |
| 586 | + <summary class="shithub-button">Add inline comment</summary> | |
| 587 | + <form method="post" action="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/review-comments"> | |
| 588 | + <input type="hidden" name="csrf_token" value="{{ .CSRFToken }}"> | |
| 589 | + <input type="text" name="file_path" placeholder="path" required> | |
| 590 | + <input type="number" name="line" placeholder="line" required> | |
| 591 | + <input type="number" name="position" placeholder="position" required> | |
| 592 | + <input type="hidden" name="commit_sha" value="{{ .PR.HeadOid }}"> | |
| 593 | + <input type="hidden" name="side" value="right"> | |
| 594 | + <textarea name="body" rows="3" required></textarea> | |
| 595 | + <button type="submit" class="shithub-button">Add comment</button> | |
| 596 | + </form> | |
| 597 | + </details> | |
| 598 | + {{ end }} | |
| 599 | + </section> | |
| 600 | + {{ end }} | |
| 601 | + </div> | |
| 602 | + </div> | |
| 542 | 603 | </section> |
| 543 | - {{ end }} | |
| 544 | 604 | {{ else if eq .Tab "checks" }} |
| 545 | 605 | {{ if .CheckGroups }} |
| 546 | 606 | <section class="shithub-pull-checks"> |