diff --git a/app/web/templates/_submissions.html b/app/web/templates/_submissions.html
index 7454e65..bf54f4e 100644
--- a/app/web/templates/_submissions.html
+++ b/app/web/templates/_submissions.html
@@ -51,6 +51,12 @@
{{ r.id }} |
{{ r.stare_scurt }}
+ {# PRD 5.9 US-002 (R1): eticheta umana scurta sub pill — text mic, `s-error`
+ pe error/needs_* (singurele stari pe care `eticheta_problema` e ne-goala).
+ Stare transmisa prin TEXT, nu doar culoare. Codul brut ramane in modal. #}
+ {% if r.eticheta_problema %}
+ {{ r.eticheta_problema }}
+ {% endif %}
|
{{ r.prez.vehicul_nr }}
@@ -60,8 +66,10 @@
|
{{ r.prez.operatie }}
+ {# PRD 5.9 US-002: doar codul RAR (ex. OE-2), FARA prefixul "cod RAR:" — chip
+ muted discret; cand nemapat afiseaza "nemapat" muted (comportament 5.8). #}
{% if r.prez.cod_rar and r.prez.cod_rar != '—' %}
- cod RAR: {{ r.prez.cod_rar }}
+ {{ r.prez.cod_rar }}
{% else %}
nemapat
{% endif %}
diff --git a/app/web/templates/base.html b/app/web/templates/base.html
index 56dec79..c7b7eda 100644
--- a/app/web/templates/base.html
+++ b/app/web/templates/base.html
@@ -176,6 +176,21 @@
.tabel-trimiteri .col-operatie > div { line-height:1.35; }
/* secundarul muted („cod RAR" / „nemapat") — >=12px, contrast pe var(--muted) >=4.5:1 */
.tabel-trimiteri .cod-rar-sub { font-size:12px; margin-top:2px; }
+ /* PRD 5.9 US-002: codul RAR pe linia 2 — chip discret, fara prefixul „cod RAR:". */
+ .tabel-trimiteri .cod-rar-cod { display:inline-block; font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
+ font-size:12px; padding:1px 7px; border:1px solid var(--line);
+ border-radius:99px; color:var(--muted); }
+ /* PRD 5.9 US-002 (R1): eticheta umana scurta sub pill — text mic; clasa `s-error`
+ o coloreaza (apare doar pe error/needs_*). Stare prin text, nu doar culoare. */
+ .tabel-trimiteri .eticheta-problema { font-size:12px; line-height:1.3; margin-top:3px; }
+ /* PRD 5.9 US-002 (R8): randul e clickabil (deschide modalul) -> tinta de atins >=44px
+ (touch) + afordanta hover/focus. Inlocuieste vechea regula `@media pointer:coarse
+ .chevron` (chevron eliminat); este SINGURA regula 44px pe rand. */
+ .tabel-trimiteri tr.trimitere-row { min-height:44px; }
+ .tabel-trimiteri tr.trimitere-row > td { padding-top:11px; padding-bottom:11px; }
+ .tabel-trimiteri tr.trimitere-row:hover { background:color-mix(in srgb, var(--accent) 6%, transparent); }
+ .tabel-trimiteri tr.trimitere-row:focus,
+ .tabel-trimiteri tr.trimitere-row:focus-visible { outline:2px solid var(--accent); outline-offset:-2px; }
/* 768-1024px: ascunde Actualizat (e in detaliu) -> 7 coloane, fara scroll */
@media (max-width:1024px) {
.tabel-trimiteri .col-actualizat { display:none; }
diff --git a/scripts/ralph/prd.json b/scripts/ralph/prd.json
index 9c25228..795e4b5 100644
--- a/scripts/ralph/prd.json
+++ b/scripts/ralph/prd.json
@@ -29,7 +29,9 @@
"Teste in `tests/test_web_submissions.py`: `test_eticheta_umana_sub_pill` (R1 rename), eticheta prezenta pe error/needs_mapping, goala pe rand ok.",
"`python3 -m pytest tests/test_web_submissions.py -q` trece."
],
- "tags": ["backend"],
+ "tags": [
+ "backend"
+ ],
"dependsOn": [],
"requiresBrowserCheck": false,
"requiresDesignReview": false,
@@ -57,7 +59,9 @@
"Teste in `tests/test_web_modal.py`: `test_modal_container_in_afara_submissions_wrap`, `test_fragment_detaliu_tinteste_modalul`.",
"`python3 -m pytest tests/test_web_modal.py -q` trece."
],
- "tags": ["ui"],
+ "tags": [
+ "ui"
+ ],
"dependsOn": [],
"requiresBrowserCheck": true,
"requiresDesignReview": true,
@@ -81,8 +85,12 @@
"Teste in `tests/test_web_responsive.py`: `test_viewport_meta_prezent`, `test_modal_fullscreen_clasa_mobil`, `test_nav_colapsabil_sub_breakpoint`.",
"`python3 -m pytest tests/test_web_responsive.py -q` trece."
],
- "tags": ["ui"],
- "dependsOn": ["US-003"],
+ "tags": [
+ "ui"
+ ],
+ "dependsOn": [
+ "US-003"
+ ],
"requiresBrowserCheck": true,
"requiresDesignReview": true,
"passes": false,
@@ -107,16 +115,21 @@
"`python3 -m pytest tests/test_web_submissions.py -q` trece.",
"E2E (requiresBrowserCheck): gstack browser pe `/` — rand `error` arata eticheta umana sub pill; fara chevron; cod RAR fara `cod RAR:`; click pe rand deschide modalul (nu rand-sibling)."
],
- "tags": ["ui"],
- "dependsOn": ["US-001", "US-003"],
+ "tags": [
+ "ui"
+ ],
+ "dependsOn": [
+ "US-001",
+ "US-003"
+ ],
"requiresBrowserCheck": true,
"requiresDesignReview": false,
- "passes": false,
+ "passes": true,
"failed": false,
"blocked": false,
"retries": 0,
"failureReason": "",
- "notes": ""
+ "notes": "Mare parte deja livrat de US-001 (camp eticheta_problema) si US-003 (rand declanseaza modalul). Atins: app/web/templates/_submissions.html (eticheta_problema sub pill cu clasa s-error doar cand ne-gol; col-operatie cod RAR ca chip cod-rar-cod fara prefixul 'cod RAR:'; nemapat muted), app/web/templates/base.html (CSS .eticheta-problema/.cod-rar-cod + R8 regula 44px touch-target pe tr.trimitere-row + hover/focus), tests/test_web_submissions.py (7 teste noi US-002 + actualizat test_operatie_contine_cod_rar si test_tabel_nu_are_coloana_motiv). Chevron inexistent in cod -> R8 doar adaugare regula 44px. Gates: pytest PASS (fisier 20; suita 826 passed, 1 deselected). DEFERAT la VERIFY: requiresBrowserCheck (gstack E2E pe /) + verificarea JS keyboard (Enter/Space deschide modal, Esc readuce focus) — netestabile in TestClient, acoperite prin assert pe markup/atribute (role=button, tabindex=0, aria-haspopup=dialog, fara aria-expanded) + prezenta handler-elor in base.html."
},
{
"id": "US-004",
@@ -138,8 +151,12 @@
"`python3 -m pytest tests/test_web_corectie.py -q` trece.",
"E2E (requiresBrowserCheck): gstack browser — `needs_data` arata fiecare camp o data (nr. pe un rand, VIN dedesubt), corectez data, `Salveaza si retrimite` -> rand `queued`; `error` arata `Re-pune in coada`; `Sterge` clar separat si rosu."
],
- "tags": ["ui"],
- "dependsOn": ["US-003"],
+ "tags": [
+ "ui"
+ ],
+ "dependsOn": [
+ "US-003"
+ ],
"requiresBrowserCheck": true,
"requiresDesignReview": true,
"passes": false,
@@ -165,8 +182,12 @@
"`python3 -m pytest tests/test_web_responsive.py -q` trece.",
"E2E (requiresBrowserCheck): gstack browser la 375px pe `/?tab=mapari`, `?tab=jurnal`, Cont/Nomenclator/Integrare si `/admin` — fiecare fara scroll orizontal, tabele lizibile, formulare pe o coloana."
],
- "tags": ["ui"],
- "dependsOn": ["US-006"],
+ "tags": [
+ "ui"
+ ],
+ "dependsOn": [
+ "US-006"
+ ],
"requiresBrowserCheck": true,
"requiresDesignReview": false,
"passes": false,
@@ -191,8 +212,12 @@
"`python3 -m pytest tests/test_web_responsive.py -q` trece.",
"E2E (requiresBrowserCheck): gstack browser la 375px pe `/`, `/login`, `/signup` — fara scroll orizontal; upload + filtre pe o coloana; carduri de trimiteri intacte."
],
- "tags": ["ui"],
- "dependsOn": ["US-006"],
+ "tags": [
+ "ui"
+ ],
+ "dependsOn": [
+ "US-006"
+ ],
"requiresBrowserCheck": true,
"requiresDesignReview": false,
"passes": false,
@@ -217,8 +242,13 @@
"`python3 -m pytest tests/test_web_modal.py -q` trece.",
"E2E (requiresBrowserCheck): gstack browser — bifez 2 trimiteri, astept >15s: bifele raman; deschid modalul, astept >15s: modalul ramane deschis cu datele intacte."
],
- "tags": ["ui"],
- "dependsOn": ["US-002", "US-003"],
+ "tags": [
+ "ui"
+ ],
+ "dependsOn": [
+ "US-002",
+ "US-003"
+ ],
"requiresBrowserCheck": true,
"requiresDesignReview": false,
"passes": false,
diff --git a/scripts/ralph/progress.txt b/scripts/ralph/progress.txt
index 6cdba40..f8753f1 100644
--- a/scripts/ralph/progress.txt
+++ b/scripts/ralph/progress.txt
@@ -34,3 +34,37 @@ Note: PRD APROBAT 2026-06-24 cu revizii obligatorii R1-R12 (raport AUTOPLAN). R1
- US-002 depinde de US-001 (acum done) + US-003.
---
## Rate limit la iter 10 — sleep 1800
+
+## Iteratie: 2026-06-25
+### Story implementat: US-002 - Tabel trimiteri: eticheta umana sub stare, fara chevron, cod RAR simplu, rand declanseaza modalul (tags: ui)
+### Status: Complete
+
+### Gates rulate:
+- Typecheck: SKIP (techStack.commands.typecheck gol)
+- Lint: SKIP (techStack.commands.lint gol)
+- Tests: PASS (tests/test_web_submissions.py 20; suita completa 826 passed, 1 deselected)
+- Browser (gstack/E2E requiresBrowserCheck) si /review: DEFERATE la VERIFY (loop fara browser) — vezi AC E2E.
+
+### Ce s-a schimbat:
+- app/web/templates/_submissions.html: sub pill (col-stare) randeaza `r.eticheta_problema`
+ (text mic `eticheta-problema s-error`, DOAR cand e ne-gol); col-operatie linia 2 arata
+ codul RAR ca chip `cod-rar-cod` FARA prefixul "cod RAR:" (nemapat -> "nemapat" muted).
+- app/web/templates/base.html: CSS nou `.eticheta-problema`, `.cod-rar-cod`, si regula R8
+ 44px touch-target pe `tr.trimitere-row` (min-height + padding 11px) + afordanta hover/focus.
+- tests/test_web_submissions.py: 7 teste noi US-002 (eticheta sub pill + absenta pe ok, fara
+ chevron, cod RAR fara prefix, nemapat, rand deschide modal, a11y+keyboard markup); actualizat
+ `test_operatie_contine_cod_rar` (fara prefix) si `test_tabel_nu_are_coloana_motiv` (eticheta sub pill).
+
+### Learnings:
+- Mare parte din scope-ul US-002 era deja livrat de US-001 (campul `eticheta_problema`) si US-003
+ (randul declanseaza modalul: role=button/tabindex/aria-haspopup, fara aria-expanded; htmx:beforeRequest
+ fara toggle). Chevron-ul NU exista in cod (grep zero) -> R8 a insemnat doar adaugarea regulii 44px, nu eliminare.
+- `motiv_uman` echo-ul mesajului RAR => eticheta_problema poate contine textul brut al erorii. Asta a
+ intrat in conflict cu vechiul `test_tabel_nu_are_coloana_motiv` (5.8) care interzicea continutul Motiv
+ in tabel; US-002 R1 il surfaceaza intentionat sub pill, deci testul a fost actualizat (pastreaza doar
+ invarianta "fara coloana/celula Motiv").
+
+### Next:
+- US-004 (detaliu editabil in-place + butoane in modal), US-005 (poll nu inchide modalul), US-006/007/008 (responsive).
+- VERIFY: ruleaza gstack E2E pe `/` pentru AC requiresBrowserCheck (eticheta sub pill, fara chevron, cod fara prefix, click deschide modal).
+---
diff --git a/tests/test_web_submissions.py b/tests/test_web_submissions.py
index 747333a..0b91f8f 100644
--- a/tests/test_web_submissions.py
+++ b/tests/test_web_submissions.py
@@ -125,7 +125,11 @@ def test_motiv_needs_data_afisat(client):
def test_tabel_nu_are_coloana_motiv(client):
- """PRD 5.8 US-007: coloana Motiv eliminata din thead/tbody (e in detaliu)."""
+ """PRD 5.8 US-007: Motiv nu e o coloana separata in thead/tbody.
+
+ Nota (PRD 5.9 US-002, R1): eticheta umana scurta a problemei apare acum sub pill-ul
+ de Stare ca text mic (NU intr-o coloana proprie) — vezi test_eticheta_umana_apare_sub_pill.
+ """
acct = _create_account_user("nomotiv@test.com")
_insert_submission(
acct, "needs_data",
@@ -136,12 +140,12 @@ def test_tabel_nu_are_coloana_motiv(client):
assert resp.status_code == 200
html = resp.text
assert " | Motiv | " not in html
- # continutul Motiv nu mai apare in tabel (a fost mutat in detaliu)
- assert "lipsa odometru xyz" not in html
+ # Motiv nu are coloana/celula dedicata (label-ul scurt sta sub pill in col-stare)
+ assert 'data-eticheta="Motiv"' not in html
def test_operatie_contine_cod_rar(client):
- """PRD 5.8 US-007: coloana Operatie arata 'cod RAR: XXX' cand mapat, 'nemapat' cand nu."""
+ """PRD 5.9 US-002: coloana Operatie arata codul RAR simplu (FARA prefix) cand mapat, 'nemapat' cand nu."""
acct = _create_account_user("codrar@test.com")
# mapat: are cod_prestatie -> cod RAR vizibil
_insert_submission(acct, "sent", payload={
@@ -163,7 +167,9 @@ def test_operatie_contine_cod_rar(client):
resp = client.get("/_fragments/submissions")
assert resp.status_code == 200
html = resp.text
- assert "cod RAR: OE-2" in html
+ # US-002: codul ramane, dar prefixul textual "cod RAR:" a fost eliminat (R8)
+ assert "OE-2" in html
+ assert "cod RAR:" not in html
assert "nemapat" in html
@@ -195,6 +201,120 @@ def test_detaliu_trimitere(client):
assert "99001" in html # nr prezentare RAR
+# ---------------------------------------------------------------------------
+# US-002 (PRD 5.9): tabel trimiteri — eticheta umana sub pill, fara chevron,
+# cod RAR simplu (fara prefix), randul declanseaza modalul. Teste de randare.
+# ---------------------------------------------------------------------------
+
+def test_eticheta_umana_apare_sub_pill(client):
+ """Sub pill-ul de Stare apare eticheta umana scurta (text), nu codul brut."""
+ acct = _create_account_user("ets@test.com")
+ _insert_submission(
+ acct, "needs_data",
+ rar_error=json.dumps([{"field": "odometru_final", "message": "lipsa odometru"}]),
+ )
+ _login(client, "ets@test.com")
+ resp = client.get("/_fragments/submissions")
+ assert resp.status_code == 200
+ html = resp.text
+ assert "eticheta-problema" in html # containerul textului uman sub pill
+ assert "s-error" in html # colorat ca problema (error/needs_*)
+ # NU randeaza cod brut de catalog pe rand
+ assert "COD_" not in html
+ assert "RAR_EROARE" not in html
+
+
+def test_eticheta_umana_absenta_pe_rand_ok(client):
+ """Pe randuri fara problema (sent) nu apare eticheta-problema (string gol -> nimic)."""
+ acct = _create_account_user("etok@test.com")
+ _insert_submission(acct, "sent", id_prezentare=70123)
+ _login(client, "etok@test.com")
+ resp = client.get("/_fragments/submissions")
+ assert resp.status_code == 200
+ assert "eticheta-problema" not in resp.text
+
+
+def test_fara_chevron_in_rand(client):
+ """R8: niciun chevron in coloana # / pe rand (eliminat impreuna cu CSS/JS asociat)."""
+ acct = _create_account_user("chev@test.com")
+ _insert_submission(acct, "sent")
+ _login(client, "chev@test.com")
+ resp = client.get("/_fragments/submissions")
+ assert resp.status_code == 200
+ assert "chevron" not in resp.text
+
+
+def test_cod_rar_fara_prefix_text(client):
+ """Coloana Operatie linia 2: doar codul RAR (ex. OE-2), FARA prefixul 'cod RAR:'."""
+ acct = _create_account_user("crp@test.com")
+ _insert_submission(acct, "sent", payload={
+ "vin": "WVWZZZ1JZXW000111",
+ "nr_inmatriculare": "B111AAA",
+ "data_prestatie": "2026-06-18",
+ "odometru_final": "10000",
+ "prestatii": [{"cod_prestatie": "OE-2", "denumire": "Verificare X"}],
+ })
+ _login(client, "crp@test.com")
+ resp = client.get("/_fragments/submissions")
+ assert resp.status_code == 200
+ html = resp.text
+ assert "OE-2" in html # codul ramane vizibil
+ assert "cod RAR:" not in html # prefixul textual a disparut
+
+
+def test_cod_rar_nemapat_muted(client):
+ """Cand nemapat, linia 2 arata 'nemapat' muted (comportament 5.8 pastrat)."""
+ acct = _create_account_user("crn@test.com")
+ _insert_submission(acct, "needs_mapping", payload={
+ "vin": "WVWZZZ1JZXW000222",
+ "nr_inmatriculare": "B222BBB",
+ "data_prestatie": "2026-06-18",
+ "odometru_final": "20000",
+ "prestatii": [{"cod_op_service": "INTERN9", "denumire": "Spalare auto"}],
+ })
+ _login(client, "crn@test.com")
+ resp = client.get("/_fragments/submissions")
+ assert resp.status_code == 200
+ assert "nemapat" in resp.text
+
+
+def test_rand_deschide_modal(client):
+ """Randul tinteste corpul modalului (#detaliu-modal-body), NU un rand-sibling (US-003)."""
+ acct = _create_account_user("mod@test.com")
+ sid = _insert_submission(acct, "sent")
+ _login(client, "mod@test.com")
+ resp = client.get("/_fragments/submissions")
+ assert resp.status_code == 200
+ html = resp.text
+ assert f'hx-get="/_fragments/trimitere/{sid}"' in html
+ assert 'hx-target="#detaliu-modal-body"' in html
+ # randul-sibling de detaliu din 5.8 a fost eliminat
+ assert "detaliu-rand" not in html
+
+
+def test_rand_a11y_si_keyboard_markup(client):
+ """R8 a11y: rand role=button, tabindex=0, aria-haspopup=dialog, FARA aria-expanded.
+
+ Limitare: deschiderea efectiva pe Enter/Space si readucerea focusului pe Esc sunt
+ gestionate de JS in base.html (keydown delegat), netestabile in TestClient (fara DOM).
+ Verificam markup-ul/atributele care le activeaza + prezenta handler-elor de tastatura.
+ """
+ acct = _create_account_user("kbd@test.com")
+ _insert_submission(acct, "sent")
+ _login(client, "kbd@test.com")
+ resp = client.get("/_fragments/submissions")
+ assert resp.status_code == 200
+ html = resp.text
+ assert 'role="button"' in html
+ assert 'tabindex="0"' in html
+ assert 'aria-haspopup="dialog"' in html
+ assert "aria-expanded" not in html # R8: nu mai e expand/collapse pe rand
+ # Handler-ele de tastatura traiesc in base.html (pagina completa).
+ base = client.get("/?tab=coada").text
+ assert "Enter" in base and "Spacebar" in base # Enter/Space deschid modalul
+ assert "Escape" in base # Esc inchide + readuce focusul
+
+
# ---------------------------------------------------------------------------
# US-001 (R1): eticheta umana scurta a problemei pe randul de tabel.
# Teste pure pe _submission_row_view — randarea sub pill e US-002.