diff --git a/app/web/routes.py b/app/web/routes.py index 5ab9b55..749d46d 100644 --- a/app/web/routes.py +++ b/app/web/routes.py @@ -269,6 +269,20 @@ def _held_counts(conn, account_id: int) -> tuple[int, int]: return (int(row["manual"] or 0), int(row["aged"] or 0)) +def _held_bulk_ctx(conn, account_id: int) -> dict: + """Context partajat pentru banner-ul bulk "Trimite toate (N)" + mediul RAR tinta. + + Randat in _submissions.html la FIECARE reincarcare a listei (nu doar la incarcarea Acasa), + ca sa nu ramana stale dupa eliberari (fix /code-review #3). `held_manual_count` = total + randuri tinute ale contului (independent de filtrul tabelului). + """ + manual, _aged = _held_counts(conn, account_id) + return { + "held_manual_count": manual, + "env_bulk": rar_env_efectiv_cont(conn, account_id) or "prod", + } + + def _trimiteri_versiune(conn, account_id: int) -> str: """Semnatura ieftina a starii trimiterilor contului: numar randuri + cel mai recent updated_at. Se schimba la orice insert/update/delete -> nudge-ul "Date noi" o compara @@ -1126,7 +1140,7 @@ def fragment_submissions( vehicul: str | None = None, data_de: str | None = None, data_pana: str | None = None, - held: int | None = None, + held: str | None = None, page: int = 1, ) -> HTMLResponse: """Tabel Trimiteri, scoped pe cont, cu filtre optionale si paginare. @@ -1141,7 +1155,10 @@ def fragment_submissions( vehicul_q = (vehicul or "").strip().upper() or None data_de = (data_de or "").strip() or None data_pana = (data_pana or "").strip() or None - filtru_activ = bool(status or vehicul_q or data_de or data_pana or held == 1) + # `held` vine ca query string ("1" din deep-link/form; "" cand filtrul e oprit — nu int, + # altfel un `held=` gol ar da 422 la coercion). Normalizat la bool intern. + held_activ = (held or "").strip() == "1" + filtru_activ = bool(status or vehicul_q or data_de or data_pana or held_activ) filtru_python = bool(vehicul_q or data_de or data_pana) # filtru care necesita Python page = max(1, page) # pre-clamp >= 1 @@ -1156,7 +1173,7 @@ def fragment_submissions( params.append(status) # US-007 (PRD 5.19): deep-link banner "coada tinuta" -> lista filtrata pe tinute # (queued AND held=1). Filtru derivat, fara stare noua. - if held == 1: + if held_activ: where.append("held=1") where_sql = " AND ".join(where) @@ -1231,10 +1248,15 @@ def fragment_submissions( "f_vehicul": vehicul_q or "", "f_data_de": data_de or "", "f_data_pana": data_pana or "", + # US-007 (5.19): filtrul "doar tinute" persistat prin OOB pe #f-held + paginare + # (fix /code-review #2 — altfel se pierdea la reincarcare/paginare). + "f_held": "1" if held_activ else "", # Pill-uri (OOB) + stare activa + versiune pentru nudge-ul "Date noi". "pills_categorii": _pills_categorii(_status_counts(conn, account_id)), "status_filtru": status or "", "versiune_trimiteri": _trimiteri_versiune(conn, account_id), + # US-005 (5.19): banner bulk "Trimite toate" re-randat la fiecare reincarcare. + **_held_bulk_ctx(conn, account_id), }) finally: conn.close() @@ -1270,8 +1292,11 @@ def _render_submissions(request: Request, conn, account_id: int, "csrf_token": get_csrf_token(request), "pills_categorii": _pills_categorii(_status_counts(conn, account_id)), "status_filtru": "", + "f_held": "", # lista fara filtre -> curata OOB filtrul "doar tinute" "versiune_trimiteri": _trimiteri_versiune(conn, account_id), "bulk_message": message, # US-010 (PRD 5.15): sumar bulk-fix + # US-005 (5.19): banner bulk "Trimite toate" reflecta held count curent (fix staleness). + **_held_bulk_ctx(conn, account_id), }) @@ -1377,7 +1402,11 @@ def _detaliu_ctx(request: Request, row, *, message: str | None = None, `conn`+`account_id` (optional): cand sunt date si randul e needs_mapping, expune `nemapate_inline` + `nomenclator` pentru maparea inline din panou. """ - eticheta = eticheta_stare(row["status"]) + # US-006/US-010 (PRD 5.19): un rand `queued AND held=1` e tinut manual -> eticheta de + # avertizare + afordanta de eliberare in panoul de detaliu (paritate cu rândul din listă). + tinut = (bool(row["held"]) if ("held" in row.keys() and row["held"] is not None) else False) \ + and row["status"] == "queued" + eticheta = eticheta_stare(row["status"], held=tinut) nemapate_inline: list[dict] = [] nomenclator: list[dict] = [] # Nomenclatorul complet, incarcat pentru needs_mapping si refolosit mai jos. @@ -1428,6 +1457,8 @@ def _detaliu_ctx(request: Request, row, *, message: str | None = None, "editabil": row["status"] in _CORECTABILE, # error/needs_data/needs_mapping pot fi sterse / re-puse in coada "gestionabil": row["status"] in _GESTIONABILE_WEB, + # US-006/US-010 (5.19): rand tinut manual (queued AND held=1) -> buton "Trimite acum". + "tinut": tinut, # US-010 (PRD 5.20): mediul RAR tinta — badge in detaliu. "rar_env": row["rar_env"] if "rar_env" in row.keys() else None, # mapare inline (operatii nemapate ale acestui rand + nomenclator) diff --git a/app/web/templates/_bulk_held_banner.html b/app/web/templates/_bulk_held_banner.html new file mode 100644 index 0000000..752829a --- /dev/null +++ b/app/web/templates/_bulk_held_banner.html @@ -0,0 +1,42 @@ +{# + _bulk_held_banner.html — banner bulk "Trimite toate (N)" (PRD 5.19 US-005). + + N = randuri tinute ale contului (queued AND held=1). Randat: + - initial in _coada.html (banner_oob nesetat -> fara OOB); + - RE-RANDAT prin OOB (banner_oob=true) din _submissions.html la FIECARE reincarcare a + listei, ca sa nu ramana stale dupa eliberari (fix /code-review #3). + + Wrapper cu id STABIL #bulk-held-banner-wrap: OOB outerHTML il inlocuieste mereu (chiar si + gol la N=0), ca id-ul sa ramana tinta pentru urmatorul OOB. Confirmare tipata prin modal + (count + mediu RAR), NU hx-confirm. +#} +
+ {% if held_manual_count|default(0) %} +
+ + {{ held_manual_count }} + {{ 'prezentare tinuta' if held_manual_count == 1 else 'prezentari tinute' }} manual. + + +
+ {% set cf_id = 'modal-trimite-toate' %} + {% set cf_titlu = 'Trimiti toate prezentarile tinute?' %} + {% set cf_count = held_manual_count %} + {% set cf_env = env_bulk | default('prod') %} + {% set cf_url = '/trimite-toate' %} + {% set cf_vals = '{}' %} + {% set cf_target = '#submissions-wrap' %} + {% set cf_swap = 'innerHTML' %} + {% set cf_confirm_label = 'Trimite toate (' ~ held_manual_count ~ ')' %} + {% set cf_deschis = false %} + {% include '_modal_confirma_trimitere.html' %} + {% endif %} +
diff --git a/app/web/templates/_coada.html b/app/web/templates/_coada.html index 4acc4a7..ece74ec 100644 --- a/app/web/templates/_coada.html +++ b/app/web/templates/_coada.html @@ -11,36 +11,9 @@ aria-labelledby). Badge-ul de atentie + export CSV stau intr-un rand discret. #}

