From 4a5874d4f8eb8b1f66c121236c66efd9db0146dd Mon Sep 17 00:00:00 2001 From: Allan Eising Date: Thu, 19 Jun 2025 19:44:33 +0200 Subject: [PATCH] Update views --- .../frontend/templates/base/bare.html.j2 | 23 +++ .../frontend/templates/clients/client.html.j2 | 4 +- .../frontend/templates/clients/index.html.j2 | 4 +- .../clients/partials/client_details.html.j2 | 91 +--------- .../clients/partials/client_events.html.j2 | 157 ++++++++++++++++++ .../secrets/partials/tree_detail.html.j2 | 4 +- .../src/sshecret_admin/frontend/views/auth.py | 4 + .../sshecret_admin/frontend/views/clients.py | 57 ++++++- .../sshecret_admin/frontend/views/secrets.py | 2 + 9 files changed, 252 insertions(+), 94 deletions(-) create mode 100644 packages/sshecret-admin/src/sshecret_admin/frontend/templates/base/bare.html.j2 create mode 100644 packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/partials/client_events.html.j2 diff --git a/packages/sshecret-admin/src/sshecret_admin/frontend/templates/base/bare.html.j2 b/packages/sshecret-admin/src/sshecret_admin/frontend/templates/base/bare.html.j2 new file mode 100644 index 0000000..ce63206 --- /dev/null +++ b/packages/sshecret-admin/src/sshecret_admin/frontend/templates/base/bare.html.j2 @@ -0,0 +1,23 @@ + + + + + {% block title %}Sshecret Admin{% endblock %} + + {% block head %} + {% include 'base/partials/stylesheets.html.j2' %} + {% endblock %} + + +
+
+ {% block content %}{% endblock %} +
+
+ {% block scripts %} + {% include 'base/partials/scripts.html.j2' %} + {% endblock %} + {% block local_scripts %} + {% endblock %} + + diff --git a/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/client.html.j2 b/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/client.html.j2 index 051235c..c7fbc7d 100644 --- a/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/client.html.j2 +++ b/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/client.html.j2 @@ -2,7 +2,9 @@ {% block title %}Client {{ client.name }}{% endblock %} {% block master %} - {% include '/clients/partials/tree.html.j2' %} +
+ {% include '/clients/partials/tree.html.j2' %} +
{% endblock %} diff --git a/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/index.html.j2 b/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/index.html.j2 index 7f2ac0e..374e222 100644 --- a/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/index.html.j2 +++ b/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/index.html.j2 @@ -2,7 +2,9 @@ {% block title %}Clients{% endblock %} {% block master %} - {% include '/clients/partials/tree.html.j2' %} +
+ {% include '/clients/partials/tree.html.j2' %} +
{% endblock %} diff --git a/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/partials/client_details.html.j2 b/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/partials/client_details.html.j2 index aa12bf7..60b5341 100644 --- a/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/partials/client_details.html.j2 +++ b/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/partials/client_details.html.j2 @@ -85,94 +85,9 @@ - - - - - - - - - - - - {% for entry in events.results | list %} - - - - - - - - - - {% endfor %} - -
TimestampSubsystemMessageOrigin
-

{{ entry.timestamp }}

- - -
- {{ entry.subsystem }} - - {{ entry.message }} - - {{ entry.origin }} -
+
+ {% include '/clients/partials/client_events.html.j2' %} +
diff --git a/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/partials/client_events.html.j2 b/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/partials/client_events.html.j2 new file mode 100644 index 0000000..497f4e8 --- /dev/null +++ b/packages/sshecret-admin/src/sshecret_admin/frontend/templates/clients/partials/client_events.html.j2 @@ -0,0 +1,157 @@ + + + + + + + + + + + + {% for entry in events.results | list %} + + + + + + + + + + {% endfor %} + +
TimestampSubsystemMessageOrigin
+

{{ entry.timestamp }}

