From 2287f4597d47e4383ab1a0fe482c5d8eb22008de Mon Sep 17 00:00:00 2001 From: Samir Boulahtit Date: Sat, 7 Mar 2026 06:18:26 +0100 Subject: [PATCH] feat(hosting,prospecting): add hosting unit tests and fix template bugs - Add 55 unit tests for hosting module (hosted site service, client service service, stats service) with full fixture setup - Fix table_empty_state macro: add x_message param for dynamic Alpine.js expressions rendered via x-text instead of server-side Jinja - Fix hosting templates (sites, clients) using message= with Alpine expressions that rendered as literal text - Fix prospecting templates (leads, scan-jobs, prospects) using nonexistent subtitle= param, migrated to x_message= - Align hosting and prospecting admin templates with shared design system Co-Authored-By: Claude Opus 4.6 --- app/modules/hosting/routes/api/admin.py | 2 +- .../templates/hosting/admin/clients.html | 206 +++++----- .../templates/hosting/admin/dashboard.html | 69 ++-- .../templates/hosting/admin/site-detail.html | 374 ++++++++--------- .../templates/hosting/admin/site-new.html | 88 ++-- .../templates/hosting/admin/sites.html | 204 ++++++---- app/modules/hosting/tests/__init__.py | 0 app/modules/hosting/tests/conftest.py | 186 +++++++++ app/modules/hosting/tests/unit/__init__.py | 0 .../tests/unit/test_client_service_service.py | 219 ++++++++++ .../tests/unit/test_hosted_site_service.py | 325 +++++++++++++++ .../hosting/tests/unit/test_stats_service.py | 66 +++ .../prospecting/admin/campaigns.html | 209 +++++----- .../templates/prospecting/admin/capture.html | 131 +++--- .../prospecting/admin/dashboard.html | 70 ++-- .../templates/prospecting/admin/leads.html | 184 +++++---- .../prospecting/admin/prospect-detail.html | 276 ++++++------- .../prospecting/admin/prospects.html | 380 +++++++++--------- .../prospecting/admin/scan-jobs.html | 134 +++--- app/templates/shared/macros/tables.html | 7 +- pyproject.toml | 2 + 21 files changed, 2014 insertions(+), 1118 deletions(-) create mode 100644 app/modules/hosting/tests/__init__.py create mode 100644 app/modules/hosting/tests/conftest.py create mode 100644 app/modules/hosting/tests/unit/__init__.py create mode 100644 app/modules/hosting/tests/unit/test_client_service_service.py create mode 100644 app/modules/hosting/tests/unit/test_hosted_site_service.py create mode 100644 app/modules/hosting/tests/unit/test_stats_service.py diff --git a/app/modules/hosting/routes/api/admin.py b/app/modules/hosting/routes/api/admin.py index 07d93fa9..6367145d 100644 --- a/app/modules/hosting/routes/api/admin.py +++ b/app/modules/hosting/routes/api/admin.py @@ -14,7 +14,7 @@ from .admin_services import router as admin_services_router from .admin_sites import router as admin_sites_router from .admin_stats import router as admin_stats_router -router = APIRouter() +router = APIRouter(prefix="/hosting") router.include_router(admin_sites_router, tags=["hosting-sites"]) router.include_router(admin_services_router, tags=["hosting-services"]) diff --git a/app/modules/hosting/templates/hosting/admin/clients.html b/app/modules/hosting/templates/hosting/admin/clients.html index beb8232e..7bb87d7c 100644 --- a/app/modules/hosting/templates/hosting/admin/clients.html +++ b/app/modules/hosting/templates/hosting/admin/clients.html @@ -1,7 +1,8 @@ {% extends "admin/base.html" %} {% from 'shared/macros/headers.html' import page_header %} {% from 'shared/macros/alerts.html' import loading_state, error_state %} -{% from 'shared/macros/pagination.html' import pagination_controls %} +{% from 'shared/macros/tables.html' import table_wrapper, table_header, table_empty_state %} +{% from 'shared/macros/pagination.html' import pagination %} {% block title %}Client Services{% endblock %} @@ -11,37 +12,35 @@ {{ page_header('Client Services') }} -
-
-
- - + -
-
- - + -
-
-
@@ -52,95 +51,87 @@ {{ error_state('Error loading services') }} -
-
- - - - - - - - - +
+ {% call table_wrapper() %} + {{ table_header(['Service', 'Type', 'Status', 'Price', 'Expires', 'Site']) }} +
+ {{ table_empty_state(6, title='No services found', x_message="filterType || filterStatus || showExpiringOnly ? 'Try adjusting your filters' : 'No client services yet'", show_condition='services.length === 0', icon='cube') }} + + + {% endcall %} -{{ pagination_controls() }} + {{ pagination() }} + {% endblock %} {% block extra_scripts %} diff --git a/app/modules/hosting/templates/hosting/admin/dashboard.html b/app/modules/hosting/templates/hosting/admin/dashboard.html index e9c82211..c9fd3ab3 100644 --- a/app/modules/hosting/templates/hosting/admin/dashboard.html +++ b/app/modules/hosting/templates/hosting/admin/dashboard.html @@ -1,5 +1,5 @@ {% extends "admin/base.html" %} -{% from 'shared/macros/headers.html' import page_header %} +{% from 'shared/macros/headers.html' import page_header, section_header %} {% from 'shared/macros/alerts.html' import loading_state, error_state %} {% block title %}Hosting Dashboard{% endblock %} @@ -14,7 +14,7 @@
-
+
@@ -23,7 +23,7 @@

