feat(web): UI compact Trimiteri + bara bulk contextuala + fix buton "+" editor (PRD 5.22)

Trimiteri desktop = tabel grid cu header, un rand per trimitere: status =
bulina cu tooltip, mediu = litera T/P, multi-cod = primul cod + badge +N,
sub-linie de eroare cu textul brut RAR doar pe error/needs_data. Mobil:
2 linii prin grid-areas, fara header. Actiunile bulk apar doar la selectie
(bara contextuala cu contor + texte explicite). Mapari: exemplu concret in
loc de descriere la Reguli automate.

Fix buton "+" chips (nu facea nimic, fara eroare): hx-disabled-elt="find
button" mostenit de la form-ul parinte crapa htmx inainte de request ->
hx-disabled-elt="this" explicit pe butoanele chips; separat, no-op-urile
silentioase din post_form_chips au acum mesaje (cod invalid/duplicat) si
confirmare cu chip evidentiat la succes.

Suita: 1622 passed. Verify E2E in browser (desktop 1280 + mobil 390).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-07-07 12:27:42 +00:00
parent 6674d0e3e1
commit 5a2c976d46
17 changed files with 912 additions and 169 deletions

View File

@@ -32,6 +32,7 @@ from ..web.csrf import get_csrf_token, verify_csrf
from .labels import (
ETICHETA_ULTIMA_AUTENTIFICARE_RAR,
STARI_PREVIEW,
eroare_bruta,
eticheta_env,
eticheta_rar,
eticheta_scurta,
@@ -1131,6 +1132,8 @@ def _submission_row_view(r) -> dict:
"motiv": motiv,
# eticheta umana scurta a problemei sub pill (text, nu cod brut).
"eticheta_problema": _eticheta_problema(r["status"], motiv),
# textul brut compact al erorii (mesaj RAR/validare) — sub-linia randului.
"eroare_bruta": eroare_bruta(r["status"], r["rar_error"]),
# randurile blocate (error/needs_data/needs_mapping) sunt selectabile pentru
# stergere bulk; sent/sending/queued raman read-only (fara checkbox).
"gestionabil": r["status"] in _GESTIONABILE_WEB,
@@ -2397,9 +2400,19 @@ async def post_form_chips(request: Request) -> HTMLResponse:
})
action = str(form.get("chips_action") or "").strip()
chips_extra_error = False # T-C1/T-E4 (5.16): semnal pentru add_extra esuat
# Orice adaugare are un efect vizibil: mesaj de refuz (chips_error) sau
# confirmare + chip evidentiat (chips_ok / chips_added_cod). Fara no-op silentios.
chips_error = ""
chips_ok = ""
chips_added_cod = ""
conn = get_connection()
def _cod_valid(cod: str) -> bool:
return conn.execute(
"SELECT 1 FROM nomenclator_rar WHERE cod_prestatie=?", (cod,)
).fetchone() is not None
try:
if action == "add":
# Adauga cod la operatia specificata prin chips_add_op_index
@@ -2408,44 +2421,37 @@ async def post_form_chips(request: Request) -> HTMLResponse:
except (ValueError, TypeError):
op_idx = 0
add_cod = str(form.get(f"chips_add_cod_{op_idx}") or "").strip().upper()
if add_cod and 0 <= op_idx < len(chips):
exists = conn.execute(
"SELECT 1 FROM nomenclator_rar WHERE cod_prestatie=?", (add_cod,)
).fetchone()
if exists:
chips[op_idx]["cod_prestatie"] = add_cod
elif action == "add_flat":
# Adauga cod nou in lista plata (fara op_service)
add_cod_flat = str(form.get("chips_add_cod_flat") or "").strip().upper()
if add_cod_flat:
exists = conn.execute(
"SELECT 1 FROM nomenclator_rar WHERE cod_prestatie=?", (add_cod_flat,)
).fetchone()
if exists:
chips.append({"cod_prestatie": add_cod_flat, "cod_op_service": "", "denumire": ""})
elif action == "add_extra":
# Adauga cod RAR liber (extra, fara op_service) in modul operatii.
# Refoloseste `chips_add_cod_flat` (acelasi select; dedup per-item pastrat).
# Select gol sau cod invalid → chips_extra_error = True (semnal vizibil).
add_cod_extra = str(form.get("chips_add_cod_flat") or "").strip().upper()
if add_cod_extra:
exists = conn.execute(
"SELECT 1 FROM nomenclator_rar WHERE cod_prestatie=?", (add_cod_extra,)
).fetchone()
if exists:
# Dedup per-item (E4): nu adauga un chip extra identic deja existent
existing_pairs = {
(c.get("cod_op_service", ""), c.get("cod_prestatie", ""))
for c in chips
}
if ("", add_cod_extra) not in existing_pairs:
chips.append({"cod_prestatie": add_cod_extra, "cod_op_service": "", "denumire": ""})
else:
chips_extra_error = True # cod necunoscut in nomenclator
if not add_cod:
chips_error = "Selecteaza un cod RAR din lista inainte de a adauga."
elif not (0 <= op_idx < len(chips)):
chips_error = "Operatia nu mai exista in formular — reincarca editarea."
elif not _cod_valid(add_cod):
chips_error = f"Cod necunoscut in nomenclator: {add_cod}."
else:
chips_extra_error = True # select gol
chips[op_idx]["cod_prestatie"] = add_cod
chips_ok = f"{add_cod} adaugat."
chips_added_cod = add_cod
elif action in ("add_flat", "add_extra"):
# Adauga cod RAR liber (fara op_service): add_flat = mod plat,
# add_extra = mod operatii. Acelasi select (chips_add_cod_flat),
# aceeasi validare si acelasi dedup per-item (E4).
add_cod_flat = str(form.get("chips_add_cod_flat") or "").strip().upper()
if not add_cod_flat:
chips_error = "Selecteaza un cod RAR din lista inainte de a adauga."
elif not _cod_valid(add_cod_flat):
chips_error = f"Cod necunoscut in nomenclator: {add_cod_flat}."
else:
existing_pairs = {
(c.get("cod_op_service", ""), c.get("cod_prestatie", ""))
for c in chips
}
if ("", add_cod_flat) in existing_pairs:
chips_error = f"{add_cod_flat} este deja in lista — nu a fost adaugat inca o data."
else:
chips.append({"cod_prestatie": add_cod_flat, "cod_op_service": "", "denumire": ""})
chips_ok = f"{add_cod_flat} adaugat."
chips_added_cod = add_cod_flat
elif action == "remove":
# Sterge codul de la indexul dat (lasa op_service intact -> operatie ramane nemapata)
@@ -2480,7 +2486,9 @@ async def post_form_chips(request: Request) -> HTMLResponse:
"has_r_odo": has_r_odo,
"form_chips_url": "/form-chips",
"chips_section_id": "chips-section",
"chips_extra_error": chips_extra_error,
"chips_error": chips_error,
"chips_ok": chips_ok,
"chips_added_cod": chips_added_cod,
})