From eba7896893531fee1eb7ee22f294068b713d8a6f Mon Sep 17 00:00:00 2001 From: Ian Roddis <31021769+iroddis@users.noreply.github.com> Date: Thu, 25 Jun 2026 16:06:36 -0300 Subject: [PATCH] Doing a relayout of permissions to make it a bit easier to navigate --- app/static/css/style.css | 31 +++++++++++++++++++ app/templates/admin/_role_row.html | 27 +++++++++++++++- app/templates/admin/_role_row_edit.html | 34 ++++++++++++++++---- app/templates/admin/roles.html | 29 +++++++++++++++-- app/web/admin.py | 41 ++++++++++++++++--------- 5 files changed, 138 insertions(+), 24 deletions(-) diff --git a/app/static/css/style.css b/app/static/css/style.css index 4ea8a6f..ef4996f 100644 --- a/app/static/css/style.css +++ b/app/static/css/style.css @@ -207,6 +207,37 @@ input[type=password] { padding: 0 0.4rem; } +.perm-matrix { + border-collapse: collapse; + font-size: 0.85rem; +} + +.perm-matrix th, +.perm-matrix td { + padding: 0.2rem 0.5rem; + border: 1px solid var(--border); + text-align: center; +} + +.perm-matrix th { + background: var(--surface-2); + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.04em; + color: var(--muted); +} + +.perm-matrix .perm-scope { + text-align: left; + font-weight: 500; + white-space: nowrap; + padding-right: 1rem; +} + +.perm-matrix .perm-na { + color: var(--muted); +} + .inline-edit { display: flex; flex-wrap: wrap; diff --git a/app/templates/admin/_role_row.html b/app/templates/admin/_role_row.html index 2cb0256..7d0f37a 100644 --- a/app/templates/admin/_role_row.html +++ b/app/templates/admin/_role_row.html @@ -2,7 +2,32 @@ {{ r.id }} {{ r.name }} {{ r.description or "" }} - {% for perm in r.permissions %}{{ perm.name }}{% endfor %} + + {% set role_perm_names = r.permissions | map(attribute='name') | list %} + + + + + {% for action in actions %}{% endfor %} + + + + {% for scope in scopes %} + + + {% for action in actions %} + {% set key = scope ~ ':' ~ action %} + {% if key in perm_map %} + + {% else %} + + {% endif %} + {% endfor %} + + {% endfor %} + +
{{ action }}
{{ scope }}{{ '✓' if key in role_perm_names else '' }}—
+ diff --git a/app/templates/admin/roles.html b/app/templates/admin/roles.html index 4d4a674..c4e4b0c 100644 --- a/app/templates/admin/roles.html +++ b/app/templates/admin/roles.html @@ -12,11 +12,34 @@
Permissions - {% for perm in permissions %} - + {% if scopes %} + + + + + {% for action in actions %}{% endfor %} + + + + {% for scope in scopes %} + + + {% for action in actions %} + {% set key = scope ~ ':' ~ action %} + {% if key in perm_map %} + {% set p = perm_map[key] %} + + {% else %} + + {% endif %} + {% endfor %} + + {% endfor %} + +
{{ action }}
{{ scope }}—
{% else %} No permissions defined. Run the seed script. - {% endfor %} + {% endif %}
diff --git a/app/web/admin.py b/app/web/admin.py index b3dbf79..c0032cc 100644 --- a/app/web/admin.py +++ b/app/web/admin.py @@ -9,17 +9,17 @@ from app.crud import audit as audit_crud from app.crud import imported_part as imported_part_crud from app.crud import imported_part_config as imported_part_config_crud from app.crud import iso_thread as iso_thread_crud -from app.crud import sub_part_type as sub_part_type_crud -from app.services import odata as odata_service from app.crud import manufacturer as manufacturer_crud from app.crud import part_type as part_type_crud from app.crud import role as role_crud from app.crud import scope_model as scope_model_crud +from app.crud import sub_part_type as sub_part_type_crud from app.crud import unc_thread as unc_thread_crud from app.crud import user as user_crud from app.deps import get_current_web_user from app.models.unc_thread import UncSeries from app.models.user import User +from app.services import odata as odata_service from app.web.templates import templates router = APIRouter(prefix="/admin", include_in_schema=False) @@ -39,6 +39,18 @@ def web_require(*perms: str): return checker +async def _role_perm_ctx(db: AsyncSession) -> dict: + all_perms = await role_crud.list_permissions(db) + scopes = sorted({p.name.split(":")[0] for p in all_perms}) + perm_map = {p.name: p for p in all_perms} + return { + "permissions": all_perms, + "scopes": scopes, + "perm_map": perm_map, + "actions": ["read", "write", "delete"], + } + + @router.get("", response_class=HTMLResponse) async def admin_home(): return RedirectResponse(url="/admin/users", status_code=status.HTTP_302_FOUND) @@ -190,11 +202,7 @@ async def roles_page( return templates.TemplateResponse( request, "admin/roles.html", - { - "user": user, - "roles": await role_crud.list_roles(db), - "permissions": await role_crud.list_permissions(db), - }, + {"user": user, "roles": await role_crud.list_roles(db), **(await _role_perm_ctx(db))}, ) @@ -222,10 +230,7 @@ async def create_role( return templates.TemplateResponse( request, "admin/_roles_table.html", - { - "roles": await role_crud.list_roles(db), - "permissions": await role_crud.list_permissions(db), - }, + {"roles": await role_crud.list_roles(db), **(await _role_perm_ctx(db))}, ) @@ -242,7 +247,7 @@ async def edit_role_row( return templates.TemplateResponse( request, "admin/_role_row_edit.html", - {"r": role, "permissions": await role_crud.list_permissions(db)}, + {"r": role, **(await _role_perm_ctx(db))}, ) @@ -256,7 +261,11 @@ async def role_row( role = await role_crud.get(db, role_id) if role is None: raise HTTPException(status_code=404, detail="Role not found") - return templates.TemplateResponse(request, "admin/_role_row.html", {"r": role}) + return templates.TemplateResponse( + request, + "admin/_role_row.html", + {"r": role, **(await _role_perm_ctx(db))}, + ) @router.post("/roles/{role_id}", response_class=HTMLResponse) @@ -277,7 +286,11 @@ async def update_role( resource_id=role_id, description=audit_crud.describe_update("Role", role_id, changes), ) - return templates.TemplateResponse(request, "admin/_role_row.html", {"r": role}) + return templates.TemplateResponse( + request, + "admin/_role_row.html", + {"r": role, **(await _role_perm_ctx(db))}, + ) @router.delete("/roles/{role_id}")