fix(5.11): tabel trimiteri stabil — bug status=None, pills in bara de filtre, nudge "Date noi" in loc de poll 15s, logo ROMFAST marit

- Fix bug: campul hidden de filtru randa literal "None" (status_filtru None +
  Jinja default('')) -> poll-ul trimitea status=None -> tabel gol. status or "".
- Pills de stare mutate din bara de status in bara de filtre (filtreazaStare scrie
  campul hidden + re-trimite form-ul; filtrul persista la reincarcari). Re-randate
  OOB cu contoare proaspete la fiecare reincarcare a tabelului.
- Polling redesign: tabelul nu se mai reincarca singur (fara every 15s). Poller usor
  JSON (/_fragments/trimiteri-versiune) detecteaza schimbari -> nudge "Date noi —
  Reincarca". Reincarcarea (nudge / actiune) pastreaza filtrul+pagina. Scroll/selectia
  nu se mai pierd. Poll-guard eliminat (nu mai exista poll periodic de pauzat).
- Logo ROMFAST 32px -> 60px (ca pe romfast.ro), header min-height 92px, 44px pe mobil.

Regresie: 896 passed, 1 deselected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-06-25 21:13:42 +00:00
parent 074b6e7c8a
commit f05fe5b221
10 changed files with 224 additions and 199 deletions

View File

@@ -128,10 +128,19 @@ def test_badge_trimiteri_scoped_pe_acasa(client):
assert "2" in html[idx:idx + 400]
def test_trimiteri_poll_aliniat_15s(client):
"""Poll-ul de trimiteri e aliniat la 15s (anti dublu-poll M5), nu 10s."""
def test_trimiteri_fara_poll_periodic_pe_tabel(client):
"""Tabelul de trimiteri NU se mai reimprospateaza periodic: #submissions-wrap se
incarca la load / actiunile utilizatorului / Reincarca (nudge), fara `every Ns`.
Reimprospatarea live se face prin nudge-ul "Date noi" + endpointul de versiune."""
_seed_submission("sent")
r = client.get("/?tab=acasa")
html = r.text
assert "every 15s" in html
assert "every 10s" not in html
# Trigger-ul tabelului nu contine poll periodic.
wrap = html[html.find('id="submissions-wrap"'):]
wrap = wrap[:wrap.find(">") + 1]
assert "every" not in wrap, f"tabelul nu trebuie sa aiba poll periodic: {wrap}"
assert "reincarcaTrimiteri" in wrap
assert "trimiteriChanged" in wrap
# Mecanismul de nudge exista (banner + endpoint versiune).
assert 'id="nudge-trimiteri"' in html
assert "/_fragments/trimiteri-versiune" in html

View File

