feat(errors): erori pe 3 niveluri (problema+cauza+fix) pe API si UI (PRD 5.4)
Catalog central pur app/errors.py ca sursa unica cod->{problema,fix},
consumat de API+UI+worker. Aditiv (field/message pastrate la octet) +
rar_error stocat superset. Scope: fluxul de declarare; login/signup/CSRF
neatinse. labels.parse_erori degradeaza gratios; UI progresiv AA light+dark.
631 teste.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
36
app/web/templates/_eroare.html
Normal file
36
app/web/templates/_eroare.html
Normal file
@@ -0,0 +1,36 @@
|
||||
{#
|
||||
_eroare.html — macro card_erori(erori) (US-006, PRD 5.4).
|
||||
|
||||
Primeste o lista de dict-uri cu cheile: problema, cauza, fix, field (sau None).
|
||||
Afiseaza 3 niveluri intr-un bloc scannabil:
|
||||
- "Problema" (bold, --err)
|
||||
- "De ce" (doar daca ne-gol, --muted)
|
||||
- "Cum repari" (accentuat, --accent)
|
||||
|
||||
Nu hardcodeaza culori — foloseste variabilele CSS din paleta (base.html).
|
||||
Suporta light + dark din box (variabilele se schimba prin [data-theme]).
|
||||
#}
|
||||
|
||||
{% macro card_erori(erori) %}
|
||||
{% if erori %}
|
||||
<div class="eroare-3n">
|
||||
{% for e in erori %}
|
||||
<div class="eroare-3n-item{% if not loop.first %} eroare-3n-sep{% endif %}">
|
||||
<div class="eroare-3n-problema">
|
||||
{% if e.field %}<span class="eroare-3n-camp">{{ e.field }}</span> {% endif %}{{ e.problema }}
|
||||
</div>
|
||||
{% if e.cauza %}
|
||||
<div class="eroare-3n-cauza">
|
||||
<span class="eroare-3n-label">De ce:</span> {{ e.cauza }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if e.fix %}
|
||||
<div class="eroare-3n-fix">
|
||||
<span class="eroare-3n-label">Cum repari:</span> {{ e.fix }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
@@ -1,12 +1,17 @@
|
||||
<div id="import-section">
|
||||
{% set pas = 2 %}{% include '_stepper.html' %}
|
||||
{% from '_eroare.html' import card_erori %}
|
||||
<div class="card">
|
||||
<h2 style="font-size:15px; margin:0 0 12px;">
|
||||
Mapare coloane —
|
||||
<span class="muted" style="font-weight:400;">{{ filename or ("import #" ~ import_id) }}</span>
|
||||
</h2>
|
||||
|
||||
{% if message %}
|
||||
{% if eroare_mapare %}
|
||||
<div style="margin-bottom:12px;">
|
||||
{{ card_erori([eroare_mapare]) }}
|
||||
</div>
|
||||
{% elif message %}
|
||||
<div class="flash" style="{% if error %}border-color:var(--err); background:color-mix(in srgb, var(--err) 12%, var(--card));{% endif %} margin-bottom:12px;"
|
||||
{% if error %}role="alert"{% endif %}>
|
||||
{{ message }}
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
{%- set op = (prestatii[0].get('cod_prestatie') or prestatii[0].get('cod_op_service', '')) if prestatii else '' -%}
|
||||
{% if editing %}
|
||||
{%- set err_map = {} -%}
|
||||
{%- for e in row.errors -%}{%- if e is mapping and e.get('field') -%}{%- set _ = err_map.update({e.field: (e.get('message') or e.get('msg'))}) -%}{%- endif -%}{%- endfor -%}
|
||||
{%- set fix_map = {} -%}
|
||||
{%- for e in row.errors -%}{%- if e is mapping and e.get('field') -%}{%- set _ = err_map.update({e.field: (e.get('message') or e.get('msg'))}) -%}{%- if e.get('fix') -%}{%- set _ = fix_map.update({e.field: e.get('fix')}) -%}{%- endif -%}{%- endif -%}{%- endfor -%}
|
||||
<tr id="preview-row-{{ row.row_index }}" data-status="{{ status }}" data-editing="1">
|
||||
<td colspan="10" style="background:rgba(91,141,239,.06);">
|
||||
<form class="rand-editare"
|
||||
@@ -50,6 +51,9 @@
|
||||
{% if err_map.get(nume) %}
|
||||
<div class="s-error" style="font-size:12px; margin-top:2px;">{{ err_map.get(nume) }}</div>
|
||||
{% endif %}
|
||||
{% if fix_map.get(nume) %}
|
||||
<span class="camp-fix">{{ fix_map.get(nume) }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
@@ -83,13 +87,23 @@
|
||||
})();
|
||||
</script>
|
||||
{% else %}
|
||||
{%- set disp_fix_map = {} -%}
|
||||
{%- for e in row.errors -%}{%- if e is mapping and e.get('field') and e.get('fix') -%}{%- set _ = disp_fix_map.update({e.field: e.get('fix')}) -%}{%- endif -%}{%- endfor -%}
|
||||
<tr id="preview-row-{{ row.row_index }}" data-status="{{ status }}"
|
||||
style="{% if status == 'needs_review' %}background:rgba(230,179,74,.04);{% elif status in ('already_sent', 'duplicate_in_file') %}opacity:.65;{% endif %}">
|
||||
<td class="muted">{{ row.row_index + 1 }}</td>
|
||||
<td>{{ res.get('vin') or '<span class="muted">—</span>' | safe }}</td>
|
||||
<td>{{ res.get('nr_inmatriculare') or '' }}</td>
|
||||
<td>{{ res.get('data_prestatie') or '' }}</td>
|
||||
<td>{{ res.get('odometru_final') or '' }}</td>
|
||||
<td>{{ res.get('vin') or '<span class="muted">—</span>' | safe }}
|
||||
{% if disp_fix_map.get('vin') %}<span class="camp-fix">{{ disp_fix_map.get('vin') }}</span>{% endif %}
|
||||
</td>
|
||||
<td>{{ res.get('nr_inmatriculare') or '' }}
|
||||
{% if disp_fix_map.get('nr_inmatriculare') %}<span class="camp-fix">{{ disp_fix_map.get('nr_inmatriculare') }}</span>{% endif %}
|
||||
</td>
|
||||
<td>{{ res.get('data_prestatie') or '' }}
|
||||
{% if disp_fix_map.get('data_prestatie') %}<span class="camp-fix">{{ disp_fix_map.get('data_prestatie') }}</span>{% endif %}
|
||||
</td>
|
||||
<td>{{ res.get('odometru_final') or '' }}
|
||||
{% if disp_fix_map.get('odometru_final') %}<span class="camp-fix">{{ disp_fix_map.get('odometru_final') }}</span>{% endif %}
|
||||
</td>
|
||||
<td>{{ op or '<span class="muted">—</span>' | safe }}</td>
|
||||
<td><span class="pill s-{{ status }}">{{ status }}</span></td>
|
||||
<td class="muted" style="font-size:12px; white-space:normal; max-width:220px;">
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% from "_eroare.html" import card_erori %}
|
||||
<div class="card" id="detaliu-card-{{ id }}" style="border-color:var(--accent);">
|
||||
<div style="display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:0 0 12px;">
|
||||
<h2 style="font-size:15px; margin:0;">Detaliu trimitere #{{ id }}</h2>
|
||||
@@ -27,7 +28,11 @@
|
||||
<div><div class="muted" style="font-size:12px;">Urmatoarea incercare</div><div>{{ next_attempt_at }}</div></div>
|
||||
</div>
|
||||
|
||||
{% if motiv %}
|
||||
{% if erori_3n %}
|
||||
<div style="margin-top:12px; padding-top:10px; border-top:1px solid var(--line);">
|
||||
{{ card_erori(erori_3n) }}
|
||||
</div>
|
||||
{% elif motiv %}
|
||||
<div style="margin-top:12px; padding-top:10px; border-top:1px solid var(--line);">
|
||||
<div class="muted" style="font-size:12px;">Motiv</div>
|
||||
<div>{{ motiv }}</div>
|
||||
|
||||
@@ -2,13 +2,18 @@
|
||||
{% set pas = 1 %}{% include '_stepper.html' %}
|
||||
{# US-004 (3.6): bara de upload accentuata (border de accent) ca sa ramana punctul
|
||||
de intrare evident chiar cu tabelul Trimiteri lung dedesubt (D-1.1/D-5.2). #}
|
||||
{% from '_eroare.html' import card_erori %}
|
||||
<div class="card" style="border-color:var(--accent);">
|
||||
|
||||
{% if message %}
|
||||
<div class="flash" style="margin-bottom:12px;">{{ message }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if error %}
|
||||
{% if eroare_upload %}
|
||||
<div style="margin-bottom:12px;">
|
||||
{{ card_erori([eroare_upload]) }}
|
||||
</div>
|
||||
{% elif error %}
|
||||
<div class="flash" style="border-color:var(--err); background:color-mix(in srgb, var(--err) 12%, var(--card)); margin-bottom:12px;"
|
||||
role="alert">{{ error }}</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -103,6 +103,19 @@
|
||||
border-color:var(--line); border-bottom-color:var(--card); }
|
||||
.tab-panel { min-height:120px; }
|
||||
.status-bar { margin-bottom:12px; }
|
||||
/* Eroare 3 niveluri (US-006, PRD 5.4) */
|
||||
.eroare-3n { margin-top:10px; }
|
||||
.eroare-3n-item { padding:8px 10px; border-left:3px solid var(--err);
|
||||
background:color-mix(in srgb, var(--err) 8%, var(--card));
|
||||
border-radius:0 6px 6px 0; }
|
||||
.eroare-3n-sep { margin-top:6px; }
|
||||
.eroare-3n-problema { font-weight:600; color:var(--err); font-size:13px; }
|
||||
.eroare-3n-camp { font-family:monospace; font-size:12px; opacity:.85; }
|
||||
.eroare-3n-cauza { color:var(--muted); font-size:12px; margin-top:3px; }
|
||||
.eroare-3n-fix { color:var(--accent); font-size:12px; margin-top:3px; }
|
||||
.eroare-3n-label { font-weight:500; }
|
||||
/* Inline fix per camp in preview */
|
||||
.camp-fix { color:var(--accent); font-size:11px; margin-top:2px; display:block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user