vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Serve repositories from the root of the URL space
ed03b3d1fa16ef6b55e2773aaf10e3be13282c3a · Keenan Nemetz · 4h ago · parent d37d301f
Serve repositories from the root of the URL space A repository is now /<name> and its Git transport /<name>.git, so the URL a person opens, the URL a clone uses, and the Go module path are the same name. The forge's own pages moved under /-/ (admin, accounts, the directory, the feed, sign-in, assets), a prefix no repository name can start with: names are [a-z0-9...] and cannot begin with "-". That leaves the router with two disjoint spaces and removes the /r/ and /git/ prefixes, which existed only to keep repositories away from the forge's own paths. Routes: repoRoutes lose /r/; global, auth and admin routes gain /-/; assets move to /-/static/ because a subtree pattern like /static/ cannot coexist with one-segment-wildcard repo routes — Go's mux reports them as conflicting neither-more-specific patterns. The catch-all still renders the styled 404. Transport: githttp.Route parses /<name>.git/<rest> instead of a /git/ prefix, and forgepaths.go hands such requests to the proxy before the mux, because a wildcard fills a whole segment and cannot match "<name>.git". LFS stays on the mux (<name>.git/info/lfs/...), and the Go module discovery probe moves to the same pre-router so a package path under a public repository is answered even when its first segments name a page tab. Names: repo.ValidateName now refuses the four root paths the forge must keep — static, robots.txt, sitemap.xml, sitemap-pages.xml. Everything else is an ordinary repository name, including admin, u, and activity. Docs and the packaged URLs follow the new layout; robots.txt, the sitemaps and the instance activity feed point at the new paths. No aliases: the old /r/ and /git/ URLs are gone. Verified with ./vole workflow check and ./vole workflow run verify.
server/web/templates/requests.html +32−32
| @@ -7,7 +7,7 @@ | |||
| 7 | 7 | <h1>Changes</h1> | |
| 8 | 8 | <p class="page-sub">Proposed updates to the project, reviewed and approved before they are merged.</p> | |
| 9 | 9 | </div> | |
| 10 | {{if .CanOpen}}<div class="page-head-actions"><a class="button" href="/r/{{.Name}}/changes/new">{{icon "plus"}}New change</a></div>{{end}} | ||
| 10 | {{if .CanOpen}}<div class="page-head-actions"><a class="button" href="/{{.Name}}/changes/new">{{icon "plus"}}New change</a></div>{{end}} | ||
| 11 | 11 | </div> | |
| 12 | 12 | ||
| 13 | 13 | {{template "change_list" .}} | |
| @@ -21,18 +21,18 @@ | |||
| 21 | 21 | {{/* One row: state chips on the left, search on the right. The chips live | |
| 22 | 22 | inside the form so a search keeps the state, and the whole row is replaced | |
| 23 | 23 | with the server's rendering after a search or a chip click. */}} | |
| 24 | <form method="get" action="/r/{{.Name}}/changes" class="filters" role="search" hx-get="/r/{{.Name}}/changes" hx-target="#change-list" hx-swap="outerHTML" hx-push-url="true"> | ||
| 24 | <form method="get" action="/{{.Name}}/changes" class="filters" role="search" hx-get="/{{.Name}}/changes" hx-target="#change-list" hx-swap="outerHTML" hx-push-url="true"> | ||
| 25 | 25 | <div class="chips" hx-boost="true" hx-target="#change-list" hx-swap="outerHTML" hx-push-url="true"> | |
| 26 | <a class="chip{{if eq .State "open"}} active{{end}}" href="/r/{{.Name}}/changes?state=open{{if .Query}}&q={{urlquery .Query}}{{end}}">Open <span class="chip-count">{{.Open}}</span></a> | ||
| 27 | <a class="chip{{if eq .State "merged"}} active{{end}}" href="/r/{{.Name}}/changes?state=merged{{if .Query}}&q={{urlquery .Query}}{{end}}">Merged <span class="chip-count">{{.Merged}}</span></a> | ||
| 28 | <a class="chip{{if eq .State "closed"}} active{{end}}" href="/r/{{.Name}}/changes?state=closed{{if .Query}}&q={{urlquery .Query}}{{end}}">Closed <span class="chip-count">{{.Closed}}</span></a> | ||
| 29 | <a class="chip{{if eq .State "all"}} active{{end}}" href="/r/{{.Name}}/changes?state=all{{if .Query}}&q={{urlquery .Query}}{{end}}">All <span class="chip-count">{{.Total}}</span></a> | ||
| 26 | <a class="chip{{if eq .State "open"}} active{{end}}" href="/{{.Name}}/changes?state=open{{if .Query}}&q={{urlquery .Query}}{{end}}">Open <span class="chip-count">{{.Open}}</span></a> | ||
| 27 | <a class="chip{{if eq .State "merged"}} active{{end}}" href="/{{.Name}}/changes?state=merged{{if .Query}}&q={{urlquery .Query}}{{end}}">Merged <span class="chip-count">{{.Merged}}</span></a> | ||
| 28 | <a class="chip{{if eq .State "closed"}} active{{end}}" href="/{{.Name}}/changes?state=closed{{if .Query}}&q={{urlquery .Query}}{{end}}">Closed <span class="chip-count">{{.Closed}}</span></a> | ||
| 29 | <a class="chip{{if eq .State "all"}} active{{end}}" href="/{{.Name}}/changes?state=all{{if .Query}}&q={{urlquery .Query}}{{end}}">All <span class="chip-count">{{.Total}}</span></a> | ||
| 30 | 30 | </div> | |
| 31 | 31 | <input type="hidden" name="state" value="{{.State}}"> | |
| 32 | 32 | <div class="filters-search"> | |
| 33 | 33 | <input name="q" type="search" placeholder="Search title, description and author" aria-label="Search title, description and author" value="{{.Query}}"> | |
| 34 | 34 | <button type="submit">{{icon "search"}}Search</button> | |
| 35 | {{if .Filtered}}<a class="button secondary" href="/r/{{.Name}}/changes" hx-get="/r/{{.Name}}/changes" hx-target="#change-list" hx-swap="outerHTML" hx-push-url="true">{{icon "x"}}Clear</a>{{end}} | ||
| 35 | {{if .Filtered}}<a class="button secondary" href="/{{.Name}}/changes" hx-get="/{{.Name}}/changes" hx-target="#change-list" hx-swap="outerHTML" hx-push-url="true">{{icon "x"}}Clear</a>{{end}} | ||
| 36 | 36 | </div> | |
| 37 | 37 | </form> | |
| 38 | 38 | ||
| @@ -47,7 +47,7 @@ | |||
| 47 | 47 | <tr> | |
| 48 | 48 | <td class="fit">{{template "change_status" .Status}}</td> | |
| 49 | 49 | <td> | |
| 50 | <a class="row-title" href="/r/{{$.Name}}/changes/{{.ID}}">{{.Title}}</a> | ||
| 50 | <a class="row-title" href="/{{$.Name}}/changes/{{.ID}}">{{.Title}}</a> | ||
| 51 | 51 | <div class="row-meta"> | |
| 52 | 52 | <span class="sha">{{num .Number}}</span> | |
| 53 | 53 | <span>opened by {{template "userlink" (user .Author)}} {{since .Created.Unix}}</span> | |
| @@ -91,7 +91,7 @@ | |||
| 91 | 91 | ||
| 92 | 92 | {{define "request_changes"}} | |
| 93 | 93 | <section id="request-changes"{{if .Live}} hx-swap-oob="outerHTML"{{end}}> | |
| 94 | <h2 class="with-more"><span>{{icon "file"}}Changes</span>{{if .FileCount}} <a class="more" href="/r/{{.Name}}/changes/{{.Request.ID}}/files">View changes</a>{{end}}</h2> | ||
| 94 | <h2 class="with-more"><span>{{icon "file"}}Changes</span>{{if .FileCount}} <a class="more" href="/{{.Name}}/changes/{{.Request.ID}}/files">View changes</a>{{end}}</h2> | ||
| 95 | 95 | {{if .FileCount}} | |
| 96 | 96 | <p class="muted">{{.FileCount}} file(s) changed{{if .Added}} · <span class="adds">+{{.Added}}</span>{{end}}{{if .Removed}} · <span class="dels">−{{.Removed}}</span>{{end}}</p> | |
| 97 | 97 | {{else if .AlreadyMerged}} | |
| @@ -107,7 +107,7 @@ | |||
| 107 | 107 | target picker, or an open composer is not thrown away. */}} | |
| 108 | 108 | {{define "request_aside"}} | |
| 109 | 109 | <div id="request-aside" | |
| 110 | hx-get="/r/{{.Name}}/changes/{{.Request.ID}}/live" | ||
| 110 | hx-get="/{{.Name}}/changes/{{.Request.ID}}/live" | ||
| 111 | 111 | hx-trigger="every 20s [document.visibilityState === 'visible']" | |
| 112 | 112 | hx-sync="this:replace" | |
| 113 | 113 | hx-swap="none"> | |
| @@ -158,7 +158,7 @@ | |||
| 158 | 158 | ||
| 159 | 159 | {{define "request_review_status"}} | |
| 160 | 160 | <div id="request-review-status"{{if .Live}} hx-swap-oob="outerHTML"{{end}}> | |
| 161 | <h2 class="with-more"><span>{{icon "git-branch"}}Review{{template "help" "The request follows its head branch, so a push moves the head with it. Changing the base or head starts approvals over. A conflict here blocks landing."}}</span> <a class="more sha" href="/r/{{.Name}}/commit/{{.Request.Head}}" title="commit under review">{{short .Request.Head}}</a></h2> | ||
| 161 | <h2 class="with-more"><span>{{icon "git-branch"}}Review{{template "help" "The request follows its head branch, so a push moves the head with it. Changing the base or head starts approvals over. A conflict here blocks landing."}}</span> <a class="more sha" href="/{{.Name}}/commit/{{.Request.Head}}" title="commit under review">{{short .Request.Head}}</a></h2> | ||
| 162 | 162 | {{if .MergeChecked}}{{if .Conflicts}} | |
| 163 | 163 | <p class="conflict">This branch no longer merges into {{.Request.Base}} cleanly: | |
| 164 | 164 | {{range .Conflicts}}<code>{{.}}</code> {{end}}— rebase or merge {{.Request.Base}} before landing it.</p> | |
| @@ -170,7 +170,7 @@ | |||
| 170 | 170 | ||
| 171 | 171 | {{define "request_target"}} | |
| 172 | 172 | {{if .CanRetarget}} | |
| 173 | <form method="post" action="/r/{{.Name}}/changes/{{.Request.ID}}/target" class="request-target"> | ||
| 173 | <form method="post" action="/{{.Name}}/changes/{{.Request.ID}}/target" class="request-target"> | ||
| 174 | 174 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | |
| 175 | 175 | <div class="target-fields"> | |
| 176 | 176 | <label class="target-field"> | |
| @@ -221,14 +221,14 @@ | |||
| 221 | 221 | ||
| 222 | 222 | {{define "request_checks"}} | |
| 223 | 223 | <section id="request-checks"{{if .Live}} hx-swap-oob="outerHTML"{{end}}> | |
| 224 | <h2 class="with-more"><span>{{icon "circle-check"}}Checks{{template "help" "Workflow runs for the commit under review. If the base branch requires checks, a failing or missing run blocks landing."}}</span> <a class="more" href="/r/{{.Name}}/changes/{{.Request.ID}}/runs">View runs</a></h2> | ||
| 224 | <h2 class="with-more"><span>{{icon "circle-check"}}Checks{{template "help" "Workflow runs for the commit under review. If the base branch requires checks, a failing or missing run blocks landing."}}</span> <a class="more" href="/{{.Name}}/changes/{{.Request.ID}}/runs">View runs</a></h2> | ||
| 225 | 225 | {{with .ContributorCI}} | |
| 226 | 226 | <p class="muted">CI is waiting for a maintainer to allow <code>{{.Ref}}</code> at this commit.</p> | |
| 227 | 227 | {{end}} | |
| 228 | 228 | {{if .Checks}} | |
| 229 | 229 | <div class="side-list"> | |
| 230 | 230 | {{range .Checks}} | |
| 231 | <a class="side-run" href="/r/{{$.Name}}/runs/{{.ID}}"> | ||
| 231 | <a class="side-run" href="/{{$.Name}}/runs/{{.ID}}"> | ||
| 232 | 232 | <span class="side-run-top"> | |
| 233 | 233 | <span class="status {{.Status}}">{{.Status}}</span> | |
| 234 | 234 | <span class="side-subject">{{.JobTitle}}</span> | |
| @@ -246,7 +246,7 @@ | |||
| 246 | 246 | {{define "request_combined"}} | |
| 247 | 247 | {{if .CombinedNeeded}} | |
| 248 | 248 | <section id="request-combined"{{if .Live}} hx-swap-oob="outerHTML"{{end}}> | |
| 249 | <h2 class="with-more"><span>{{icon "git-merge"}}Combined result{{template "help" "The merge that would land, built from this change and the latest base. It is tested automatically so the branch is ready when the review is. Only a conflict needs work on the branch."}}</span> {{if .CombinedSHA}}<a class="more sha" href="/r/{{.Name}}/commit/{{.CombinedSHA}}" title="combined result commit">{{short .CombinedSHA}}</a>{{end}}</h2> | ||
| 249 | <h2 class="with-more"><span>{{icon "git-merge"}}Combined result{{template "help" "The merge that would land, built from this change and the latest base. It is tested automatically so the branch is ready when the review is. Only a conflict needs work on the branch."}}</span> {{if .CombinedSHA}}<a class="more sha" href="/{{.Name}}/commit/{{.CombinedSHA}}" title="combined result commit">{{short .CombinedSHA}}</a>{{end}}</h2> | ||
| 250 | 250 | {{if eq .CombinedState "passed"}} | |
| 251 | 251 | <p class="muted">Passed with the latest <code>{{.Request.Base}}</code>.</p> | |
| 252 | 252 | {{else if eq .CombinedState "testing"}} | |
| @@ -259,7 +259,7 @@ | |||
| 259 | 259 | {{if .CombinedRuns}} | |
| 260 | 260 | <div class="side-list"> | |
| 261 | 261 | {{range .CombinedRuns}} | |
| 262 | <a class="side-run" href="/r/{{$.Name}}/runs/{{.ID}}"> | ||
| 262 | <a class="side-run" href="/{{$.Name}}/runs/{{.ID}}"> | ||
| 263 | 263 | <span class="side-run-top"> | |
| 264 | 264 | <span class="status {{.Status}}">{{.Status}}</span> | |
| 265 | 265 | <span class="side-subject">{{.JobTitle}}</span> | |
| @@ -282,12 +282,12 @@ | |||
| 282 | 282 | <div class="side-list"> | |
| 283 | 283 | {{range .LinkedIssues}} | |
| 284 | 284 | <div class="request-issue"> | |
| 285 | <a class="side-issue" href="/r/{{$.Name}}/issues/{{.ID}}"> | ||
| 285 | <a class="side-issue" href="/{{$.Name}}/issues/{{.ID}}"> | ||
| 286 | 286 | <span class="side-subject"><span class="side-num">{{num .Number}}</span>{{.Title}}</span> | |
| 287 | 287 | <span class="side-meta">{{who .Author}}{{if not .Created.IsZero}}<span>{{since .Created.Unix}}</span>{{end}}</span> | |
| 288 | 288 | </a> | |
| 289 | 289 | {{if $.CanEditIssues}} | |
| 290 | <form method="post" action="/r/{{$.Name}}/changes/{{$.Request.ID}}/issues" hx-post="/r/{{$.Name}}/changes/{{$.Request.ID}}/issues" hx-target="#request-issues" hx-swap="outerHTML"> | ||
| 290 | <form method="post" action="/{{$.Name}}/changes/{{$.Request.ID}}/issues" hx-post="/{{$.Name}}/changes/{{$.Request.ID}}/issues" hx-target="#request-issues" hx-swap="outerHTML"> | ||
| 291 | 291 | <input type="hidden" name="csrf" value="{{$.CSRF}}"> | |
| 292 | 292 | <input type="hidden" name="issue" value="{{.ID}}"> | |
| 293 | 293 | <button class="link request-unlink" type="submit" name="action" value="remove" title="Unlink this issue" aria-label="Unlink {{num .Number}} from this change">{{icon "unlink"}}</button> | |
| @@ -301,7 +301,7 @@ | |||
| 301 | 301 | {{end}} | |
| 302 | 302 | {{if .CanEditIssues}} | |
| 303 | 303 | <div class="request-issue-picker"> | |
| 304 | <form class="request-issue-search" hx-get="/r/{{.Name}}/changes/{{.Request.ID}}/issues/search" hx-trigger="input changed delay:250ms, search, submit" hx-target="#request-issue-results" hx-swap="innerHTML"> | ||
| 304 | <form class="request-issue-search" hx-get="/{{.Name}}/changes/{{.Request.ID}}/issues/search" hx-trigger="input changed delay:250ms, search, submit" hx-target="#request-issue-results" hx-swap="innerHTML"> | ||
| 305 | 305 | <input id="request-issue-search" name="q" type="search" placeholder="Search by title, #number, or ULID" aria-label="Search issues by title, number, or ULID" autocomplete="off"> | |
| 306 | 306 | </form> | |
| 307 | 307 | <div id="request-issue-results" class="request-issue-results" aria-live="polite"></div> | |
| @@ -318,7 +318,7 @@ | |||
| 318 | 318 | {{else if .Results}} | |
| 319 | 319 | <div class="request-issue-matches"> | |
| 320 | 320 | {{range .Results}} | |
| 321 | <form method="post" action="/r/{{$.Name}}/changes/{{$.Request.ID}}/issues" class="request-issue-match" hx-post="/r/{{$.Name}}/changes/{{$.Request.ID}}/issues" hx-target="#request-issues" hx-swap="outerHTML"> | ||
| 321 | <form method="post" action="/{{$.Name}}/changes/{{$.Request.ID}}/issues" class="request-issue-match" hx-post="/{{$.Name}}/changes/{{$.Request.ID}}/issues" hx-target="#request-issues" hx-swap="outerHTML"> | ||
| 322 | 322 | <input type="hidden" name="csrf" value="{{$.CSRF}}"> | |
| 323 | 323 | <input type="hidden" name="issue" value="{{.ID}}"> | |
| 324 | 324 | <button type="submit" name="action" value="add" title="Link {{num .Number}}"> | |
| @@ -337,7 +337,7 @@ | |||
| 337 | 337 | {{define "request_inline_comment"}} | |
| 338 | 338 | <tr class="inline-comment"> | |
| 339 | 339 | <td colspan="4"> | |
| 340 | <form method="post" action="/r/{{.Name}}/changes/{{.Request.ID}}/comments" class="inline-comment-form"> | ||
| 340 | <form method="post" action="/{{.Name}}/changes/{{.Request.ID}}/comments" class="inline-comment-form"> | ||
| 341 | 341 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | |
| 342 | 342 | <input type="hidden" name="path" value="{{.Target.Path}}"> | |
| 343 | 343 | <input type="hidden" name="line" value="{{.Target.Line}}"> | |
| @@ -362,9 +362,9 @@ | |||
| 362 | 362 | <span class="page-num">{{num .Number}}</span> | |
| 363 | 363 | <h1 class="details-title-view" data-details-title-view{{if .Details.Title.Active}} hidden{{end}}>{{.Request.Title}}</h1> | |
| 364 | 364 | {{if .CanEdit}} | |
| 365 | <a class="title-edit-toggle" href="/r/{{.Name}}/changes/{{.Request.ID}}/edit"{{if .Details.Inline}} data-title-edit{{end}}{{if .Details.Title.Active}} hidden{{end}} aria-label="Edit title" title="Edit title">{{icon "pencil"}}</a> | ||
| 365 | <a class="title-edit-toggle" href="/{{.Name}}/changes/{{.Request.ID}}/edit"{{if .Details.Inline}} data-title-edit{{end}}{{if .Details.Title.Active}} hidden{{end}} aria-label="Edit title" title="Edit title">{{icon "pencil"}}</a> | ||
| 366 | 366 | {{if .Details.Inline}} | |
| 367 | <form class="title-edit-form" data-title-edit-form method="post" action="/r/{{.Name}}/changes/{{.Request.ID}}/edit" hx-post="/r/{{.Name}}/changes/{{.Request.ID}}/edit" hx-target="#request-head" hx-swap="outerHTML" hx-disabled-elt="find button[type='submit']"{{if not .Details.Title.Active}} hidden{{end}}> | ||
| 367 | <form class="title-edit-form" data-title-edit-form method="post" action="/{{.Name}}/changes/{{.Request.ID}}/edit" hx-post="/{{.Name}}/changes/{{.Request.ID}}/edit" hx-target="#request-head" hx-swap="outerHTML" hx-disabled-elt="find button[type='submit']"{{if not .Details.Title.Active}} hidden{{end}}> | ||
| 368 | 368 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | |
| 369 | 369 | <input type="hidden" name="field" value="title"> | |
| 370 | 370 | <input class="details-title-input" type="text" name="title" required maxlength="200" aria-label="Title" value="{{if .Details.Title.Active}}{{.Details.Title.Value}}{{else}}{{.Request.Title}}{{end}}" data-title-edit-input{{if .Details.Title.Active}} autofocus{{end}}> | |
| @@ -402,7 +402,7 @@ | |||
| 402 | 402 | {{if or .CanApprove .CanClose .CanMerge .MergeArmed .ContributorCI .Live}} | |
| 403 | 403 | <div id="request-actions" class="page-head-actions"{{if .Live}} hx-swap-oob="outerHTML"{{end}}> | |
| 404 | 404 | {{with .ContributorCI}}{{if .CanAllow}} | |
| 405 | <form method="post" action="/r/{{$.Name}}/ci/allow"> | ||
| 405 | <form method="post" action="/{{$.Name}}/ci/allow"> | ||
| 406 | 406 | <input type="hidden" name="csrf" value="{{$.CSRF}}"> | |
| 407 | 407 | <input type="hidden" name="request" value="{{$.Request.ID}}"> | |
| 408 | 408 | <input type="hidden" name="ref" value="refs/heads/{{.Ref}}"> | |
| @@ -410,7 +410,7 @@ | |||
| 410 | 410 | </form> | |
| 411 | 411 | {{end}}{{end}} | |
| 412 | 412 | {{if .CanApprove}} | |
| 413 | <form method="post" action="/r/{{.Name}}/changes/{{.Request.ID}}/approve" hx-post="/r/{{.Name}}/changes/{{.Request.ID}}/approve" hx-swap="none" hx-disabled-elt="find button[type='submit']"> | ||
| 413 | <form method="post" action="/{{.Name}}/changes/{{.Request.ID}}/approve" hx-post="/{{.Name}}/changes/{{.Request.ID}}/approve" hx-swap="none" hx-disabled-elt="find button[type='submit']"> | ||
| 414 | 414 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | |
| 415 | 415 | <input type="hidden" name="base" value="{{.Request.Base}}"> | |
| 416 | 416 | <input type="hidden" name="head" value="{{.Request.Head}}"> | |
| @@ -418,18 +418,18 @@ | |||
| 418 | 418 | </form> | |
| 419 | 419 | {{end}} | |
| 420 | 420 | {{if .MergeArmed}} | |
| 421 | <form method="post" action="/r/{{.Name}}/changes/{{.Request.ID}}/merge/cancel"> | ||
| 421 | <form method="post" action="/{{.Name}}/changes/{{.Request.ID}}/merge/cancel"> | ||
| 422 | 422 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | |
| 423 | 423 | <button class="secondary" type="submit">{{icon "circle-x"}}Cancel merge</button> | |
| 424 | 424 | </form> | |
| 425 | 425 | {{else if .CanMerge}} | |
| 426 | <form method="post" action="/r/{{.Name}}/changes/{{.Request.ID}}/merge"> | ||
| 426 | <form method="post" action="/{{.Name}}/changes/{{.Request.ID}}/merge"> | ||
| 427 | 427 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | |
| 428 | 428 | <button class="success" type="submit"{{if .MergeBlocked}} disabled{{end}}>{{icon "git-merge"}}{{if .MergePending}}Merge when ready{{else}}Merge{{end}}</button> | |
| 429 | 429 | </form> | |
| 430 | 430 | {{end}} | |
| 431 | 431 | {{if .CanClose}} | |
| 432 | <form method="post" action="/r/{{.Name}}/changes/{{.Request.ID}}/state"> | ||
| 432 | <form method="post" action="/{{.Name}}/changes/{{.Request.ID}}/state"> | ||
| 433 | 433 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | |
| 434 | 434 | <input type="hidden" name="state" value="{{if eq .Request.State "open"}}closed{{else}}open{{end}}"> | |
| 435 | 435 | <button class="{{if eq .Request.State "open"}}danger{{else}}secondary{{end}}" type="submit">{{if eq .Request.State "open"}}{{icon "circle-x"}}Close{{else}}{{icon "rotate-ccw"}}Reopen{{end}}</button> | |
| @@ -442,9 +442,9 @@ | |||
| 442 | 442 | {{define "request_tabs"}} | |
| 443 | 443 | <div class="tabrow subtabs"> | |
| 444 | 444 | <nav class="tabs" aria-label="Change sections"> | |
| 445 | <a class="{{if eq .Tab "conversation"}}active{{end}}" href="/r/{{.Name}}/changes/{{.Request.ID}}"{{if eq .Tab "conversation"}} aria-current="page"{{end}}>{{icon "message-square"}}Conversation</a> | ||
| 446 | <a class="{{if eq .Tab "files"}}active{{end}}" href="/r/{{.Name}}/changes/{{.Request.ID}}/files"{{if eq .Tab "files"}} aria-current="page"{{end}}>{{icon "file"}}Changes <span class="chip-count">{{.FileCount}}</span></a> | ||
| 447 | <a class="{{if eq .Tab "runs"}}active{{end}}" href="/r/{{.Name}}/changes/{{.Request.ID}}/runs"{{if eq .Tab "runs"}} aria-current="page"{{end}}>{{icon "play"}}Runs <span class="chip-count">{{len .Checks}}</span></a> | ||
| 445 | <a class="{{if eq .Tab "conversation"}}active{{end}}" href="/{{.Name}}/changes/{{.Request.ID}}"{{if eq .Tab "conversation"}} aria-current="page"{{end}}>{{icon "message-square"}}Conversation</a> | ||
| 446 | <a class="{{if eq .Tab "files"}}active{{end}}" href="/{{.Name}}/changes/{{.Request.ID}}/files"{{if eq .Tab "files"}} aria-current="page"{{end}}>{{icon "file"}}Changes <span class="chip-count">{{.FileCount}}</span></a> | ||
| 447 | <a class="{{if eq .Tab "runs"}}active{{end}}" href="/{{.Name}}/changes/{{.Request.ID}}/runs"{{if eq .Tab "runs"}} aria-current="page"{{end}}>{{icon "play"}}Runs <span class="chip-count">{{len .Checks}}</span></a> | ||
| 448 | 448 | </nav> | |
| 449 | 449 | </div> | |
| 450 | 450 | {{end}} | |
| @@ -467,7 +467,7 @@ | |||
| 467 | 467 | {{if .Description}}{{.Description}}{{else}}<p class="muted">No description.</p>{{end}} | |
| 468 | 468 | </div> | |
| 469 | 469 | {{if .CanEdit}} | |
| 470 | <form class="comment-edit-form details-edit-form" data-comment-edit-form method="post" action="/r/{{.Name}}/changes/{{.Request.ID}}/edit" hx-post="/r/{{.Name}}/changes/{{.Request.ID}}/edit" hx-target="#request-description" hx-swap="outerHTML" hx-disabled-elt="find button[type='submit']"{{if not .Details.Description.Active}} hidden{{end}}> | ||
| 470 | <form class="comment-edit-form details-edit-form" data-comment-edit-form method="post" action="/{{.Name}}/changes/{{.Request.ID}}/edit" hx-post="/{{.Name}}/changes/{{.Request.ID}}/edit" hx-target="#request-description" hx-swap="outerHTML" hx-disabled-elt="find button[type='submit']"{{if not .Details.Description.Active}} hidden{{end}}> | ||
| 471 | 471 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | |
| 472 | 472 | <input type="hidden" name="field" value="body"> | |
| 473 | 473 | {{if .Details.Description.Error}}<p class="error">{{.Details.Description.Error}}</p>{{end}} | |