vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
Compact the change request target controls
41d1fee900568b1bff5c7cff3b4c52942f47fabd · Keenan Nemetz · 13d ago · parent e050e14a
Compact the change request target controls Replace the separate base and head forms and the duplicated labels with one row: base picker, head picker, update. The pickers preselect the current targets, and a pinned head appears as the current commit. Collapse the help text to one line. Post both targets to one /target handler and write them in one metadata commit. Either change invalidates approvals; keeping the current value is allowed even if its branch has gone missing so the other side can still be repaired.
server/web/templates/requests.html +20−31
| @@ -104,48 +104,37 @@ | |||
| 104 | 104 | {{if .Error}}<p class="error">{{.Error}}</p>{{end}} | |
| 105 | 105 | <section> | |
| 106 | 106 | <h2>{{icon "git-branch"}}Review</h2> | |
| 107 | <dl class="meta-list"> | ||
| 108 | <dt>Base</dt><dd><code>{{.Request.Base}}</code></dd> | ||
| 109 | <dt>Head</dt><dd>{{with .Request.HeadRef}}<code title="the branch this request follows">{{.}}</code>{{if $.HeadRefNote}} <span class="muted">({{$.HeadRefNote}})</span>{{end}} {{end}}<a class="sha" href="/r/{{.Name}}/commit/{{.Request.Head}}">{{short .Request.Head}}</a></dd> | ||
| 110 | </dl> | ||
| 111 | {{if .CanChangeBase}} | ||
| 112 | <form method="post" action="/r/{{.Name}}/requests/{{.Request.ID}}/base" class="base-move"> | ||
| 107 | {{if .CanRetarget}} | ||
| 108 | <form method="post" action="/r/{{.Name}}/requests/{{.Request.ID}}/target" class="request-target"> | ||
| 113 | 109 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | |
| 114 | <label>Change base | ||
| 115 | <select name="base" required> | ||
| 116 | <option value="" selected disabled>Choose a branch</option> | ||
| 117 | {{range .BaseBranches}}<option value="{{.}}">{{.}}</option>{{end}} | ||
| 110 | <div class="target-row"> | ||
| 111 | <select name="base" aria-label="Base branch"> | ||
| 112 | {{range .BaseOptions}}<option value="{{.Name}}"{{if .Selected}} selected{{end}}>{{.Name}}</option>{{end}} | ||
| 118 | 113 | </select> | |
| 119 | </label> | ||
| 120 | <button class="secondary" type="submit"{{if not .BaseBranches}} disabled{{end}}>{{icon "rotate-ccw"}}Update</button> | ||
| 121 | </form> | ||
| 122 | <p class="muted">A new base changes the diff and starts approvals over. Retarget a stacked request after the branch below it lands.</p> | ||
| 123 | {{if not .BaseBranches}}<p class="muted">Push a branch first.</p>{{end}} | ||
| 124 | {{end}} | ||
| 125 | {{if .CanMoveHead}} | ||
| 126 | <form method="post" action="/r/{{.Name}}/requests/{{.Request.ID}}/head" class="head-move"> | ||
| 127 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | ||
| 128 | <label>Repoint request | ||
| 129 | <select name="head" required> | ||
| 130 | <option value="" selected disabled>Choose a branch</option> | ||
| 131 | {{range .HeadBranches}}<option value="{{.}}">{{.}}</option>{{end}} | ||
| 114 | <span class="muted" aria-hidden="true">←</span> | ||
| 115 | <select name="head" aria-label="Head branch"> | ||
| 116 | {{if not .Request.HeadRef}}<option value="" selected>commit {{short .Request.Head}} (pinned)</option>{{end}} | ||
| 117 | {{range .HeadOptions}}<option value="{{.Name}}"{{if .Selected}} selected{{end}}>{{.Name}}</option>{{end}} | ||
| 132 | 118 | </select> | |
| 133 | </label> | ||
| 134 | <button class="secondary" type="submit"{{if not .HeadBranches}} disabled{{end}}>{{icon "rotate-ccw"}}Update</button> | ||
| 119 | <button class="secondary" type="submit" title="Update base and head" aria-label="Update base and head">{{icon "rotate-ccw"}}</button> | ||
| 120 | </div> | ||
| 121 | <p class="muted">{{if .HeadRefNote}}{{.HeadRefNote}}. {{end}}Pushes move the head (<a class="sha" href="/r/{{.Name}}/commit/{{.Request.Head}}">{{short .Request.Head}}</a>); changing base or head starts approvals over.</p> | ||
| 135 | 122 | </form> | |
| 136 | {{if .Request.HeadRef}} | ||
| 137 | <p class="muted">Pushes to <code>{{.Request.HeadRef}}</code> move this request automatically. Repoint only to follow a different branch.</p> | ||
| 138 | 123 | {{else}} | |
| 139 | <p class="muted">This request is pinned to a commit. Choose a branch to make it follow pushes.</p> | ||
| 140 | {{end}} | ||
| 141 | {{if not .HeadBranches}}<p class="muted">Push a branch first.</p>{{end}} | ||
| 124 | <p class="target-summary"> | ||
| 125 | <code>{{.Request.Base}}</code> | ||
| 126 | <span class="muted" aria-hidden="true">←</span> | ||
| 127 | {{with .Request.HeadRef}}<code>{{.}}</code> {{end}} | ||
| 128 | <a class="sha" href="/r/{{.Name}}/commit/{{.Request.Head}}">{{short .Request.Head}}</a> | ||
| 129 | </p> | ||
| 130 | {{if .HeadRefNote}}<p class="muted">{{.HeadRefNote}}.</p>{{end}} | ||
| 142 | 131 | {{end}} | |
| 143 | 132 | </section> | |
| 144 | 133 | ||
| 145 | 134 | <section> | |
| 146 | 135 | <h2>{{icon "check"}}Approvals</h2> | |
| 147 | 136 | <p class="muted">{{.Current}} of {{.Required}} required approval(s).</p> | |
| 148 | <p class="muted">Approving names the current head; a new head starts over.</p> | ||
| 137 | <p class="muted">Approving names the current base and head; a new base or head starts over.</p> | ||
| 149 | 138 | {{if .Approvals}} | |
| 150 | 139 | <ul class="approval-list"> | |
| 151 | 140 | {{range .Approvals}} | |