@@ -161,58 +161,48 @@ def test_modal_hookuri_js_prezente(client):
assert "window.inchideDetaliu" in js
# --- PRD 5.9 US-005 (R6): poll-guard ---------------------------------------
# Modalul + selectia trebuie sa supravietuiasca poll-ului de 15s. Logica e JS in
# base.html: testam la nivel de markup/handler ca guard-ul exista si distinge corect
# sursa trigger-ului (periodic vs trimiteriChanged/filtru). Comportamentul runtime
# efectiv (anularea propriu-zisa) e validat E2E (requiresBrowserCheck) — aici asertam
# codul/atributele care il implementeaza.
# --- Tabelul nu se reincarca singur: modalul + selectia sunt sigure ---------
# Tabelul (#submissions-wrap) nu mai are poll periodic; se reincarca DOAR la load,
# la actiunile utilizatorului (trimiteriChanged) sau la apasarea pe Reincarca (nudge).
# Asa, modalul deschis si bifele de bulk nu pot fi sterse de un timer.
def test_poll_pauzat_cat_modal_deschis(client):
"""Guard-ul de poll exista si, cat modalul de detaliu e deschis, anuleaza
reincarcarea periodica a listei (#submissions-wrap), nu pe restul."""
_create_account_user("poll1@test.com")
def test_tabel_fara_poll_periodic(client):
"""#submissions-wrap nu are trigger periodic (`every Ns`) — niciun timer nu poate
reseta modalul deschis sau selectia de bulk in timpul interactiunii."""
acct = _create_account_user("poll1@test.com")
_login(client, "poll1@test.com")
js = client.get("/?tab=acasa").text
_insert_submission(acct)
html = client.get("/?tab=acasa").text
# Guard scopat la poll-ul listei, declansat pe htmx:beforeRequest.
assert "htmx:beforeRequest" in js
assert "d.elt.id !== 'submissions-wrap'" in js, "guard-ul trebuie scopat la #submissions-wrap"
# Conditia (a): modal deschis -> pauza (preventDefault).
assert "modalDeschis" in js
assert "modal-detaliu" in js and "hidden" in js
assert "evt.preventDefault()" in js, "pauza scopata se face prin preventDefault"
assert 'id="submissions-wrap"' in html
wrap = html[html.find('id="submissions-wrap"'):]
wrap = wrap[:wrap.find(">") + 1]
assert "every" not in wrap, f"tabelul nu trebuie sa aiba poll periodic: {wrap}"
def test_poll_pauzat_cat_exista_bifa(client):
"""Conditia (b): macar un checkbox de bulk bifat -> poll-ul periodic e pus pe
pauza. Resume pe checkbox `change` prin delegare pe body (prinde si bifele
randate dupa swap)."""
_create_account_user("poll2@test.com")
def test_nudge_date_noi_in_loc_de_poll(client):
"""Reimprospatarea live se face prin nudge-ul 'Date noi' (poller usor de versiune)
care NU atinge tabelul; utilizatorul reincarca explicit cand vrea."""
acct = _create_account_user("poll2@test.com")
_login(client, "poll2@test.com")
js = client.get("/?tab=acasa").text
_insert_submission(acct)
html = client.get("/?tab=acasa").text
# Detecteaza bifa de bulk in interiorul #submissions-wrap.
assert "existaBifa" in js
assert 'input[name="submission_id"]:checked' in js
# Resume: delegare pe body pe evenimentul `change` al checkbox-ului de bulk.
assert "addEventListener('change'" in js
assert "t.name === 'submission_id'" in js
assert 'id="nudge-trimiteri"' in html, "bannerul nudge 'Date noi' trebuie sa existe"
assert "/_fragments/trimiteri-versiune" in html, "pollerul de versiune trebuie configurat"
assert "reincarcaTrimiteri" in html, "reincarcarea manuala (Reincarca) trebuie expusa"
def test_trimiteriChanged_inca_reincarca_cu_bifa(client):
"""R6 (F5): guard-ul NU anuleaza request-urile cu `triggeringEvent`
(trimiteriChanged / submit filtru) — acelea TREC MEREU, ca pauza sa nu ramana
lipita permanent daca randul bifat paraseste filtrul."""
_create_account_user("poll3@test.com")
def test_trimiteriChanged_inca_reincarca(client):
"""Actiunile utilizatorului (corectie / stergere) reincarca tabelul prin canalul
`trimiteriChanged`, pastrand filtrul curent (hx-include #filtre-trimiteri)."""
acct = _create_account_user("poll3@test.com")
_login(client, "poll3@test.com")
js = client.get("/?tab=acasa").text
_insert_submission(acct)
html = client.get("/?tab=acasa").text
# Numai trigger-ul periodic (fara triggeringEvent) e candidat la pauza;
# orice request cu triggeringEvent iese devreme din guard.
assert "triggeringEvent" in js
assert "rc.triggeringEvent) return" in js, \
"request-urile cu triggeringEvent (trimiteriChanged/filtru) trebuie sa treaca mereu"
# Resume explicit reutilizeaza acelasi canal `trimiteriChanged` (pastreaza filtrul).
assert "trimiteriChanged" in js
wrap = html[html.find('id="submissions-wrap"'):]
wrap = wrap[:wrap.find(">") + 1]
assert "trimiteriChanged from:body" in wrap, "tabelul trebuie sa reincarce pe trimiteriChanged"
assert 'hx-include="#filtre-trimiteri"' in wrap, "reincarcarea trebuie sa pastreze filtrul"

View File

