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.
Fold admin work into repository settings and a Users page
9579c1f976254fdeb2ec73d4016db5b25c7921c1 · Keenan Nemetz · 14d ago · parent 381d6aac
Fold admin work into repository settings and a Users page Remove the combined /admin tabs. Per-repository access rules now live on the repository's Settings page, visible to instance admins while repository details and the danger zone stay with repository admins. User management moves to /users, linked from the top navigation only for instance admins, and repository creation moves to /repos/new. Align the invite, danger-zone, and settings forms with the shared card-and-actions layout, and make settings section headings consistent.
server/web/static/vole.css +7−22
| @@ -241,25 +241,22 @@ img { max-width: 100%; } | |||
| 241 | 241 | } | |
| 242 | 242 | ||
| 243 | 243 | /* The tab pages are a level below the repository identity: their own headers | |
| 244 | stay small. Top-level pages (Runners, Account, Status, Admin) keep the | ||
| 245 | home-page header scale. */ | ||
| 246 | .repohead + .page-head, | ||
| 247 | .page-head.subhead { | ||
| 244 | stay small. Top-level pages (Runners, Activity, Users, Account, Status) keep | ||
| 245 | the home-page header scale. */ | ||
| 246 | .repohead + .page-head { | ||
| 248 | 247 | align-items: flex-start; | |
| 249 | 248 | gap: 16px; | |
| 250 | 249 | padding: 0; | |
| 251 | 250 | margin-bottom: 12px; | |
| 252 | 251 | border-bottom: 0; | |
| 253 | 252 | } | |
| 254 | .repohead + .page-head h1, | ||
| 255 | .page-head.subhead h1 { | ||
| 253 | .repohead + .page-head h1 { | ||
| 256 | 254 | font-size: 18px; | |
| 257 | 255 | line-height: 1.35; | |
| 258 | 256 | letter-spacing: -0.005em; | |
| 259 | 257 | margin: 0 0 3px; | |
| 260 | 258 | } | |
| 261 | .repohead + .page-head .page-sub, | ||
| 262 | .page-head.subhead .page-sub { font-size: 12.5px; } | ||
| 259 | .repohead + .page-head .page-sub { font-size: 12.5px; } | ||
| 263 | 260 | ||
| 264 | 261 | @media (max-width: 720px) { | |
| 265 | 262 | .repo-title { padding: 18px 0 10px; } | |
| @@ -1189,19 +1186,6 @@ details[open] > summary .tree-chevron { transform: rotate(90deg); } | |||
| 1189 | 1186 | .page-head-actions .clone-pop { left: auto; right: 0; } | |
| 1190 | 1187 | .page-sub { color: var(--fg-muted); font-size: 13px; margin: 0; max-width: 80ch; } | |
| 1191 | 1188 | ||
| 1192 | /* Admin is a top-level page with its own tabs, so its title does not need the | ||
| 1193 | usual rule; the tab bar is the divider. Detail pages under it use .subhead. */ | ||
| 1194 | .page-head.admin-head { padding-bottom: 8px; margin-bottom: 0; border-bottom: 0; } | ||
| 1195 | .admin-tabs { border-bottom: 1px solid var(--border); margin-bottom: 20px; } | ||
| 1196 | .toolbar { | ||
| 1197 | display: flex; | ||
| 1198 | align-items: center; | ||
| 1199 | justify-content: space-between; | ||
| 1200 | gap: 12px; | ||
| 1201 | margin: 0 0 12px; | ||
| 1202 | } | ||
| 1203 | .toolbar .muted { font-size: 12px; } | ||
| 1204 | |||
| 1205 | 1189 | @media (max-width: 720px) { | |
| 1206 | 1190 | .page-head { padding: 18px 0 16px; } | |
| 1207 | 1191 | .page-head h1 { font-size: 22px; } | |
| @@ -1570,6 +1554,7 @@ details[open] > summary .tree-chevron { transform: rotate(90deg); } | |||
| 1570 | 1554 | /* Form cards: fields live on a card, actions sit below it and align right. | |
| 1571 | 1555 | Every primary action uses the same height and horizontal padding. */ | |
| 1572 | 1556 | .form-block { margin: 12px 0; } | |
| 1557 | .danger-form + .danger-form { margin-top: 28px; } | ||
| 1573 | 1558 | .acl-check { display: flex; align-items: center; gap: 6px; } | |
| 1574 | 1559 | .acl-check input[type="checkbox"] { width: auto; margin: 0; } | |
| 1575 | 1560 | table.acl select { min-width: 9rem; } | |
| @@ -1769,7 +1754,7 @@ form.htmx-request .label-tokens { opacity: 0.6; } | |||
| 1769 | 1754 | .activity-title { white-space: normal; } | |
| 1770 | 1755 | } | |
| 1771 | 1756 | .danger-zone { border-color: color-mix(in srgb, var(--bad) 40%, var(--border)); } | |
| 1772 | .danger-zone h3 { margin: 14px 0 4px; } | ||
| 1757 | .danger-zone h3 { margin: 14px 0 4px; color: var(--fg-muted); } | ||
| 1773 | 1758 | .state.active { color: var(--good); } | |
| 1774 | 1759 | .state.retired { color: var(--fg-faint); } | |
| 1775 | 1760 | ||