From ae630f9115eece17be08a2e5c6a889b72a14e6ac Mon Sep 17 00:00:00 2001 From: Ruslan Date: Fri, 2 Oct 2026 06:51:18 +0000 Subject: [PATCH] Pilots: separate admin tab, collapsible dashboard section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Admin: moved pilot management out of the RDP tab into its own "Pilots" tab - dedicated list, create/edit form and slot table with a per-slot user-assign dropdown (always on, no more is_pilot checkbox toggling the RDP tab's slot table between two modes). The RDP tab goes back to exactly its pre-pilots shape. Dashboard: a granted pilot no longer sits inside the "Ваши сервисы" grid - it gets its own
section above it, open by default whenever the user has at least one pilot (and simply absent when they have none, rather than showing empty and collapsed). Co-Authored-By: Claude Sonnet 5 --- app/main.py | 14 +- app/templates/admin.html | 274 ++++++++++++++++++++++++++++++----- app/templates/dashboard.html | 38 ++++- 3 files changed, 282 insertions(+), 44 deletions(-) diff --git a/app/main.py b/app/main.py index 43565a2..e06c556 100644 --- a/app/main.py +++ b/app/main.py @@ -1047,7 +1047,10 @@ def index(request: Request, user: Optional[User] = Depends(get_current_user), db ) ).all() ) - services = [svc for svc in all_services if svc.id in granted_ids] + # Pilots the user has access to get their own collapsible section above + # the regular catalog instead of sitting in the "Ваши сервисы" grid. + pilot_services = [svc for svc in all_services if svc.id in granted_ids and svc.is_pilot] + services = [svc for svc in all_services if svc.id in granted_ids and not svc.is_pilot] locked_services = [svc for svc in all_services if svc.id not in granted_ids] pilot_ids = {svc.id for svc in all_services if svc.is_pilot} @@ -1107,6 +1110,7 @@ def index(request: Request, user: Optional[User] = Depends(get_current_user), db "user": user, "services": services, "locked_services": locked_services, + "pilot_services": pilot_services, "pilot_ids": pilot_ids, "categories": categories, "category_counts": category_counts, @@ -1148,8 +1152,9 @@ def admin_page(request: Request, admin: User = Depends(require_admin), db: Sessi categories = db.scalars(select(Category).order_by(Category.name)).all() services = db.scalars(select(Service).where(Service.type.in_([ServiceType.WEB, ServiceType.RDP])).order_by(Service.id)).all() web_services = [s for s in services if s.type == ServiceType.WEB] - rdp_services = [s for s in services if s.type == ServiceType.RDP] - pilot_service_ids = {s.id for s in services if s.is_pilot} + rdp_services = [s for s in services if s.type == ServiceType.RDP and not s.is_pilot] + pilot_services = [s for s in services if s.is_pilot] + pilot_service_ids = {s.id for s in pilot_services} service_category_map = {s.id: [] for s in services} if services: service_rows = db.execute( @@ -1231,7 +1236,7 @@ def admin_page(request: Request, admin: User = Depends(require_admin), db: Sessi {"cutoff": cutoff}, ).mappings().all() rdp_slots: dict[int, list] = {} - for svc in rdp_services: + for svc in rdp_services + pilot_services: slots = db.scalars(select(RdpSlot).where(RdpSlot.service_id == svc.id).order_by(RdpSlot.id)).all() slot_list = [] for slot in slots: @@ -1278,6 +1283,7 @@ def admin_page(request: Request, admin: User = Depends(require_admin), db: Sessi ], "web_services": web_services, "rdp_services": rdp_services, + "pilot_services": pilot_services, "pilot_service_ids": pilot_service_ids, "services": services, "categories": categories, diff --git a/app/templates/admin.html b/app/templates/admin.html index 447f778..5a68c44 100644 --- a/app/templates/admin.html +++ b/app/templates/admin.html @@ -221,6 +221,7 @@ + @@ -477,10 +478,10 @@
{% for s in rdp_services %} - + {% endfor %} +
+ +
+
Редактирование пилота
+
Используйте поля host/port/user. Поле target собирается автоматически.
+
+ + + + + + + + + + + + + +
+
Категории
+
+ {% for c in categories %} + + {% endfor %} +
+
+ + + +
+ +
+
Иконка пилота
+
+ icon +
+ +
+ + +
+
+
+
+ + + +
+
Добавить пилота
+
Для большинства кейсов достаточно host + user + password.
+
+ + + + + + + + + + + + +
+
Категории
+
+ {% for c in categories %} + + {% endfor %} +
+ +
+ + +