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

@@ -20,7 +20,7 @@ from pathlib import Path
from typing import Any
from fastapi import APIRouter, File, Form, HTTPException, Request, UploadFile
from fastapi.responses import HTMLResponse
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.templating import Jinja2Templates
from .. import __version__
@@ -113,6 +113,18 @@ def _status_counts(conn, account_id: int) -> dict[str, int]:
return {r["status"]: int(r["n"]) for r in rows}
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
fara a re-randa tabelul."""
row = conn.execute(
"SELECT COUNT(*) AS n, COALESCE(MAX(updated_at), '') AS m FROM submissions "
"WHERE (account_id = ? OR (? = 1 AND account_id IS NULL))",
(account_id, account_id),
).fetchone()
return f"{row['n']}:{row['m']}"
def _account_active(conn, account_id: int) -> bool:
"""True daca contul e activ (sau legacy cu NULL/absent active)."""
row = conn.execute("SELECT active FROM accounts WHERE id=?", (account_id,)).fetchone()
@@ -196,6 +208,10 @@ def _get_acasa_context(request: Request, conn, account_id: int) -> dict:
"are_trimiteri": are_trimiteri,
"are_cheie_folosita": are_cheie_folosita,
"blocate_total": blocate_total,
# Pill-uri de filtrare a starii, randate in bara de filtre (nu in bara de status).
"pills_categorii": _pills_categorii(counts),
# Semnatura datelor: nudge-ul "Date noi" o compara la fiecare poll usor.
"versiune_trimiteri": _trimiteri_versiune(conn, account_id),
# US-002: Acasa include caseta de upload -> are nevoie de csrf_token
"csrf_token": get_csrf_token(request),
}
@@ -212,7 +228,9 @@ def _render_panel_acasa(request: Request, conn=None, account_id: int = 1, status
{"request": request, "csrf_token": get_csrf_token(request)}
)
ctx = _get_acasa_context(request, conn, account_id)
ctx["status_filtru"] = status
# `status or ""`: campul hidden de filtru ar randa literal "None" cu un None Python
# (Jinja `default('')` inlocuieste doar undefined), trimitand status=None la poll.
ctx["status_filtru"] = status or ""
return templates.get_template("_acasa.html").render(ctx)
@@ -621,6 +639,19 @@ def fragment_status(request: Request) -> HTMLResponse:
conn.close()
@router.get("/_fragments/trimiteri-versiune", response_class=JSONResponse)
def fragment_trimiteri_versiune(request: Request) -> JSONResponse:
"""Semnatura curenta a trimiterilor contului (JSON usor). Pollerul "Date noi" o
compara cu versiunea cu care s-a randat tabelul; daca difera, arata nudge-ul de
reincarcare — tabelul nu se mai schimba singur."""
account_id = require_login(request)
conn = get_connection()
try:
return JSONResponse({"v": _trimiteri_versiune(conn, account_id)})
finally:
conn.close()
def _iso_date_prefix(value: object) -> str | None:
"""Intoarce primele 10 caractere (YYYY-MM-DD) daca incep cu o data ISO valida, altfel None.
@@ -795,6 +826,10 @@ def fragment_submissions(
"f_vehicul": vehicul_q or "",
"f_data_de": data_de or "",
"f_data_pana": data_pana or "",
# 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),
})
finally:
conn.close()
@@ -823,6 +858,9 @@ def _render_submissions(request: Request, conn, account_id: int) -> HTMLResponse
"rows": view,
"filtru_activ": False,
"csrf_token": get_csrf_token(request),
"pills_categorii": _pills_categorii(_status_counts(conn, account_id)),
"status_filtru": "",
"versiune_trimiteri": _trimiteri_versiune(conn, account_id),
})