-
+
@@ -32,7 +32,7 @@

-
+
@@ -41,7 +41,7 @@

-
+
@@ -53,41 +53,44 @@
-
- - - New Site - - - - All Sites - - - - All Services - +
+ {{ section_header('Quick Actions', icon='cursor-click') }} +
- +
-
-

Sites by Status

+
+ {{ section_header('Sites by Status', icon='globe') }}
-
-

Active Services

+
+ {{ section_header('Active Services', icon='cube') }}
Total Active @@ -100,7 +103,7 @@
-
+
Monthly Revenue function hostingDashboard() { return { + ...data(), + currentPage: 'hosting-dashboard', loading: true, - error: false, + error: null, stats: {}, async init() { try { - const resp = await fetch('/api/admin/hosting/stats/dashboard'); - if (!resp.ok) throw new Error('Failed to load'); - this.stats = await resp.json(); + this.stats = await apiClient.get('/admin/hosting/stats/dashboard'); } catch (e) { - this.error = true; + this.error = e.message; } finally { this.loading = false; } diff --git a/app/modules/hosting/templates/hosting/admin/site-detail.html b/app/modules/hosting/templates/hosting/admin/site-detail.html index c2fffbda..9b65ecd3 100644 --- a/app/modules/hosting/templates/hosting/admin/site-detail.html +++ b/app/modules/hosting/templates/hosting/admin/site-detail.html @@ -1,6 +1,7 @@ {% extends "admin/base.html" %} -{% from 'shared/macros/headers.html' import page_header %} +{% from 'shared/macros/headers.html' import section_header, tab_header %} {% from 'shared/macros/alerts.html' import loading_state, error_state %} +{% from 'shared/macros/modals.html' import modal %} {% from 'shared/macros/inputs.html' import number_stepper %} {% block title %}Site Detail{% endblock %} @@ -13,122 +14,124 @@
-
+ -
- - - - - - - - + class="sm:ml-auto inline-flex items-center px-3 py-2 text-sm font-medium leading-5 text-teal-700 dark:text-teal-300 transition-colors duration-150 bg-teal-100 dark:bg-teal-900 border border-transparent rounded-lg hover:bg-teal-200 dark:hover:bg-teal-800 focus:outline-none"> + Preview POC
-
- -
+ {{ tab_header([ + {'id': 'overview', 'label': 'Overview', 'icon': 'eye'}, + {'id': 'services', 'label': 'Services', 'icon': 'cube'}, + {'id': 'store', 'label': 'Store', 'icon': 'shopping-bag'}, + ], active_var='activeTab') }}
-
-

Contact Info

+
+ {{ section_header('Contact Info', icon='phone') }}
Name - +
Email - +
Phone - +
-
-

Timeline

+
+ {{ section_header('Timeline', icon='clock') }}
Created - +
Proposal Sent - +
Accepted - +
Went Live - +
-
-

Notes

+
+ {{ section_header('Notes', icon='document-text') }}
-

Proposal Notes

+

Proposal Notes

-

Internal Notes

+

Internal Notes

@@ -137,25 +140,25 @@
-
ServiceTypeStatusPriceExpiresSite