Show effective access roles in HTML5 workspace
CI / python (push) Has been cancelled
CI / rust (push) Has been cancelled

This commit is contained in:
2026-05-21 19:40:12 +03:00
parent 87236606d1
commit 5f066d2f6b
5 changed files with 76 additions and 3 deletions
@@ -70,7 +70,8 @@ def render_html5_access_page(
<div class="panel-title">Группы доступа</div>
<div class="access-list">{''.join(_group_card(item) for item in groups[:80]) or '<p class="muted padded">Группы не найдены</p>'}</div>
<div class="panel-title">Пользователи</div>
<div class="access-list">{''.join(_user_card(item) for item in users[:80]) or '<p class="muted padded">Пользователи не найдены</p>'}</div>
<div data-html5-access-user-detail>{render_html5_access_user_detail(project_id=project_id, user_payload=None)}</div>
<div class="access-list">{''.join(_user_card(project_id, item) for item in users[:80]) or '<p class="muted padded">Пользователи не найдены</p>'}</div>
</aside>
</section>
</main>
@@ -157,6 +158,35 @@ def render_html5_access_profile_apply_result(*, project_id: str, response: objec
"""
def render_html5_access_user_detail(*, project_id: str, user_payload: dict | None) -> str:
if user_payload is None:
return """
<section class="access-user-detail">
<p class="muted padded">Выберите пользователя, чтобы увидеть группы и эффективные роли.</p>
</section>
"""
user = dict(user_payload.get("user") or {})
roles = list(user_payload.get("effective_roles") or [])
groups = list(user.get("groups") or [])
name = str(user.get("name") or "")
full_name = str(user.get("full_name") or "")
return f"""
<section class="access-user-detail" data-html5-access-user="{escape(name)}">
<div class="access-plan-head">
<span class="status-pill">пользователь</span>
<strong>{escape(name)}</strong>
</div>
<p class="object-summary">{escape(full_name or "ФИО не загружено")}</p>
<div class="report-grid">
{_metric("Группы", len(groups))}
{_metric("Эффективные роли", len(roles))}
</div>
{_notice_list("Группы пользователя", groups)}
<div class="access-role-grid">{''.join(_role_card(_DictRole(item)) for item in roles) or '<p class="muted padded">Эффективные роли не найдены</p>'}</div>
</section>
"""
def render_html5_access_profile(*, project_id: str, profile: object | None) -> str:
if profile is None:
return """
@@ -308,11 +338,21 @@ def _group_card(group: object) -> str:
return f'<article class="access-card"><strong>{escape(name)}</strong><small>{escape(profile)} · {len(users)} пользователей</small></article>'
def _user_card(user: object) -> str:
def _user_card(project_id: str, user: object) -> str:
name = str(getattr(user, "name", ""))
full_name = str(getattr(user, "full_name", "") or "")
groups = list(getattr(user, "groups", []) or [])
return f'<article class="access-card"><strong>{escape(name)}</strong><small>{escape(full_name)} · {len(groups)} групп</small></article>'
return f"""
<article
class="access-card"
hx-get="/html5/projects/{quote(project_id)}/access/users/{quote(name, safe='')}"
hx-target="[data-html5-access-user-detail]"
hx-swap="innerHTML"
>
<strong>{escape(name)}</strong>
<small>{escape(full_name)} · {len(groups)} групп</small>
</article>
"""
def _operation_card(operation: dict) -> str:
@@ -359,3 +399,10 @@ class _DictProfile:
self.roles = payload.get("roles") or []
self.attributes = payload.get("attributes") or {}
self.source = payload.get("source") or "workspace"
class _DictRole:
def __init__(self, payload: dict):
self.role = str(payload.get("role") or payload.get("name") or "")
self.role_qualified_name = str(payload.get("role_qualified_name") or payload.get("qualified_name") or self.role)
self.source = str(payload.get("source") or "")