Trimiterile tale

- {# US-005 (PRD 5.19): bulk "Trimite toate (N)" — N = randuri tinute (queued AND held=1). - Ascuns cand N=0. Confirmare tipata prin modal (count + mediu RAR), NU hx-confirm. #} - {% if held_manual_count|default(0) %} -
- - {{ held_manual_count }} - {{ 'prezentare tinuta' if held_manual_count == 1 else 'prezentari tinute' }} manual. - - -
- {% set cf_id = 'modal-trimite-toate' %} - {% set cf_titlu = 'Trimiti toate prezentarile tinute?' %} - {% set cf_count = held_manual_count %} - {% set cf_env = env_bulk | default('prod') %} - {% set cf_url = '/trimite-toate' %} - {% set cf_vals = '{}' %} - {% set cf_target = '#submissions-wrap' %} - {% set cf_swap = 'innerHTML' %} - {% set cf_confirm_label = 'Trimite toate (' ~ held_manual_count ~ ')' %} - {% set cf_deschis = false %} - {% include '_modal_confirma_trimitere.html' %} - {% endif %} + {# US-005 (PRD 5.19): bulk "Trimite toate (N)". Randat initial aici; re-randat prin OOB + din _submissions.html la fiecare reincarcare a listei (fix staleness /code-review #3). #} + {% include '_bulk_held_banner.html' %} {% if blocate_total %}
@@ -71,6 +44,9 @@ {# Pagina curenta — actualizata prin OOB swap din _submissions.html; inclusa la reincarcari. #} + {# US-007 (5.19): filtrul "doar tinute" — persistat prin OOB din _submissions.html, ca sa + nu se piarda la reincarcare (trimiteriChanged) sau paginare (fix /code-review #2). #} + {# === STANGA: Quick-pills de data (preset interval) + buton Custom === Azi / 7 zile / 30 zile → seteaza interval preset si submitr automat. diff --git a/app/web/templates/_submissions.html b/app/web/templates/_submissions.html index 4f4f85c..a46336f 100644 --- a/app/web/templates/_submissions.html +++ b/app/web/templates/_submissions.html @@ -5,6 +5,13 @@ #} +{# OOB: sincronizeaza filtrul "doar tinute" (#f-held) cu starea randata acum, ca reincarcarile + (trimiteriChanged / paginare) sa-l pastreze in loc sa revina la lista completa (/code-review #2). #} + + +{# OOB: banner bulk "Trimite toate (N)" re-randat la fiecare reincarcare a listei (fix staleness). #} +{% with banner_oob = true %}{% include '_bulk_held_banner.html' %}{% endwith %} + {# OOB: re-randeaza pill-urile de stare (in bara de filtre, in afara #submissions-wrap) cu contoarele si starea activa proaspete la fiecare reincarcare a tabelului. #} {% include '_pills.html' %} @@ -22,6 +29,23 @@
{% endif %} +{# US-007 (5.19): chip filtru activ "doar tinute" cu buton de golire (fix /code-review #2 — + filtrul held e sticky prin OOB, deci ii dam un off-switch explicit). #} +{% if f_held %} +
+ + Doar tinute manual + + +
+{% endif %} + {% if rows %} {# Form bulk cu DOUA actiuni: (1) aplica cod RAR la selectate (bulk-fix, US-010), (2) sterge selectate (sterge-bulk). Selectia opereaza DOAR pe randuri blocate @@ -196,6 +220,7 @@ {% if f_vehicul %}{% set pq = pq + "&vehicul=" + f_vehicul %}{% endif %} {% if f_data_de %}{% set pq = pq + "&data_de=" + f_data_de %}{% endif %} {% if f_data_pana %}{% set pq = pq + "&data_pana=" + f_data_pana %}{% endif %} +{% if f_held %}{% set pq = pq + "&held=" + f_held %}{% endif %}