Implementare completa U5 din plan-treapta2.md (sectiunea 13): - _upload.html: drop zone + buton accesibil (a11y: drag nu e la tastatura), drag-and-drop JS, mesaj 'NU se trimite nimic pana confirmi', selector foi pt multi-sheet xlsx, stari eroare/mesaj - _mapcoloane.html: formular mapare coloane cu .maprow/.mapcol.grow, sugestii fuzzy pre-selectate, etiichete <label> vizibile, sample values, format data configurabil - _preview_import.html: tabel 6 stari, pills rezumat, filtre pe stare, .chk per-rand pe needs_review (D11), banner declarant .banner.warn direct deasupra input-ului N (D12), bara confirmare sticky, text 'dubla cu randul N' pe duplicate_in_file (D10 daltonism), link export CSV randuri esuate - base.html: .s-needs_review (warn), .s-already_sent/.s-duplicate_in_file (muted), .drop-zone, .banner.warn, .sticky-bar, .htmx-indicator - routes.py: rute /_import/upload/mapare-coloane/preview/reset/confirma; helper _web_compute_preview refoloseste _resolve_row_for_preview, _already_sent_lookup, _signature din import_router (fara a-l edita); commit ON CONFLICT DO NOTHING (TOCTOU); log atestare - tests/test_import_ui.py: 15 teste (dashboard, upload, mapare, preview, confirmare N corect/gresit, reset, erori, multi-sheet, a11y D10/D11/D12) 279 teste total, 0 esecuri. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
58 lines
2.6 KiB
HTML
58 lines
2.6 KiB
HTML
{% extends "base.html" %}
|
|
{% block content %}
|
|
|
|
<!-- Sectiunea de import fisier: stare initiala = drop zone; HTMX swapeaza in flow -->
|
|
{% include '_upload.html' %}
|
|
|
|
<div class="card banner {% if not blocked %}hidden{% endif %}"
|
|
hx-get="/_fragments/banner" hx-trigger="every 15s" hx-swap="outerHTML">
|
|
<strong>Atentie:</strong> {{ blocked }} submission-uri blocate (error / needs_data / needs_mapping).
|
|
Plasa de siguranta pe pene RAR > 30h. Verifica coada mai jos.
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div style="display:flex; gap:24px; flex-wrap:wrap;">
|
|
<div><div class="muted">Worker</div><div class="{{ 's-sent' if worker_alive else 's-error' }}">
|
|
{{ 'viu' if worker_alive else 'mort' }}</div></div>
|
|
<div><div class="muted">RAR</div><div class="{{ 's-sent' if rar_state == 'ok' else 's-error' if 'indisponibil' in rar_state else 'muted' }}">{{ rar_state }}</div></div>
|
|
<div><div class="muted">Ultimul login RAR</div><div>{{ last_login or '—' }}</div></div>
|
|
<div><div class="muted">In coada</div><div>{{ counts.get('queued', 0) }}</div></div>
|
|
<div><div class="muted">Trimise</div><div class="s-sent">{{ counts.get('sent', 0) }}</div></div>
|
|
<div><div class="muted">Blocate</div><div class="{{ 's-error' if blocked else '' }}">{{ blocked }}</div></div>
|
|
</div>
|
|
{% if rar_state != 'ok' %}
|
|
<p class="muted" style="margin:12px 0 0; font-size:12px;">
|
|
RAR posibil indisponibil — coada de mai jos arata ultima stare cunoscuta (local), nu live din RAR.
|
|
</p>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- incarcat o data; NU poll (sa nu stergem o selectie in curs). Se re-randeaza la salvare. -->
|
|
<div hx-get="/_fragments/mapari" hx-trigger="load" hx-swap="outerHTML">
|
|
<div class="card"><div class="empty">se incarca mapari…</div></div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div style="display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:0 0 12px;">
|
|
<h2 style="font-size:15px; margin:0;">Coada submissions</h2>
|
|
<span style="margin-left:auto; display:flex; gap:8px; flex-wrap:wrap;">
|
|
<a class="cardlink" href="/v1/audit/export?status=sent" download>export CSV: trimise</a>
|
|
<a class="cardlink" href="/v1/audit/export?status=all" download>toate</a>
|
|
</span>
|
|
</div>
|
|
<div hx-get="/_fragments/submissions" hx-trigger="load, every 10s" hx-swap="innerHTML">
|
|
<div class="empty">se incarca…</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<details>
|
|
<summary style="cursor:pointer; font-size:15px; font-weight:600;">Nomenclator RAR (coduri prestatii)</summary>
|
|
<div style="margin-top:12px;" hx-get="/_fragments/nomenclator" hx-trigger="load" hx-swap="innerHTML">
|
|
<div class="empty">se incarca…</div>
|
|
</div>
|
|
</details>
|
|
</div>
|
|
|
|
{% endblock %}
|