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.
Add instance-wide roles and refine access UI
5b814e9958090cfd1fa826efb2d375bf613547c1 · Keenan Nemetz · 14d ago · parent 9579c1f9
Add instance-wide roles and refine access UI Instance roles now live on accounts, apply to public repositories, and the Admin role is the unified instance-admin permission with access to every repository. Repository ACLs can raise an instance role but not lower it. Adds role assignment to the users UI and CLI, open-registration role config, a reusable role picker, and separates adding a repository account from saving access rules.
server/web/static/vole.css +56
| @@ -1558,6 +1558,62 @@ details[open] > summary .tree-chevron { transform: rotate(90deg); } | |||
| 1558 | 1558 | .acl-check { display: flex; align-items: center; gap: 6px; } | |
| 1559 | 1559 | .acl-check input[type="checkbox"] { width: auto; margin: 0; } | |
| 1560 | 1560 | table.acl select { min-width: 9rem; } | |
| 1561 | .role-options { border: 0; padding: 0; margin: 0; min-width: 0; } | ||
| 1562 | .role-options legend { | ||
| 1563 | padding: 0; | ||
| 1564 | margin: 0 0 8px; | ||
| 1565 | color: var(--fg); | ||
| 1566 | font-size: 13px; | ||
| 1567 | font-weight: 600; | ||
| 1568 | } | ||
| 1569 | .role-options > p { margin: 0 0 10px; } | ||
| 1570 | .role-option { | ||
| 1571 | display: flex; | ||
| 1572 | align-items: baseline; | ||
| 1573 | gap: 7px; | ||
| 1574 | margin: 5px 0; | ||
| 1575 | padding: 7px 10px; | ||
| 1576 | border: 1px solid var(--border); | ||
| 1577 | border-radius: var(--radius); | ||
| 1578 | color: var(--fg); | ||
| 1579 | font-size: 13px; | ||
| 1580 | cursor: pointer; | ||
| 1581 | } | ||
| 1582 | .role-option:hover { border-color: var(--border-strong); background: var(--bg-raised); } | ||
| 1583 | .role-option:has(input[type="radio"]:checked) { | ||
| 1584 | border-color: var(--accent); | ||
| 1585 | background: var(--accent-soft); | ||
| 1586 | } | ||
| 1587 | .role-option input[type="radio"] { | ||
| 1588 | display: block; | ||
| 1589 | flex: 0 0 auto; | ||
| 1590 | width: auto; | ||
| 1591 | margin: 0; | ||
| 1592 | accent-color: var(--accent); | ||
| 1593 | } | ||
| 1594 | .role-option .role-name { font-weight: 600; } | ||
| 1595 | .role-option .role-desc { color: var(--fg-muted); font-size: 12px; line-height: 1.45; } | ||
| 1596 | .role-options.compact { display: flex; flex-wrap: wrap; gap: 4px 12px; } | ||
| 1597 | .role-options.compact legend { display: none; } | ||
| 1598 | .role-options.compact .role-option { | ||
| 1599 | display: inline-flex; | ||
| 1600 | align-items: center; | ||
| 1601 | gap: 5px; | ||
| 1602 | margin: 0; | ||
| 1603 | padding: 0; | ||
| 1604 | border: 0; | ||
| 1605 | border-radius: 0; | ||
| 1606 | background: none; | ||
| 1607 | font-size: 12px; | ||
| 1608 | } | ||
| 1609 | .role-options.compact .role-option:hover { background: none; } | ||
| 1610 | .role-options.compact .role-option:has(input[type="radio"]:checked) { | ||
| 1611 | border: 0; | ||
| 1612 | background: none; | ||
| 1613 | } | ||
| 1614 | .role-options.compact .role-option:has(input[type="radio"]:checked) .role-name { color: var(--accent); } | ||
| 1615 | .role-options.compact .role-desc { display: none; } | ||
| 1616 | .role-options.compact input[type="radio"] { margin: 0; } | ||
| 1561 | 1617 | .form-card { margin: 0; } | |
| 1562 | 1618 | .form-actions { | |
| 1563 | 1619 | display: flex; | |