Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

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.

Code

392 commit(s) on main

Merge change request 01M70WES5ZZDJ6RP226WB11BBZ: Let people rename and remove their own passkeys keenan · 53m ago 4b8c9e1d
history blame raw 10.2 KiB
1{{define "status_body"}}
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">
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>
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
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>
50<p class="muted"><a href="/-/admin?tab=audit">Read the full audit log</a></p>
51{{else if not .RecentAudit.Err}}
52<div class="empty-state"><p>No privileged actions have been recorded yet.</p></div>
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>
70<p class="muted"><a href="/-/admin?tab=configuration">See every effective setting</a></p>
71{{end}}
72
73<h2>Page views</h2>
74{{if .Views.Disabled}}
75<p class="muted">Page-view tracking is not wired on this instance.</p>
76{{else}}
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>
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>
89{{end}}
90{{end}}
91
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>
105</div>
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}}
111
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}}
117<div class="panel">
118<table>
119 <thead><tr><th>Kind</th><th>Objects</th><th>Size</th></tr></thead>
120 <tbody>
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>
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>
144 <td class="muted">{{since .Seen.Unix}}</td>
145 </tr>
146 {{end}}
147 </tbody>
148</table>
149</div>
150{{else}}
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@&lt;host&gt;</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>
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>
164 <td><a href="/{{.Name}}">{{.Name}}</a></td>
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}}
173<div class="empty-state"><p>Nothing is waiting and nothing is running.</p></div>
174{{end}}
175{{end}}
176
177{{if eq .Tab "configuration"}}
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>.
185Clone 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}}
192<form method="post" action="/-/admin/instance/repo" class="form-block">
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>
204 <tr><td><code>profile/custom.css</code></td><td>Instance-wide stylesheet, loaded after the built-in ones and any theme</td></tr>
205 <tr><td><code>profile/themes/&lt;id&gt;.css</code></td><td>One stylesheet per theme; the file name is its label in Account → Appearance</td></tr>
206 <tr><td><code>profile/favicon.svg</code></td><td>Favicon override</td></tr>
207 <tr><td><code>assets/</code></td><td>Files served at <code>/-/static/custom/assets/</code></td></tr>
208 </tbody>
209</table>
210</div>
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>
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}}
228 <tr>
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>
231 </tr>
232 {{end}}
233 {{end}}
234 </tbody>
235</table>
236</div>
237{{else}}
238<p class="muted">Configuration is unavailable.</p>
239{{end}}
240{{end}}
241{{end}}
242