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.

Build out the forge web UI

f09ef39efe44de693748053a7b596ef328fcf06b · Keenan Nemetz · 15d ago · parent 70b70264

Build out the forge web UI

Turn the web surface into a compact, server-rendered forge with HTMX as the
progressive dynamic layer.

- Split templates and assets into embedded files; add a tokenised dark theme,
  Lucide icons, and vendored HTMX.
- Add the repository Overview page and a separate chronological Activity feed
  with type filters and HTMX fragment updates.
- Finish the issue and change workflows: create pages, comments, close/reopen,
  labels and assignees, approval, discussion, line-anchored review comments,
  and HTMX list filters.
- Add syntax-highlighted blobs, contributor/statistics derivation, branch-aware
  code browsing, and a repository Runs list.
- Add a loopback-only development login for local write testing, with explicit
  configuration and listener checks.
- Extend tests for the new pages, fragments, labels, assignees, anchors, and
  development login.

docs/ui-plan.md +172

@@ -0,0 +1,172 @@
1 # UI plan
2
3 Working notes for Vole's web surface. Decisions here are the brief; change them
4 deliberately rather than by drift.
5
6 ## Direction
7
8 - **Compact, not sparse.** Take Linear's information density and restraint.
9 Avoid GitHub's whitespace-heavy chrome; avoid Sourcehut's bareness. A row of
10 data should be readable at a glance, and a page should fit on one screen when
11 it can.
12 - **Dark only for now.** Every colour comes from a custom property on `:root`.
13 A light theme is a second block of variables, not a rewrite.
14 - **Server rendered.** Go `html/template` produces the page. HTMX is the default
15 dynamic layer, vendored into the binary; JavaScript remains for passkeys,
16 clipboard copy, and rich widgets such as the label/assignee token input.
17 No SPA, no client-side router, no npm build.
18 - **Progressive enhancement.** Forms keep a normal `method`/`action` fallback.
19 Handlers answer a fragment when `HX-Request: true` and a redirect otherwise.
20 - **Identity later.** Keep the `vole` wordmark as a placeholder and keep colour,
21 type, radius, and spacing in tokens so a real identity is a token swap.
22 - **Single tenant.** No organisation/workspace switcher. The global bar has
23 three destinations; the repository owns its own horizontal tabs.
24
25 ## Navigation model
26
27 Global bar (slim): `Repositories` · `Runners` · account/login.
28
29 Repository header: name, then horizontal tabs directly beneath it:
30
31 `Overview` · `Activity` · `Code` · `Issues` · `Changes` · `Releases` · `Runs` · `Locks` · `Settings`
32
33 No sidebar. A sidebar only pays for its width when there are many persistent
34 destinations; here the repository has seven, and they fit on one row at desktop
35 widths. On narrow screens the row scrolls horizontally rather than collapsing
36 into a menu.
37
38 Overview is the project page: README in the main column; recent commits, recent
39 runs, releases, contributors, languages, and size in the sidebar. Activity is the
40 chronological feed: commits, issues, changes, releases, and runs with type
41 filters. Code is the file browser. Settings appears once the page exists and the
42 viewer has an admin role.
43
44 ## Surfaces
45
46 Status: `done` exists today · `wip` in progress · `todo` missing.
47
48 ### Global
49
50 - done — repository list (`/`)
51 - done — login, registration, enrollment link
52 - done — account (display name, keys, passkeys, sessions)
53 - done — runners and queue
54 - todo — styled 404 / 500 pages everywhere
55 - todo — search across visible repositories
56 - todo — instance-wide activity feed on the home page (after the repo feed)
57 - todo — instance admin: users, invites, keys, repos, permissions
58 - todo — health/status page (currently JSON at `/healthz`)
59
60 ### Repository
61
62 - done — code tab, tree, blob with line numbers, raw
63 - done — commit history, commit view, parent links, diff
64 - done — issues list/detail, comments, filters, close/reopen, labels and assignees (create and edit)
65 - done — changes list/detail, discussion composer, approvals, inline-comment markers, close/reopen
66 - done — releases list/detail, artifacts, archives
67 - done — locks
68 - done — run detail, log, artifacts
69 - done — runs list per repository (`/r/{name}/runs`) with status filters
70 - done — repository activity feed on `/r/{name}/activity`: commits, issues,
71 changes, releases, runs, type filters, and HTMX fragment updates
72 - todo — activity events from metadata-log state changes (closed/reopened),
73 actor filter, and assignee filter
74 - todo — repository settings: description, default branch, ACL, visibility,
75 danger zone
76 - todo — compare view (`/r/{name}/compare/{base}...{head}`)
77 - todo — file history and blame
78 - todo — syntax highlighting in the blob view
79 - todo — language-aware file icons
80 - todo — code search within a repository
81 - todo — release create/edit from the browser (today CLI/tag push)
82 - done — inline review comments on diff lines; the marker appears on the next
83 page load
84
85 ### CI
86
87 - done — runner list, queue, run detail/log/artifacts
88 - todo — workflow/job list per repository
89 - todo — rerun/cancel from the browser (only if the queue model supports it)
90
91 ## Slice order
92
93 1. ~~**Foundations**~~ — embedded template files, tokenised CSS, slim shell,
94 repo tabs, styled not-found.
95 2. **Code browsing** — overview/code split, stats, contributors, runs list,
96 tree, line-numbered blobs, commit/diff. Syntax highlighting remains.
97 3. **Issues and changes** — done: list/detail layout, composer, filters,
98 close/reopen, discussion. Remaining: label/assignee triage, writing inline
99 review comments.
100 4. **Activity and settings** — repository activity feed, repository settings,
101 ACL editor.
102 5. **Instance admin** — users, invitations, keys, repositories, permissions.
103 6. **CI** — workflow/job list, rerun/cancel.
104 7. **Polish** — search, responsive pass, accessibility pass, light theme,
105 empty states, pagination.
106
107 ## Dynamic layer
108
109 HTMX 2.0.11 is pinned at `server/web/static/htmx.min.js` (Zero-Clause BSD,
110 license beside it). It is served from the embedded static assets and loaded on
111 every page. Interactions are converted one flow at a time:
112
113 - done — issue close/reopen, labels, assignees, and comments update their
114 section in place. Labels and assignees save on token change; there is no
115 visible save button.
116 - done — change approve/close updates the sidebar, and comments update the
117 discussion fragment.
118 - done — Issues and Changes filters swap their list fragment and push the URL.
119 - done — repository activity feed swaps its event fragment for type filters and
120 pushes the URL.
121 - done — diff lines link to an anchored review composer; posted anchors are
122 stored with the reviewed blob.
123
124 The token input and passkey ceremonies stay custom JavaScript: HTMX moves HTML
125 from the server, it does not manage client-side chip state or credential APIs.
126
127 ## Activity feed
128
129 No notification table and no per-user inbox. The feed is derived from Git, the
130 metadata branch, tags, and the run queue. Events carry a type, time, actor,
131 title, link, and (for issue/change events) assignees so the same feed can later
132 be filtered by assignee.
133
134 Repository feed is done on `/r/{name}/activity`; Overview stays the project
135 summary. The home page will become the instance-wide feed over visible
136 repositories. State changes such as closed and reopened need the metadata branch
137 log; the first feed covers creation, comments, approvals, commits, releases, and
138 runs.
139
140 ## Admin scope
141
142 Instance admin covers the operations that are currently CLI-only:
143
144 - users: create by invitation, retire, grant/revoke admin; inspect/revoke keys
145 and sessions
146 - repositories: create, rename, delete
147 - per-repository ACL: set roles, default role, approvals, checks, runners
148
149 The web admin will not ask an admin to paste a user's SSH key. Account creation
150 uses the existing `identity.CreateWithInvite` path and returns a one-time
151 enrollment link; browser auth must be enabled for that link to work.
152
153 Repository admins still own repository settings (description, default branch,
154 visibility, danger zone). Every admin write uses the existing stores, CSRF, and
155 the audit log; the web is a second surface over the same operations, not a
156 second implementation.
157
158 ## Icons
159
160 Icons are Lucide 0.468.0 SVGs (ISC, license at `server/web/static/lucide.LICENSE`),
161 stored as path data in `server/web/icons.go` and rendered inline with
162 `{{icon "name"}}`. No icon font, no CDN, no network request; they inherit
163 `currentColor` and size with the surrounding text. A test checks that every icon
164 named in a template exists.
165
166 ## Rules
167
168 - Every state-changing form carries the CSRF hidden input.
169 - A private repository answers 404, never 403.
170 - No inline CSS or JS in templates; assets live in `server/web/static/`.
171 - Tables are for tabular data; navigation and page chrome are not tables.
172 - Test the page at 1440, 1024, and 390 px wide before calling it done.