diff --git a/CHANGELOG.md b/CHANGELOG.md index cf9a303..e32ba18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - **Proxy URL scheme validation in `load_proxy_tiers()`** — URLs in `PROXY_URLS_DATACENTER` / `PROXY_URLS_RESIDENTIAL` that are missing an `http://` or `https://` scheme are now logged as a warning and skipped, rather than being passed through and causing SSL handshake failures or connection errors at request time. Also fixed a missing `http://` prefix in the dev `.env` `PROXY_URLS_DATACENTER` entry. ### Changed +- **Unified confirm dialog — pure HTMX `hx-confirm` + `
`** — eliminated the `confirmAction()` JS function and the duplicate `cloneNode` hack. All confirmation prompts now go through a single `showConfirm()` Promise-based function called by the `htmx:confirm` interceptor. The dialog HTML uses `` for native close semantics (`returnValue` is `"ok"` or `"cancel"`), removing the need to clone and replace buttons on every invocation. All 12 Padelnomics call sites converted from `onclick=confirmAction(...)` to `hx-boost="true"` + `hx-confirm="..."` on the submit button. Pipeline trigger endpoints updated to treat `HX-Boosted: true` requests as non-HTMX (returning a redirect rather than an inline partial) so boosted form submissions flow through the normal redirect cycle. Same changes applied to BeanFlows and the quart-saas-boilerplate template. + - `web/src/padelnomics/admin/templates/admin/base_admin.html`: replaced dialog `
` with ``, replaced `confirmAction()` + inline `htmx:confirm` handler with unified `showConfirm()` + single `htmx:confirm` listener + - `web/src/padelnomics/admin/pipeline_routes.py`: `pipeline_trigger_extract` and `pipeline_trigger_transform` now exclude `HX-Boosted: true` from the HTMX partial path + - 12 templates updated: `pipeline.html`, `partials/pipeline_extractions.html`, `affiliate_form.html`, `affiliate_program_form.html`, `partials/affiliate_program_results.html`, `partials/affiliate_row.html`, `generate_form.html`, `articles.html`, `audience_contacts.html`, `template_detail.html`, `partials/scenario_results.html` + - Same changes mirrored to BeanFlows and quart-saas-boilerplate template + - **Per-proxy dead tracking in tiered cycler** — `make_tiered_cycler` now accepts a `proxy_failure_limit` parameter (default 3). Individual proxies that hit the limit are marked dead and permanently skipped by `next_proxy()`. If all proxies in the active tier are dead, `next_proxy()` auto-escalates to the next tier without needing the tier-level threshold. `record_failure(proxy_url)` and `record_success(proxy_url)` accept an optional `proxy_url` argument for per-proxy tracking; callers without `proxy_url` are fully backward-compatible. New `dead_proxy_count()` callable exposed for monitoring. - `extract/padelnomics_extract/src/padelnomics_extract/proxy.py`: added per-proxy state (`proxy_failure_counts`, `dead_proxies`), updated `next_proxy`/`record_failure`/`record_success`, added `dead_proxy_count` - `extract/padelnomics_extract/src/padelnomics_extract/playtomic_tenants.py`: `_fetch_page_via_cycler` passes `proxy_url` to `record_success`/`record_failure` diff --git a/web/src/padelnomics/admin/pipeline_routes.py b/web/src/padelnomics/admin/pipeline_routes.py index 3bc926f..623b649 100644 --- a/web/src/padelnomics/admin/pipeline_routes.py +++ b/web/src/padelnomics/admin/pipeline_routes.py @@ -780,7 +780,8 @@ async def pipeline_trigger_extract(): else: await enqueue("run_extraction") - is_htmx = request.headers.get("HX-Request") == "true" + is_htmx = (request.headers.get("HX-Request") == "true" + and request.headers.get("HX-Boosted") != "true") if is_htmx: return await _render_overview_partial() @@ -1005,7 +1006,8 @@ async def pipeline_trigger_transform(): (task_name,), ) if existing: - is_htmx = request.headers.get("HX-Request") == "true" + is_htmx = (request.headers.get("HX-Request") == "true" + and request.headers.get("HX-Boosted") != "true") if is_htmx: return await _render_transform_partial() await flash(f"A '{step}' task is already queued (task #{existing['id']}).", "warning") @@ -1013,7 +1015,8 @@ async def pipeline_trigger_transform(): await enqueue(task_name) - is_htmx = request.headers.get("HX-Request") == "true" + is_htmx = (request.headers.get("HX-Request") == "true" + and request.headers.get("HX-Boosted") != "true") if is_htmx: return await _render_transform_partial() diff --git a/web/src/padelnomics/admin/templates/admin/affiliate_form.html b/web/src/padelnomics/admin/templates/admin/affiliate_form.html index 5ea6366..95e26b2 100644 --- a/web/src/padelnomics/admin/templates/admin/affiliate_form.html +++ b/web/src/padelnomics/admin/templates/admin/affiliate_form.html @@ -226,10 +226,9 @@ document.addEventListener('DOMContentLoaded', function() { Cancel
{% if editing %} - +
{% endif %} diff --git a/web/src/padelnomics/admin/templates/admin/affiliate_program_form.html b/web/src/padelnomics/admin/templates/admin/affiliate_program_form.html index 70c62a9..524d47f 100644 --- a/web/src/padelnomics/admin/templates/admin/affiliate_program_form.html +++ b/web/src/padelnomics/admin/templates/admin/affiliate_program_form.html @@ -120,10 +120,9 @@ document.addEventListener('DOMContentLoaded', function() { Cancel {% if editing %} -
+
{% endif %} diff --git a/web/src/padelnomics/admin/templates/admin/articles.html b/web/src/padelnomics/admin/templates/admin/articles.html index c8133d4..80acc2a 100644 --- a/web/src/padelnomics/admin/templates/admin/articles.html +++ b/web/src/padelnomics/admin/templates/admin/articles.html @@ -11,9 +11,10 @@
New Article -
+ - +
diff --git a/web/src/padelnomics/admin/templates/admin/audience_contacts.html b/web/src/padelnomics/admin/templates/admin/audience_contacts.html index b48de55..e3e2187 100644 --- a/web/src/padelnomics/admin/templates/admin/audience_contacts.html +++ b/web/src/padelnomics/admin/templates/admin/audience_contacts.html @@ -27,10 +27,11 @@ {{ c.email if c.email is defined else (c.get('email', '-') if c is mapping else '-') }} {{ (c.created_at if c.created_at is defined else (c.get('created_at', '-') if c is mapping else '-'))[:16] if c else '-' }} -
+ - +
diff --git a/web/src/padelnomics/admin/templates/admin/base_admin.html b/web/src/padelnomics/admin/templates/admin/base_admin.html index 9cc68ef..6f8c0aa 100644 --- a/web/src/padelnomics/admin/templates/admin/base_admin.html +++ b/web/src/padelnomics/admin/templates/admin/base_admin.html @@ -228,36 +228,29 @@

-
- - -
+
+ + +
{% endblock %} diff --git a/web/src/padelnomics/admin/templates/admin/generate_form.html b/web/src/padelnomics/admin/templates/admin/generate_form.html index 1b7c137..33e3298 100644 --- a/web/src/padelnomics/admin/templates/admin/generate_form.html +++ b/web/src/padelnomics/admin/templates/admin/generate_form.html @@ -19,7 +19,7 @@

No data rows found. Run the data pipeline to populate {{ config_data.data_table }}.

{% else %} -
+
@@ -45,7 +45,8 @@

-
diff --git a/web/src/padelnomics/admin/templates/admin/partials/affiliate_program_results.html b/web/src/padelnomics/admin/templates/admin/partials/affiliate_program_results.html index 71f7b41..66c3a1d 100644 --- a/web/src/padelnomics/admin/templates/admin/partials/affiliate_program_results.html +++ b/web/src/padelnomics/admin/templates/admin/partials/affiliate_program_results.html @@ -21,10 +21,9 @@ Edit -
+
diff --git a/web/src/padelnomics/admin/templates/admin/partials/affiliate_row.html b/web/src/padelnomics/admin/templates/admin/partials/affiliate_row.html index 3d62461..7663208 100644 --- a/web/src/padelnomics/admin/templates/admin/partials/affiliate_row.html +++ b/web/src/padelnomics/admin/templates/admin/partials/affiliate_row.html @@ -20,10 +20,9 @@ {{ product.click_count or 0 }} Edit -
+
diff --git a/web/src/padelnomics/admin/templates/admin/partials/pipeline_extractions.html b/web/src/padelnomics/admin/templates/admin/partials/pipeline_extractions.html index de54678..40a6691 100644 --- a/web/src/padelnomics/admin/templates/admin/partials/pipeline_extractions.html +++ b/web/src/padelnomics/admin/templates/admin/partials/pipeline_extractions.html @@ -29,10 +29,10 @@ -
+ -
@@ -112,11 +112,11 @@ {% if run.status == 'running' %}
+ class="m-0" hx-boost="true"> -
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 d742914..3ba3047 100644 --- a/web/src/padelnomics/admin/templates/admin/partials/scenario_results.html +++ b/web/src/padelnomics/admin/templates/admin/partials/scenario_results.html @@ -36,9 +36,10 @@ PDF EN PDF DE Edit -
+ - +
diff --git a/web/src/padelnomics/admin/templates/admin/pipeline.html b/web/src/padelnomics/admin/templates/admin/pipeline.html index 511b11b..96ea282 100644 --- a/web/src/padelnomics/admin/templates/admin/pipeline.html +++ b/web/src/padelnomics/admin/templates/admin/pipeline.html @@ -57,11 +57,11 @@

Extraction status, data catalog, and ad-hoc query editor

-
+ -
diff --git a/web/src/padelnomics/admin/templates/admin/template_detail.html b/web/src/padelnomics/admin/templates/admin/template_detail.html index d0ca524..5395c02 100644 --- a/web/src/padelnomics/admin/templates/admin/template_detail.html +++ b/web/src/padelnomics/admin/templates/admin/template_detail.html @@ -13,9 +13,10 @@
Generate Articles -
+ -