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

@@ -123,7 +123,7 @@
background:var(--bg); color:var(--ink); -webkit-font-smoothing:antialiased; }
/* US-012c (PRD 5.10): grila 3 coloane — stanga (logo ROMFAST) | centru (titlu+env) | dreapta (controale). */
header { padding:16px 24px; border-bottom:1px solid var(--line);
display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:8px; }
display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:8px; min-height:92px; }
.header-left { display:flex; align-items:center; }
.header-center { display:flex; flex-direction:column; align-items:center; text-align:center; }
.header-right { display:flex; align-items:center; justify-content:flex-end; gap:8px; }
@@ -131,7 +131,8 @@
32px inaltime — usor mai mare decat in header-center (28px) pentru vizibilitate ca brand anchor.
margin:0 — aliniat stanga, NU centrat (era `margin:3px auto 0` cand era sub titlu).
Logo transparent: ok pe dark/light/petrol fara filtre de culoare. */
.brand-logo { height:32px; width:auto; display:block; margin:0; }
/* Logo ROMFAST la dimensiunea de pe romfast.ro (~60px inaltime), aliniat stanga. */
.brand-logo { height:60px; width:auto; display:block; margin:0; }
/* Env badge mic sub titlu in header-center (US-012c): nu mai echilibreaza optic dreapta
(logo-ul face asta), ci identifica mediul langa titlu. Pastrat mic, color:var(--muted). */
.header-center .env { font-size:11px; margin-top:2px; }
@@ -149,6 +150,28 @@
th { color:var(--muted); font-weight:500; font-size:12px; text-transform:uppercase; letter-spacing:.04em; }
.empty { color:var(--muted); padding:24px; text-align:center; }
.pill { font-size:12px; padding:2px 8px; border-radius:99px; border:1px solid var(--line); }
/* Pill-uri de filtrare a starii (bara de filtre Trimiteri). Inactiv = contur+text pe
culoarea categoriei (injectata inline); activ = umplere pe acea culoare. */
.pills-categorii { display:inline-flex; gap:8px; flex-wrap:wrap; align-items:center; }
.pill-cat { display:inline-flex; align-items:center; gap:5px; padding:4px 11px; border-radius:99px;
font-size:12px; font-weight:600; cursor:pointer; background:transparent;
border:1.5px solid var(--line); color:var(--muted); min-height:30px;
transition:background .15s, color .15s; }
.pill-cat:hover { filter:brightness(1.1); }
.pill-cat:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
.pill-cat-n { font-size:11px; font-weight:700; color:var(--card); padding:0 5px;
border-radius:99px; min-width:18px; text-align:center; }
.pill-cat[aria-pressed="true"] { background:currentColor; color:var(--card); border-color:currentColor; }
.pill-cat[aria-pressed="true"] .pill-cat-n { background:var(--card) !important; color:currentColor; }
.pill-cat-reset[aria-pressed="true"] { background:var(--accent); color:#fff; border-color:var(--accent); }
/* Nudge "Date noi": apare doar cand pollerul usor detecteaza schimbari; tabelul nu se
schimba singur niciodata, utilizatorul reincarca cand vrea. */
#nudge-trimiteri { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:0 0 12px;
padding:8px 12px; border-radius:8px; font-size:13px;
border:1px solid var(--accent);
background:color-mix(in srgb, var(--accent) 12%, var(--card)); }
#nudge-trimiteri[hidden] { display:none; }
#nudge-trimiteri button { font-size:13px; padding:5px 12px; min-height:32px; }
.s-queued{color:var(--accent);} .s-sending{color:var(--warn);} .s-sent{color:var(--ok);}
.s-error,.s-needs_data,.s-needs_mapping{color:var(--err);}
.s-ok{color:var(--ok);}
@@ -349,7 +372,8 @@
/* Header + nav colapsate: pe mobil trece de la grid la flex wrap.
Randul 1: [logo ROMFAST stanga] [controale dreapta] (margin-left:auto pe .header-right).
Randul 2: [titlu + env mic centrat, full-width]. Fara scroll orizontal, tinte >=44px. */
header { display:flex; flex-wrap:wrap; padding:12px 16px; gap:8px; align-items:center; }
header { display:flex; flex-wrap:wrap; padding:12px 16px; gap:8px; align-items:center; min-height:0; }
.brand-logo { height:44px; }
.header-left { order:0; flex:0 0 auto; }
.header-center { order:2; width:100%; text-align:center; }
.header-right { order:1; margin-left:auto; flex:0 0 auto; }
@@ -789,45 +813,49 @@
})();
</script>
<script>
// Poll-guard (PRD 5.9 US-005, R6). Inlocuieste vechea pauza pe „rand expandat" (5.8):
// randul-sibling de detaliu nu mai exista (US-003 l-a mutat in modalul global, care
// traieste in afara #submissions-wrap -> un swap de poll nu-l atinge). Aici oprim
// poll-ul de 15s de a REINCARCA lista cat timp (a) modalul e deschis SAU (b) exista
// cel putin un checkbox de bulk bifat — altfel modalul s-ar reseta / bifele s-ar sterge.
//
// CRITIC (F5): blocam DOAR trigger-ul periodic. In htmx `load`/`every 15s` declanseaza
// requestul FARA `triggeringEvent`; `trimiteriChanged` (HX-Trigger dupa corectie/stergere)
// si submit-ul/filtrul AU `triggeringEvent` -> TREC MEREU. Asa evitam blocajul permanent:
// daca randul bifat paraseste filtrul, pauza nu ramane lipita (pauza e legata strict de
// trigger-ul periodic, nu de o stare „sticky"). Anularea unui `htmx:beforeRequest` NU
// opreste timer-ul htmx (se reprogrameaza singur) -> poll-ul reia automat la urmatorul
// tic cand ambele conditii dispar; nu se pierde scroll, focus sau selectia de bife.
// Filtrare stare prin pill-uri + reincarcare manuala a tabelului. Tabelul NU se mai
// schimba singur (fara poll periodic pe #submissions-wrap): un poller usor verifica
// doar versiunea datelor si arata nudge-ul "Date noi" cand difera. Reincarcarea
// (pill, nudge sau actiune) trece prin form -> pastreaza filtrul/pagina curenta.
(function() {
function modalDeschis() {
var o = document.getElementById('modal-detaliu');
return !!(o && !o.hidden);
// Pill de stare: scrie campul hidden, reseteaza pagina la 1 si re-trimite filtrul.
window.filtreazaStare = function(btn, status) {
var form = document.getElementById('filtre-trimiteri');
if (!form) return;
var hs = document.getElementById('f-status'); if (hs) hs.value = status || '';
var hp = document.getElementById('f-page'); if (hp) hp.value = '1';
document.querySelectorAll('#pills-categorii .pill-cat').forEach(function(b) {
b.setAttribute('aria-pressed', 'false');
});
if (btn) btn.setAttribute('aria-pressed', 'true');
if (form.requestSubmit) form.requestSubmit(); else form.submit();
};
// Reincarca tabelul pastrand filtrul curent (hx-include #filtre-trimiteri) si ascunde nudge-ul.
window.reincarcaTrimiteri = function() {
var n = document.getElementById('nudge-trimiteri'); if (n) n.hidden = true;
if (window.htmx) htmx.trigger('#submissions-wrap', 'reincarcaTrimiteri');
};
// Poller "Date noi": compara versiunea datelor cu cea cu care s-a randat tabelul.
// Daca difera, arata nudge-ul; daca nu, nu atinge nimic. JSON usor, fara re-render.
var INTERVAL = 20000;
function versiuneCurenta() {
var e = document.getElementById('trimiteri-versiune');
return e ? e.getAttribute('data-v') : null;
}
function existaBifa() {
return !!document.querySelector('#submissions-wrap input[name="submission_id"]:checked');
function verifica() {
if (versiuneCurenta() === null) return; // tabelul nu e pe ecran (alt tab)
var nudge = document.getElementById('nudge-trimiteri');
if (!nudge || !nudge.hidden) return; // deja afisat -> nu re-cere
fetch('/_fragments/trimiteri-versiune', { headers: { 'X-Requested-With': 'fetch' } })
.then(function(r) { return r.ok ? r.json() : null; })
.then(function(d) {
if (!d) return;
if (d.v !== versiuneCurenta()) nudge.hidden = false;
})
.catch(function() {});
}
document.body.addEventListener('htmx:beforeRequest', function(evt) {
var d = evt.detail || {};
if (!d.elt || d.elt.id !== 'submissions-wrap') return; // doar poll-ul listei
var rc = d.requestConfig || {};
if (rc.triggeringEvent) return; // trimiteriChanged / filtru: TREC MEREU
if (modalDeschis() || existaBifa()) evt.preventDefault(); // pauza scopata pe periodic
});
// Resume pe checkbox `change`->gol: delegare pe body ca sa prinda si checkbox-urile
// randate dupa swap. Cand modalul e inchis si nu mai exista nicio bifa, fortam un
// refresh imediat (nu mai asteptam ticul de 15s) prin `trimiteriChanged from:body`,
// care pastreaza filtrul curent (hx-include #filtre-trimiteri) si trece de guard.
document.body.addEventListener('change', function(evt) {
var t = evt.target;
if (!(t && t.name === 'submission_id')) return;
if (!modalDeschis() && !existaBifa() && window.htmx) {
htmx.trigger(document.body, 'trimiteriChanged');
}
});
setInterval(verifica, INTERVAL);
})();
</script>
</body>