@@ -84,25 +84,24 @@ def test_pill_per_categorie_cu_numar(client):
_ins(acct, status="sent", vin="WVIN_SE1_001", nr="BSE1")
_login(client, "pill1@test.com")
resp = client.get("/_fragments/status")
# Pill-urile traiesc in bara de filtre din sectiunea Trimiteri.
resp = client.get("/?tab=acasa")
assert resp.status_code == 200
body = resp.text
# Pill-urile sunt elemente <button> (nu <span onclick>)
# Pill-urile sunt elemente <button>
assert "<button" in body, "Pill-urile trebuie sa fie elemente <button>"
# Fiecare categorie problemativa apare ca pill
assert "needs_data" in body, "Pill needs_data trebuie sa apara"
assert "needs_mapping" in body, "Pill needs_mapping trebuie sa apara"
assert "error" in body, "Pill error trebuie sa apara (hx-get sau text)"
assert 'data-status="needs_data"' in body, "Pill needs_data trebuie sa apara"
assert 'data-status="needs_mapping"' in body, "Pill needs_mapping trebuie sa apara"
assert 'data-status="error"' in body, "Pill error trebuie sa apara"
# Contoarele sunt afisate in pill-uri
assert ">2<" in body or "2<" in body, "Contorul 2 pt needs_data trebuie vizibil in pill"
# Starea 'sent' nu produce pill (nu e categorie de problema)
# (nu exista un pill cu status=sent in bara de status)
pill_sent_count = body.count("status=sent")
assert pill_sent_count == 0, "Nu trebuie pill pentru sent in bara de status"
assert 'data-status="sent"' not in body, "Nu trebuie pill pentru sent"
def test_pill_click_seteaza_status(client):
@@ -113,21 +112,21 @@ def test_pill_click_seteaza_status(client):
_ins(acct, status="error", vin="WVIN_ER2_001", nr="BER_P2a")
_login(client, "pill2@test.com")
resp = client.get("/_fragments/status")
resp = client.get("/?tab=acasa")
assert resp.status_code == 200
body = resp.text
# Fiecare pill are atribut hx-get cu parametrul status corespunzator
assert "status=needs_data" in body, "Pill needs_data trebuie sa aiba ?status=needs_data in hx-get"
assert "status=needs_mapping" in body, "Pill needs_mapping trebuie sa aiba ?status=needs_mapping in hx-get"
assert "status=error" in body, "Pill error trebuie sa aiba ?status=error in hx-get"
# Fiecare pill scrie campul de filtru prin filtreazaStare(this, 'X')
assert "filtreazaStare(this, 'needs_data')" in body, "Pill needs_data trebuie sa apeleze filtreazaStare cu needs_data"
assert "filtreazaStare(this, 'needs_mapping')" in body, "Pill needs_mapping trebuie sa apeleze filtreazaStare cu needs_mapping"
assert "filtreazaStare(this, 'error')" in body, "Pill error trebuie sa apeleze filtreazaStare cu error"
# Pill-urile au aria-pressed pentru accesibilitate (WCAG)
assert "aria-pressed" in body, "Pill-urile trebuie sa aiba atribut aria-pressed"
# Target-ul este tabelul de trimiteri
assert "submissions-wrap" in body or "_fragments/submissions" in body, (
"Pill-urile trebuie sa targeteze #submissions-wrap sau sa apeleze /_fragments/submissions"
# Filtrarea trece prin form-ul care targeteaza tabelul de trimiteri
assert "submissions-wrap" in body and "_fragments/submissions" in body, (
"Form-ul de filtre trebuie sa targeteze #submissions-wrap prin /_fragments/submissions"
)
@@ -161,7 +160,7 @@ def test_pill_needs_mapping_culoare_warn(client):
_ins(acct, status="needs_mapping", vin="WVIN_NM_WARN0001", nr="BNMW1")
_login(client, "warn@test.com")
resp = client.get("/_fragments/status")
resp = client.get("/?tab=acasa")
assert resp.status_code == 200
body = resp.text
@@ -169,4 +168,4 @@ def test_pill_needs_mapping_culoare_warn(client):
assert "var(--warn)" in body, (
"Pill needs_mapping trebuie sa foloseasca var(--warn) conform DESIGN.md §Componente"
)
assert "status=needs_mapping" in body, "Pill needs_mapping trebuie sa fie prezent in bara"
assert 'data-status="needs_mapping"' in body, "Pill needs_mapping trebuie sa fie prezent in bara de filtre"

View File

@@ -133,26 +133,16 @@ def test_status_blocate_defalcare(client):
_insert_submission("needs_data", acct_id)
_insert_submission("error", acct_id)
resp = client.get("/_fragments/status")
# Pill-urile s-au mutat in bara de filtre din sectiunea Trimiteri (nu in bara de status).
resp = client.get("/?tab=acasa")
assert resp.status_code == 200
html = resp.text
# US-003 (PRD 5.10): Blocatele apar ca pill-uri (nu ca lista cu ID-uri)
assert "Necesita atentie" in html, (
f"Fragmentul nu contine sectiunea 'Necesita atentie'. HTML: {html[:800]}"
)
# Pill-urile au etichetele scurte per categorie (nu etichetele lungi din eticheta_stare)
assert "Lipsa cod" in html, (
"Fragmentul nu arata pill-ul pentru needs_mapping"
)
assert "Date incomplete" in html, (
"Fragmentul nu arata pill-ul pentru needs_data"
)
assert "Eroare" in html, (
"Fragmentul nu arata pill-ul pentru error"
)
assert "Lipsa cod" in html, "Acasa nu arata pill-ul pentru needs_mapping"
assert "Date incomplete" in html, "Acasa nu arata pill-ul pentru needs_data"
assert "Eroare" in html, "Acasa nu arata pill-ul pentru error"
# Pill-urile arata numarul total per categorie (2 needs_mapping, 1 needs_data, 1 error)
assert "2" in html, "Pill-ul needs_mapping trebuie sa arate numarul 2"
assert 'class="pill-cat"' in html, "Pill-urile trebuie sa fie elemente cu clasa pill-cat"
assert "<button" in html, "Pill-urile trebuie sa fie elemente <button>"
@@ -207,16 +197,15 @@ def _insert_submission_vehicul(status, account_id, vin, nr):
def test_categorie_blocata_linkeaza_la_trimiteri_filtrate(client):
"""US-003 (PRD 5.10): pill-ul error are hx-get cu ?status=error.
Deep-link-ul tab=acasa&status=error a fost eliminat (pill inlocuieste link-ul vechi)."""
"""Pill-ul error filtreaza tabelul prin filtreazaStare(this, 'error') in bara de filtre."""
acct_id, _ = _create_account_user("link@test.com", "parolasecreta10")
_login(client, "link@test.com", "parolasecreta10")
_insert_submission("error", acct_id)
html = client.get("/_fragments/status").text
# Pill-ul are hx-get cu status=error (filtrare directa submissions)
assert "/_fragments/submissions?status=error" in html
# Deep-link-ul tab=acasa&status=error nu mai exista — pill-uri inlocuiesc link-urile
html = client.get("/?tab=acasa").text
# Pill-ul scrie campul de filtru si re-trimite form-ul (nu mai navigheaza prin deep-link)
assert "filtreazaStare(this, 'error')" in html
assert 'data-status="error"' in html
assert "tab=acasa&status=error" not in html
@@ -228,12 +217,10 @@ def test_status_nu_arata_identificator_rand_blocat(client):
_insert_submission_vehicul("error", acct_id, "WVWZZZ1KZAW000123", "B123ABC")
html = client.get("/_fragments/status").text
# Bara de status arata pill cu count, nu lista cu VIN/nr per rand
# Bara de status arata doar contoare, nu lista cu VIN/nr per rand (fara PII nominal)
assert "B123ABC" not in html, "Nr inmatriculare nu trebuie sa mai apara in bara de status"
assert "WVWZZZ1KZAW000123" not in html, "VIN integral nu trebuie expus"
assert "0123" not in html, "VIN partial nu trebuie sa mai apara in bara de status"
# Pill-ul cu count 1 apare in locul listei
assert "status=error" in html, "Pill error trebuie sa aiba hx-get cu status=error"
def test_scoped_pe_cont(client):