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.
|
43e681d8
Keenan Nemetz
4d ago
|
1 | {{define "status_body"}} |
|
4506a4d3
Keenan Nemetz
13d ago
|
2 | {{if eq .Tab "overview"}} |
| 3 | <div class="status-grid"> | |
| 4 | <div class="card"> | |
| 5 | <span class="muted">Storage used</span> | |
| 6 | <strong>{{bytes .Storage.Used}}</strong> | |
| 7 | {{if .Storage.Disk.Total}}<span class="status-note">of {{bytes .Storage.Disk.Total}} total</span>{{end}} | |
| 8 | </div> | |
| 9 | <div class="card"> | |
| 10 | <span class="muted">Free space</span> | |
| 11 | <strong>{{if .Storage.DiskErr}}—{{else}}{{bytes .Storage.Disk.Available}}{{end}}</strong> | |
| 12 | {{if .Storage.DiskErr}}<span class="status-note bad">unavailable</span>{{else}}<span class="status-note">available of {{bytes .Storage.Disk.Total}}</span>{{end}} | |
| 13 | </div> | |
| 14 | <div class="card"> | |
|
9a2a270b
Keenan Nemetz
4d ago
|
15 | <span class="muted">Users</span> |
| 16 | <strong>{{.Accounts}}</strong> | |
| 17 | <span class="status-note">{{.AccountSummary.UsersNote}}</span> | |
| 18 | </div> | |
| 19 | <div class="card"> | |
| 20 | <span class="muted">Repositories</span> | |
| 21 | <strong>{{.Repos}}</strong> | |
| 22 | <span class="status-note">hosted here</span> | |
|
4506a4d3
Keenan Nemetz
13d ago
|
23 | </div> |
| 24 | <div class="card"> | |
| 25 | <span class="muted">Page views</span> | |
| 26 | <strong>{{if .Views.Disabled}}—{{else}}{{.Views.Month.Views}}{{end}}</strong> | |
| 27 | <span class="status-note">{{if .Views.Disabled}}not recorded{{else}}last 30 days{{end}}</span> | |
| 28 | </div> | |
| 29 | </div> | |
| 30 | ||
|
0db980ee
Keenan Nemetz
4d ago
|
31 | <h2>Recent admin activity</h2> |
| 32 | {{if .RecentAudit.Err}}<div class="flash bad">The audit log could not be read: {{.RecentAudit.Err}}</div>{{end}} | |
| 33 | {{if .RecentAudit.Entries}} | |
| 34 | <div class="panel"> | |
| 35 | <table> | |
| 36 | <thead><tr><th>When</th><th>Action</th><th>Actor</th><th>Subject</th><th>Detail</th></tr></thead> | |
| 37 | <tbody> | |
| 38 | {{range .RecentAudit.Entries}} | |
| 39 | <tr> | |
| 40 | <td class="nowrap" title="{{.Time.UTC.Format "2006-01-02 15:04:05 UTC"}}">{{since .Time.Unix}}</td> | |
| 41 | <td><code>{{.Action}}</code></td> | |
| 42 | <td>{{template "userlink" (user .Actor)}}</td> | |
| 43 | <td>{{.Subject}}</td> | |
| 44 | <td class="muted audit-detail">{{.Detail}}</td> | |
| 45 | </tr> | |
| 46 | {{end}} | |
| 47 | </tbody> | |
| 48 | </table> | |
| 49 | </div> | |
|
ed03b3d1
Keenan Nemetz
3h ago
|
50 | <p class="muted"><a href="/-/admin?tab=audit">Read the full audit log</a></p> |
|
0db980ee
Keenan Nemetz
4d ago
|
51 | {{else if not .RecentAudit.Err}} |
|
c7b9094f
Keenan Nemetz
1d ago
|
52 | <div class="empty-state"><p>No privileged actions have been recorded yet.</p></div> |
|
0db980ee
Keenan Nemetz
4d ago
|
53 | {{end}} |
| 54 | ||
| 55 | {{if .ConfigWarnings}} | |
| 56 | <h2>Configuration attention</h2> | |
| 57 | <div class="panel"> | |
| 58 | <table> | |
| 59 | <thead><tr><th>Setting</th><th>Why it matters</th></tr></thead> | |
| 60 | <tbody> | |
| 61 | {{range .ConfigWarnings}} | |
| 62 | <tr> | |
| 63 | <td><code>{{.Key}}</code> <span class="muted">= {{.Value}}</span></td> | |
| 64 | <td class="muted">{{if .Note}}{{.Note}}{{else}}review this setting{{end}}</td> | |
| 65 | </tr> | |
| 66 | {{end}} | |
| 67 | </tbody> | |
| 68 | </table> | |
| 69 | </div> | |
|
ed03b3d1
Keenan Nemetz
3h ago
|
70 | <p class="muted"><a href="/-/admin?tab=configuration">See every effective setting</a></p> |
|
0db980ee
Keenan Nemetz
4d ago
|
71 | {{end}} |
| 72 | ||
|
4506a4d3
Keenan Nemetz
13d ago
|
73 | <h2>Page views</h2> |
| 74 | {{if .Views.Disabled}} | |
| 75 | <p class="muted">Page-view tracking is not wired on this instance.</p> | |
|
09b15120
Keenan Nemetz
15d ago
|
76 | {{else}} |
|
4506a4d3
Keenan Nemetz
13d ago
|
77 | {{if .Views.Err}}<div class="flash bad">{{.Views.Err}}</div>{{end}} |
| 78 | <div class="panel"> | |
| 79 | <table> | |
| 80 | <thead><tr><th>Period</th><th>Views</th><th>Unique signed-in users</th></tr></thead> | |
| 81 | <tbody> | |
| 82 | <tr><td>Today (UTC)</td><td>{{.Views.Today.Views}}</td><td>{{.Views.Today.Users}}</td></tr> | |
| 83 | <tr><td>Last 7 days</td><td>{{.Views.Week.Views}}</td><td>{{.Views.Week.Users}}</td></tr> | |
| 84 | <tr><td>Last 30 days</td><td>{{.Views.Month.Views}}</td><td>{{.Views.Month.Users}}</td></tr> | |
| 85 | </tbody> | |
| 86 | </table> | |
| 87 | </div> | |
|
43e681d8
Keenan Nemetz
4d ago
|
88 | <p class="muted">Counts successful HTML pages. Static files, Git traffic, redirects, HTMX fragments, and this Admin page are excluded. Anonymous views count toward Views; Unique users counts signed-in accounts.</p> |
|
4506a4d3
Keenan Nemetz
13d ago
|
89 | {{end}} |
|
09b15120
Keenan Nemetz
15d ago
|
90 | {{end}} |
| 91 | ||
|
4506a4d3
Keenan Nemetz
13d ago
|
92 | {{if eq .Tab "storage"}} |
| 93 | <h2>Storage</h2> | |
| 94 | {{if .Storage.Err}}<div class="flash bad">The data directory could not be fully measured: {{.Storage.Err}}</div>{{end}} | |
| 95 | <div class="panel"> | |
| 96 | <table> | |
| 97 | <thead><tr><th>Category</th><th>Size</th><th>Files</th></tr></thead> | |
| 98 | <tbody> | |
| 99 | {{range .Storage.Categories}} | |
| 100 | <tr><td>{{.Name}}</td><td>{{bytes .Bytes}}</td><td class="muted">{{.Files}}</td></tr> | |
| 101 | {{end}} | |
| 102 | <tr class="status-total"><td>Total</td><td>{{bytes .Storage.Used}}</td><td class="muted">{{.Storage.Files}}</td></tr> | |
| 103 | </tbody> | |
| 104 | </table> | |
|
09b15120
Keenan Nemetz
15d ago
|
105 | </div> |
|
4506a4d3
Keenan Nemetz
13d ago
|
106 | {{if .Storage.Disk.Total}} |
| 107 | <p class="muted">{{bytes .Storage.Disk.Available}} available of {{bytes .Storage.Disk.Total}} on the filesystem; {{bytes .Storage.Disk.Used}} used. Snapshot taken {{since .Storage.Measured.Unix}}.</p> | |
| 108 | {{else if .Storage.DiskErr}} | |
| 109 | <p class="bad">Filesystem capacity is unavailable: {{.Storage.DiskErr}}</p> | |
| 110 | {{end}} | |
|
09b15120
Keenan Nemetz
15d ago
|
111 | |
|
4506a4d3
Keenan Nemetz
13d ago
|
112 | <h2>LFS and build objects</h2> |
| 113 | {{if .LFS.Disabled}} | |
| 114 | <p class="muted">The LFS object store is disabled.</p> | |
| 115 | {{else}} | |
| 116 | {{if .LFS.Err}}<div class="flash bad">{{.LFS.Err}}</div>{{end}} | |
|
09b15120
Keenan Nemetz
15d ago
|
117 | <div class="panel"> |
| 118 | <table> | |
|
4506a4d3
Keenan Nemetz
13d ago
|
119 | <thead><tr><th>Kind</th><th>Objects</th><th>Size</th></tr></thead> |
|
09b15120
Keenan Nemetz
15d ago
|
120 | <tbody> |
|
4506a4d3
Keenan Nemetz
13d ago
|
121 | <tr><td>CI artifacts</td><td>{{.LFS.Artifacts.Objects}}</td><td>{{bytes .LFS.Artifacts.Bytes}}</td></tr> |
| 122 | <tr><td>Repository LFS and other</td><td>{{.LFS.Other.Objects}}</td><td>{{bytes .LFS.Other.Bytes}}</td></tr> | |
| 123 | <tr class="status-total"><td>Object pool</td><td>{{.LFS.Total.Objects}}</td><td>{{bytes .LFS.Total.Bytes}}</td></tr> | |
| 124 | </tbody> | |
| 125 | </table> | |
| 126 | </div> | |
| 127 | <p class="muted">Sizes are the object pool's content. The storage table above reports allocated disk blocks, so the same bytes can appear slightly larger there. “Repository LFS and other” includes Git LFS files and any pool object the run queue does not reference.</p> | |
| 128 | {{end}} | |
| 129 | {{end}} | |
| 130 | ||
| 131 | {{if eq .Tab "runners"}} | |
| 132 | <h2 id="runners">Runners and queue</h2> | |
| 133 | {{if .RunnerErr}}<div class="flash bad">{{.RunnerErr}}</div>{{end}} | |
| 134 | {{if .RunnerSessions}} | |
| 135 | <div class="panel"> | |
| 136 | <table> | |
| 137 | <thead><tr><th>Runner</th><th>Takes</th><th>State</th><th>Last seen</th></tr></thead> | |
| 138 | <tbody> | |
| 139 | {{range .RunnerSessions}} | |
| 140 | <tr> | |
| 141 | <td>{{.Account}}</td> | |
| 142 | <td class="muted">{{if .Labels}}{{.Labels}}{{else}}any job{{end}}</td> | |
|
ed03b3d1
Keenan Nemetz
3h ago
|
143 | <td>{{if .Idle}}<span class="muted">waiting for work</span>{{else if .RunID}}<a href="/{{.Repo}}/runs/{{.RunID}}">{{.Job}}</a> on <a href="/{{.Repo}}">{{.Repo}}</a>{{else}}<span class="muted">busy</span>{{end}}</td> |
|
4506a4d3
Keenan Nemetz
13d ago
|
144 | <td class="muted">{{since .Seen.Unix}}</td> |
| 145 | </tr> | |
| 146 | {{end}} | |
| 147 | </tbody> | |
| 148 | </table> | |
| 149 | </div> | |
| 150 | {{else}} | |
|
c7b9094f
Keenan Nemetz
1d ago
|
151 | <div class="empty-state"> |
| 152 | <p>No runner is connected: none has been seen in the last {{.RunnerWindow}}. Start one with <code>vole runner --remote ssh://git@<host></code>. If a job asks for a machine with <code>runs-on</code>, the runner has to carry that label with <code>--label</code>.</p> | |
| 153 | </div> | |
|
4506a4d3
Keenan Nemetz
13d ago
|
154 | {{end}} |
| 155 | ||
| 156 | <h3>Queue</h3> | |
| 157 | {{if .RunnerQueue}} | |
| 158 | <div class="panel"> | |
| 159 | <table> | |
| 160 | <thead><tr><th>Repository</th><th>Waiting</th><th>Running</th></tr></thead> | |
| 161 | <tbody> | |
| 162 | {{range .RunnerQueue}} | |
| 163 | <tr> | |
|
ed03b3d1
Keenan Nemetz
3h ago
|
164 | <td><a href="/{{.Name}}">{{.Name}}</a></td> |
|
4506a4d3
Keenan Nemetz
13d ago
|
165 | <td class="muted">{{.Queued}}</td> |
| 166 | <td class="muted">{{.Running}}{{if .Cap}}{{if ge .Running .Cap}} of {{.Cap}} <span class="muted">(at the cap)</span>{{else}} of {{.Cap}}{{end}}{{end}}</td> | |
| 167 | </tr> | |
| 168 | {{end}} | |
| 169 | </tbody> | |
| 170 | </table> | |
| 171 | </div> | |
| 172 | {{else}} | |
|
c7b9094f
Keenan Nemetz
1d ago
|
173 | <div class="empty-state"><p>Nothing is waiting and nothing is running.</p></div> |
|
4506a4d3
Keenan Nemetz
13d ago
|
174 | {{end}} |
| 175 | {{end}} | |
| 176 | ||
| 177 | {{if eq .Tab "configuration"}} | |
|
6ce635a8
Keenan Nemetz
1d ago
|
178 | <h2 id="instance-repository">Instance repository</h2> |
| 179 | {{if .InstanceRepo.Created}}<div class="flash good">Instance repository created. The home page now reads <code>profile/README.md</code> from it.</div>{{end}} | |
| 180 | {{if not .InstanceRepo.Enabled}} | |
| 181 | <p class="muted">Customization from a repository is disabled because <code>instance_repo</code> is empty.</p> | |
| 182 | {{else if .InstanceRepo.Ready}} | |
| 183 | {{if .InstanceRepo.Err}}<div class="flash warn">The last reload failed; the previous theme is still in use: {{.InstanceRepo.Err}}</div>{{end}} | |
| 184 | <p class="muted">Loaded from <code>{{.InstanceRepo.Name}}</code> at <code>{{short .InstanceRepo.Commit}}</code>. | |
| 185 | Clone it with <code>{{.InstanceRepo.CloneURL}}</code>.</p> | |
| 186 | {{else}} | |
| 187 | {{if .InstanceRepo.Err}} | |
| 188 | <p class="muted">The instance repository <code>{{.InstanceRepo.Name}}</code> is not readable: {{.InstanceRepo.Err}}</p> | |
| 189 | {{else}} | |
| 190 | <p class="muted">The instance repository <code>{{.InstanceRepo.Name}}</code> does not exist yet.</p> | |
| 191 | {{end}} | |
|
ed03b3d1
Keenan Nemetz
3h ago
|
192 | <form method="post" action="/-/admin/instance/repo" class="form-block"> |
|
6ce635a8
Keenan Nemetz
1d ago
|
193 | <input type="hidden" name="csrf" value="{{.CSRF}}"> |
| 194 | <div class="form-actions"><button type="submit">{{icon "plus"}}Create instance repository</button></div> | |
| 195 | </form> | |
| 196 | <p class="muted">Or create a repository named <code>{{.InstanceRepo.Name}}</code> and push the files below.</p> | |
| 197 | {{end}} | |
| 198 | <div class="panel"> | |
| 199 | <table class="config-table"> | |
| 200 | <thead><tr><th>Path</th><th>What it does</th></tr></thead> | |
| 201 | <tbody> | |
| 202 | <tr><td><code>profile/README.md</code></td><td>Landing page introduction (markdown, sanitized)</td></tr> | |
| 203 | <tr><td><code>profile/private/README.md</code></td><td>The same, only for signed-in viewers</td></tr> | |
|
f7a34d87
Keenan Nemetz
1d ago
|
204 | <tr><td><code>profile/custom.css</code></td><td>Instance-wide stylesheet, loaded after the built-in ones and any theme</td></tr> |
|
d222b0cf
Keenan Nemetz
1d ago
|
205 | <tr><td><code>profile/themes/<id>.css</code></td><td>One stylesheet per theme; the file name is its label in Account → Appearance</td></tr> |
|
6ce635a8
Keenan Nemetz
1d ago
|
206 | <tr><td><code>profile/favicon.svg</code></td><td>Favicon override</td></tr> |
|
ed03b3d1
Keenan Nemetz
3h ago
|
207 | <tr><td><code>assets/</code></td><td>Files served at <code>/-/static/custom/assets/</code></td></tr> |
|
6ce635a8
Keenan Nemetz
1d ago
|
208 | </tbody> |
| 209 | </table> | |
| 210 | </div> | |
|
3e7c5e67
Keenan Nemetz
1d ago
|
211 | <p class="muted">This is an ordinary repository: it appears in the repository list and its visibility is set in its own Settings. It is private to instance admins by default, but the files above are served to visitors.</p> |
|
4506a4d3
Keenan Nemetz
13d ago
|
212 | {{if .Config}} |
| 213 | <h2 id="configuration">Configuration</h2> | |
| 214 | <p class="muted">Effective values read at startup. This page is read-only; edit the file on the host and restart Vole to apply changes.</p> | |
| 215 | {{if .Config.Path}} | |
| 216 | <p class="muted">Config file: <code>{{.Config.Path}}</code></p> | |
| 217 | {{if not .Config.Loaded}}<div class="flash warn">That file was not found or was empty at startup, so the built-in defaults below are in use.</div>{{end}} | |
| 218 | {{else}} | |
| 219 | <p class="muted">No config file was read; the built-in defaults below are in use.</p> | |
| 220 | {{end}} | |
| 221 | <div class="panel"> | |
| 222 | <table class="config-table"> | |
| 223 | <thead><tr><th>Setting</th><th>Effective value</th></tr></thead> | |
| 224 | <tbody> | |
| 225 | {{range .Config.Groups}} | |
| 226 | <tr class="config-group"><td colspan="2">{{.Name}}</td></tr> | |
| 227 | {{range .Settings}} | |
|
09b15120
Keenan Nemetz
15d ago
|
228 | <tr> |
|
4506a4d3
Keenan Nemetz
13d ago
|
229 | <td><code>{{.Key}}</code></td> |
| 230 | <td>{{.Value}}{{if .Note}} <span class="muted">— {{.Note}}</span>{{end}}{{if .Warn}} <span class="check-state warn">warning</span>{{end}}</td> | |
|
09b15120
Keenan Nemetz
15d ago
|
231 | </tr> |
| 232 | {{end}} | |
|
4506a4d3
Keenan Nemetz
13d ago
|
233 | {{end}} |
|
09b15120
Keenan Nemetz
15d ago
|
234 | </tbody> |
| 235 | </table> | |
| 236 | </div> | |
|
4506a4d3
Keenan Nemetz
13d ago
|
237 | {{else}} |
| 238 | <p class="muted">Configuration is unavailable.</p> | |
| 239 | {{end}} | |
| 240 | {{end}} | |
|
09b15120
Keenan Nemetz
15d ago
|
241 | {{end}} |