feat: UI polish - dark default, version drift vs default release, humanized enums, failed-jobs layout, processing button hierarchy, PT-BR titles/CTAs

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
gti
2026-09-24 14:26:44 -03:00
co-authored by Claude Sonnet 5
parent 9a142975a6
commit c950ffb47f
18 changed files with 247 additions and 52 deletions
+38 -4
View File
@@ -1,3 +1,4 @@
from pathlib import Path
import re
from datetime import datetime, timedelta, timezone
@@ -85,7 +86,7 @@ def test_dashboard_renders_operational_queue_labels_and_human_dates():
assert "Produtos com blockers abertos" in response.text
assert "Blockers abertos" in response.text
assert "Atenção necessária" in response.text
assert "Ver todos" in response.text
assert "Ver blockers" in response.text
assert "Jobs com falha" in response.text
assert "Agents desatualizados" in response.text
assert not re.search(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}", response.text)
@@ -188,9 +189,9 @@ def test_dashboard_lists_bounded_failed_job_rows_with_identity_error_age_and_emp
response = client.get("/")
assert response.status_code == 200
assert "Acme" in response.text and "Acme ERP" in response.text and "srv-01" in response.text
assert "erro curto" in response.text and "Tipo / erro" in response.text and "Falhou" in response.text
assert "erro curto" in response.text and "Falhas recentes" in response.text and "Falhou" in response.text
assert 'href="/jobs?scope=active&amp;status=FAILED&amp;job_id=' in response.text
assert response.text.count("erro curto") == 10
assert response.text.count('class="error-text job-error-summary"') == 10 # bounded, one clamped summary per row
assert 'title="2026-09-22T18:05:11+00:00"' in response.text
assert ">22/09/2026 15:05<" in response.text
with factory() as session:
@@ -458,7 +459,8 @@ def test_agent_detail_reconciles_coverage_and_formats_missing_technical_fields()
assert "Desconhecida · Desconhecida" not in response.text
assert "ODS -" not in response.text
context = response.text.split("<h2>Contexto da empresa</h2>", 1)[1].split("</article>", 1)[0]
assert "Reprocessar tudo" in context
assert "Reprocessar tudo" not in context # the only reprocess action lives in the Processamento panel
assert response.text.count("Reprocessar tudo") == 1
assert not re.search(r"<(?:a|button)\b[^>]*>\s*</(?:a|button)>", context)
@@ -502,3 +504,35 @@ def test_agent_event_filters_lookahead_and_safe_event_reference_links_and_confir
assert f'href="/agents/{agent_id}"' in confirmation.text
assert client.post(f"/agents/{agent_id}/reprocess", data={"csrf_token": "wrong", "confirm": "yes"}).status_code == 403
assert client.post(f"/agents/{agent_id}/reprocess", data={"csrf_token": csrf, "confirm": "yes"}, follow_redirects=False).status_code == 303
def test_theme_defaults_to_dark_and_never_overrides_a_saved_choice():
client, _, _ = _panel_client()
base = client.get("/agents").text
# no saved preference -> dark; an explicit "claro" is the only thing that yields light
assert 'tema === "claro" ? "claro" : "escuro"' in base
assert "prefers-color-scheme" not in (Path(__file__).parents[1] / "static" / "tema.js").read_text(encoding="utf-8")
script = (Path(__file__).parents[1] / "static" / "tema.js").read_text(encoding="utf-8")
assert 'return "escuro"' in script and 'localStorage.setItem("tema", novo)' in script
for page in ("login.html", "logged_out.html", "sso_error.html"):
assert 'data-tema="escuro"' in (Path(__file__).parents[1] / "templates" / page).read_text(encoding="utf-8")
def test_operator_pages_use_portuguese_titles_and_consistent_ctas():
client, agent_id, _ = _panel_client()
assert "<title>Agents / Servidores | GTI Fiscal</title>" in client.get("/agents").text
assert "<title>Blockers | GTI Fiscal</title>" in client.get("/blockers").text
assert "<title>Jobs | GTI Fiscal</title>" in client.get("/jobs").text
dashboard = client.get("/").text
for old in ("Abrir fila", "Ver instalações", "Ver todos", "Ver job #"):
assert old not in dashboard
def test_agent_detail_processing_hierarchy_and_status_badges():
client, agent_id, _ = _panel_client()
page = client.get(f"/agents/{agent_id}").text
assert page.count("Reprocessar tudo") == 1
assert 'class="primary-action"' in page and 'class="botao secondary"' in page and 'class="caution"' in page
assert "Mantém o heartbeat, mas não executa jobs" in page and "Recalcula todos os produtos" in page
assert "Saúde técnica: " not in page and "Status fiscal: " not in page # context lives in the small label, not in the badge
assert '<small class="status-label">Saúde técnica</small>' in page