diff --git a/web/src/padelnomics/admin/routes.py b/web/src/padelnomics/admin/routes.py index 436ed8e..a819294 100644 --- a/web/src/padelnomics/admin/routes.py +++ b/web/src/padelnomics/admin/routes.py @@ -263,6 +263,23 @@ async def users(): ) +@bp.route("/users/results") +@role_required("admin") +async def user_results(): + """HTMX partial for user list (live search).""" + search = request.args.get("search", "").strip() + page = int(request.args.get("page", 1)) + per_page = 50 + offset = (page - 1) * per_page + user_list = await get_users(limit=per_page, offset=offset, search=search or None) + return await render_template( + "admin/partials/user_results.html", + users=user_list, + search=search, + page=page, + ) + + @bp.route("/users/") @role_required("admin") async def user_detail(user_id: int): diff --git a/web/src/padelnomics/admin/templates/admin/articles.html b/web/src/padelnomics/admin/templates/admin/articles.html index 19d9d3f..8bfbe89 100644 --- a/web/src/padelnomics/admin/templates/admin/articles.html +++ b/web/src/padelnomics/admin/templates/admin/articles.html @@ -28,7 +28,8 @@
+ hx-trigger="change, input delay:300ms from:find input" + hx-indicator="#articles-loading">
@@ -65,6 +66,11 @@
+ +
diff --git a/web/src/padelnomics/admin/templates/admin/emails.html b/web/src/padelnomics/admin/templates/admin/emails.html index 8a40294..1a3ace9 100644 --- a/web/src/padelnomics/admin/templates/admin/emails.html +++ b/web/src/padelnomics/admin/templates/admin/emails.html @@ -24,7 +24,8 @@
+ hx-trigger="change, input delay:300ms from:find input" + hx-indicator="#emails-loading">
@@ -51,6 +52,11 @@
+ +
diff --git a/web/src/padelnomics/admin/templates/admin/leads.html b/web/src/padelnomics/admin/templates/admin/leads.html index 2c958ab..8f2ae57 100644 --- a/web/src/padelnomics/admin/templates/admin/leads.html +++ b/web/src/padelnomics/admin/templates/admin/leads.html @@ -25,7 +25,8 @@
+ hx-trigger="change, input delay:300ms from:find input" + hx-indicator="#leads-loading">
@@ -57,6 +58,11 @@ {% endfor %}
+ +
diff --git a/web/src/padelnomics/admin/templates/admin/partials/scenario_results.html b/web/src/padelnomics/admin/templates/admin/partials/scenario_results.html index ac9860d..d742914 100644 --- a/web/src/padelnomics/admin/templates/admin/partials/scenario_results.html +++ b/web/src/padelnomics/admin/templates/admin/partials/scenario_results.html @@ -1,9 +1,15 @@ {% if is_generating %} - + hx-swap="innerHTML"> + + + + + Generating scenarios… + {% endif %} {% if scenarios %} diff --git a/web/src/padelnomics/admin/templates/admin/partials/user_results.html b/web/src/padelnomics/admin/templates/admin/partials/user_results.html new file mode 100644 index 0000000..0f895ab --- /dev/null +++ b/web/src/padelnomics/admin/templates/admin/partials/user_results.html @@ -0,0 +1,60 @@ +
+ {% if users %} +
+
+ + + + + + + + + + + + + {% for u in users %} + + + + + + + + + + {% endfor %} + +
IDEmailNamePlanJoinedLast Login
{{ u.id }}{{ u.email }}{{ u.name or '-' }} + {% if u.plan %} + {{ u.plan }} + {% else %} + free + {% endif %} + {{ u.created_at[:10] }}{{ u.last_login_at[:10] if u.last_login_at else 'Never' }} +
+ + +
+
+ +
+ {% if page > 1 %} + + {% endif %} + Page {{ page }} + {% if users | length == 50 %} + + {% endif %} +
+ {% else %} +

No users found.

+ {% endif %} + diff --git a/web/src/padelnomics/admin/templates/admin/scenarios.html b/web/src/padelnomics/admin/templates/admin/scenarios.html index 3cfa407..a117a1e 100644 --- a/web/src/padelnomics/admin/templates/admin/scenarios.html +++ b/web/src/padelnomics/admin/templates/admin/scenarios.html @@ -17,13 +17,19 @@ -
+ +
+
+
-
- - {% if current_search or current_country or current_venue_type %} - Clear - {% endif %} + +
+ +
diff --git a/web/src/padelnomics/admin/templates/admin/suppliers.html b/web/src/padelnomics/admin/templates/admin/suppliers.html index 11905bf..2a69bba 100644 --- a/web/src/padelnomics/admin/templates/admin/suppliers.html +++ b/web/src/padelnomics/admin/templates/admin/suppliers.html @@ -24,7 +24,8 @@
+ hx-trigger="change, input delay:300ms from:find input" + hx-indicator="#suppliers-loading">
@@ -52,6 +53,11 @@ {% endfor %}
+ +
diff --git a/web/src/padelnomics/admin/templates/admin/users.html b/web/src/padelnomics/admin/templates/admin/users.html index f7d661d..58bfba9 100644 --- a/web/src/padelnomics/admin/templates/admin/users.html +++ b/web/src/padelnomics/admin/templates/admin/users.html @@ -9,69 +9,24 @@ ← Dashboard - -
-
- - -
-
+
+
+
+ +
+ +
+
- -
- {% if users %} -
- - - - - - - - - - - - - - {% for u in users %} - - - - - - - - - - {% endfor %} - -
IDEmailNamePlanJoinedLast Login
{{ u.id }}{{ u.email }}{{ u.name or '-' }} - {% if u.plan %} - {{ u.plan }} - {% else %} - free - {% endif %} - {{ u.created_at[:10] }}{{ u.last_login_at[:10] if u.last_login_at else 'Never' }} -
- - -
-
-
- - -
- {% if page > 1 %} - ← Previous - {% endif %} - Page {{ page }} - {% if users | length == 50 %} - Next → - {% endif %} -
- {% else %} -

No users found.

- {% endif %} +
+ {% include "admin/partials/user_results.html" %}
{% endblock %} diff --git a/web/src/padelnomics/static/css/input.css b/web/src/padelnomics/static/css/input.css index 1acff6b..2fa47d3 100644 --- a/web/src/padelnomics/static/css/input.css +++ b/web/src/padelnomics/static/css/input.css @@ -569,6 +569,17 @@ @apply px-4 pb-4 text-slate-dark; } + /* Inline HTMX loading indicator for search forms */ + .search-spinner { + opacity: 0; + flex-shrink: 0; + align-self: center; + } + .search-spinner.htmx-request { + opacity: 1; + animation: spin-icon 0.9s linear infinite; + } + /* Article generation spinner banner */ .generating-banner { @apply flex items-center gap-3 rounded-xl border border-light-gray bg-white text-sm text-slate-dark mb-4;