+ + +
+ {{ entry.subsystem }} + + {{ entry.message }} + + {{ entry.origin }} +
+ + +
+
+ + Showing + {% if events_paging.total < events_paging.last %} + {{events_paging.first }}-{{ events_paging.total}} of + {% else %} + {{events_paging.first }}-{{ events_paging.last}} of + {% endif %} + {{ events_paging.total }} +
+
+
+ + + {% for n in range(events_paging.total_pages) %} + {% set p = n + 1 %} + {% if p == events_paging.page %} + + {% else %} + + {% endif %} + {% endfor %} + +
+
diff --git a/packages/sshecret-admin/src/sshecret_admin/frontend/templates/secrets/partials/tree_detail.html.j2 b/packages/sshecret-admin/src/sshecret_admin/frontend/templates/secrets/partials/tree_detail.html.j2 index f26c159..fa0dbf5 100644 --- a/packages/sshecret-admin/src/sshecret_admin/frontend/templates/secrets/partials/tree_detail.html.j2 +++ b/packages/sshecret-admin/src/sshecret_admin/frontend/templates/secrets/partials/tree_detail.html.j2 @@ -86,7 +86,7 @@
- {% if groups.groups %} + {% if flat_groups.groups %}
diff --git a/packages/sshecret-admin/src/sshecret_admin/frontend/views/auth.py b/packages/sshecret-admin/src/sshecret_admin/frontend/views/auth.py index ffcc55e..dffbfad 100644 --- a/packages/sshecret-admin/src/sshecret_admin/frontend/views/auth.py +++ b/packages/sshecret-admin/src/sshecret_admin/frontend/views/auth.py @@ -133,6 +133,10 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter: token_data: dict[str, str] = {"sub": user.username} access_token = create_access_token(dependencies.settings, data=token_data) refresh_token = create_refresh_token(dependencies.settings, data=token_data) + if next == "/refresh": + # Don't redirect from login to refresh. Send to dashboard instead. + next = "/" + response = RedirectResponse(url=next, status_code=status.HTTP_302_FOUND) response.set_cookie( "access_token", diff --git a/packages/sshecret-admin/src/sshecret_admin/frontend/views/clients.py b/packages/sshecret-admin/src/sshecret_admin/frontend/views/clients.py index fa476c4..ced2cc0 100644 --- a/packages/sshecret-admin/src/sshecret_admin/frontend/views/clients.py +++ b/packages/sshecret-admin/src/sshecret_admin/frontend/views/clients.py @@ -6,6 +6,7 @@ import logging import uuid from typing import Annotated from fastapi import APIRouter, Depends, Form, HTTPException, Query, Request, Response +from fastapi.responses import RedirectResponse from pydantic import BaseModel, IPvAnyAddress, IPvAnyNetwork from sshecret_admin.frontend.views.common import PagingInfo @@ -20,6 +21,7 @@ from ..dependencies import FrontendDependencies LOG = logging.getLogger(__name__) CLIENTS_PER_PAGE = 20 +EVENTS_PER_PAGE = 20 class ClientUpdate(BaseModel): @@ -165,7 +167,7 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter: if not results: raise HTTPException(status_code=404, detail="Client not found.") events = await admin.get_audit_log_detailed( - limit=10, client_name=results.client.name + limit=EVENTS_PER_PAGE, client_name=results.client.name ) template = "clients/client.html.j2" @@ -179,6 +181,9 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter: headers["HX-Push-Url"] = request.url.path template = "clients/partials/client_details.html.j2" + events_paging = PagingInfo( + page=1, limit=EVENTS_PER_PAGE, total=events.total, offset=0 + ) return templates.TemplateResponse( request, template, @@ -191,10 +196,45 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter: "user": current_user, "results": results.results, "events": events, + "events_paging": events_paging, }, headers=headers, ) + @app.get("/clients/client/{id}/events/{page}") + async def get_client_events( + request: Request, + admin: Annotated[AdminBackend, Depends(dependencies.get_admin_backend)], + id: str, + page: int, + ) -> Response: + """Get more events for a client.""" + if not "HX-Request" in request.headers: + return RedirectResponse(url=f"/clients/client/{id}") + + client = await admin.get_client(("id", id)) + if not client: + raise HTTPException(status_code=404, detail="Client not found.") + offset = 0 + if page > 1: + offset = (page - 1) * EVENTS_PER_PAGE + events = await admin.get_audit_log_detailed( + limit=EVENTS_PER_PAGE, client_name=client.name, offset=offset + ) + + events_paging = PagingInfo( + page=page, limit=EVENTS_PER_PAGE, total=events.total, offset=offset + ) + return templates.TemplateResponse( + request, + "clients/partials/client_events.html.j2", + { + "events": events, + "client": client, + "events_paging": events_paging, + }, + ) + @app.put("/clients/{id}") async def update_client( request: Request, @@ -228,7 +268,13 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter: final_client = await admin.update_client(updated_client) - events = await admin.get_audit_log_detailed(limit=10, client_name=client.name) + events = await admin.get_audit_log_detailed( + limit=EVENTS_PER_PAGE, client_name=client.name + ) + + events_paging = PagingInfo( + page=1, limit=EVENTS_PER_PAGE, total=events.total, offset=0 + ) return templates.TemplateResponse( request, @@ -236,6 +282,7 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter: { "client": final_client, "events": events, + "events_paging": events_paging, }, ) @@ -249,6 +296,12 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter: sources: list[str] | None = None if client.sources: sources = [source.strip() for source in client.sources.split(",")] + await admin.create_client( + name=client.name, + public_key=client.public_key, + description=client.description, + sources=sources, + ) headers = {"Hx-Refresh": "true"} return Response( diff --git a/packages/sshecret-admin/src/sshecret_admin/frontend/views/secrets.py b/packages/sshecret-admin/src/sshecret_admin/frontend/views/secrets.py index 1300ac2..e848cff 100644 --- a/packages/sshecret-admin/src/sshecret_admin/frontend/views/secrets.py +++ b/packages/sshecret-admin/src/sshecret_admin/frontend/views/secrets.py @@ -173,6 +173,7 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter: """Get secret detail.""" secret = await admin.get_secret(name) groups = await admin.get_secret_groups() + flat_groups = await admin.get_secret_groups(flat=True) events = await admin.get_audit_log_detailed(limit=10, secret_name=name) if not secret: @@ -183,6 +184,7 @@ def create_router(dependencies: FrontendDependencies) -> APIRouter: context: dict[str, Any] = { "secret": secret, "groups": groups, + "flat_groups": flat_groups, "events": events, "secret_page": True, }