Melhorias de UI/UX no app (issue #36) - #37
Conversation
- botao "Validar" ganha um spinner (span .spinner) e o texto muda para "Validando..." assim que o formulario e submetido - botao fica desabilitado durante o envio, evitando duplo clique - listener em "pageshow" reseta o botao ao estado normal caso o usuario volte para a pagina pelo cache do navegador (bfcache), ja que nesse caso o JS nao roda de novo do zero - testado com Playwright (headless): estado normal, estado "Validando..." (via evento submit) e reset apos voltar, alem do fluxo real de upload+clique+redirect ponta a ponta Porque: a validacao de pacotes maiores demora e, sem nenhum feedback visual, a tela parece travada — primeiro item da issue scieloorg#36 (melhorias de UI/UX). A traducao da nova string "Validando..." fica para um commit posterior, junto com as demais strings novas da issue scieloorg#36, seguindo o mesmo padrao usado na issue scieloorg#34. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- introduz tokens de cor via CSS custom properties (--brand, --surface,
--border, --text, --critical/--success etc.), com vermelho de marca
(#da202c) no topo do cabecalho e nos botoes primarios
("Validar")
- cards (.panel) com sombra sutil e cabecalho com linha divisoria,
em vez de apenas uma borda cinza
- botoes (.button/.button-primary) e campos de formulario
(input/select) padronizados visualmente
- cabecalho de tabela (thead) com fundo sutil, texto em maiusculas e
hover nas linhas; tabelas envolvidas em .table-wrap (overflow-x:
auto) para nao vazar horizontalmente em telas estreitas
- nova classe .badge para status (usada no proximo commit, em
_history_list.html), com cores diferentes para "Valido" e
"Invalido/Erro"
- rodape fixado ao fim da coluna (margin-top: auto) e com estilo mais
discreto
Porque: segundo item da issue scieloorg#36 (melhorias de UI/UX) — o layout
anterior usava so bordas cinza padrao de navegador e passava uma
impressao de inacabado, mesmo sendo um app standalone/offline. A
paleta segue a mesma linguagem visual ja usada no template de
relatorio HTML da issue scieloorg#34 (ainda em outra branch/PR), para que as
duas telas fiquem consistentes quando integradas.
Testado visualmente com Playwright (headless): tela vazia e tela com
historico populado (pacote real), cobrindo cabecalho, cards, botoes,
badges de status e tabela.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…status
- <table> do historico envolvida em <div class="table-wrap"> para
rolagem horizontal segura em telas estreitas, sem estourar o layout
- texto do status ("Valido"/"Invalido"/"Erro") passa a ficar dentro
de <span class="badge">, que ganha aparencia de pilula colorida via
CSS ja definido em index.html
Porque: parte do segundo item da issue scieloorg#36 (melhorias de UI/UX);
mantem a estrutura e as colunas da tabela inalteradas, so aplica os
estilos introduzidos no commit anterior.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- _pdf_previews_by_article() passa a retornar "pdfs" (lista de
{filename, label}) em vez de "pdf_names" (lista de strings)
- nova _short_pdf_label(xml_stem, filename): remove o prefixo
repetido (o proprio xml_stem) de cada nome de arquivo, retornando
"PDF principal" para o arquivo sem sufixo e o sufixo restante (ex.
"suppl1") para os demais; cai no nome completo se o arquivo nao
seguir essa convencao
Porque: terceiro item da issue scieloorg#36 (melhorias de UI/UX) — a lista de
PDFs de um artigo mostra nomes de arquivo quase identicos (mesmo
prefixo longo, so muda o sufixo "-supplN"), dificultando diferencia-los
visualmente. O nome completo continua disponivel (usado como href e,
no proximo commit, como title/tooltip do link).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- novo CSS (.pdf-group, .pdf-list, .pdf-chip, .pdf-icon): cada PDF vira uma pilula compacta com icone de documento, fundo neutro e cor de texto secundaria, em vez de um link vermelho grande sublinhado ocupando uma linha inteira - cor propositalmente neutra (nao usa --brand): a lista pode ter varios itens por linha do historico, entao reserva o vermelho de marca para acoes primarias e mantem esses links discretos Porque: parte do terceiro item da issue scieloorg#36 (melhorias de UI/UX); complementa o rotulo curto do commit anterior — sem esse estilo, os rotulos como "suppl1"/"suppl2" ficavam soltos e ainda dificeis de escanear visualmente como itens separados. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- coluna PDF passa a iterar group.pdfs (filename + label) em vez de group.pdf_names (strings), usando pdf.label como texto visivel e pdf.filename no href e no atributo title (nome completo disponivel via tooltip ao passar o mouse) - cada item usa a classe .pdf-chip com um icone SVG de documento inline, estilizados no commit anterior Porque: fecha o terceiro item da issue scieloorg#36 (melhorias de UI/UX). Testado com Playwright contra o pacote real usado nos itens anteriores: rotulos "suppl1".."suppl5" e "PDF principal" no lugar dos nomes completos, com o nome de arquivo real ainda acessivel via title/href. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- nova _format_validated_at(): faz o parse do "validated_at" (gravado via datetime.now(UTC).isoformat(), que inclui microssegundos) e reformata com timespec="seconds" - aplicada a cada item em _paginated_history(), antes de passar pro template; em caso de valor invalido, mantem o original (fallback silencioso, sem afetar a listagem) Porque: quarto item da issue scieloorg#36 (melhorias de UI/UX) — a coluna Data mostrava "2026-07-30T21:34:36.960044+00:00", com microssegundos que nao tem nenhuma utilidade pra quem esta lendo a tabela e so poluem a linha. O valor gravado no banco continua com precisao total; so a exibicao foi ajustada. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- redirect de sucesso de validate() passa a repassar os parametros
atuais da querystring (q, status, page_size, page) pro
url_for("web.index", ...), usando "or None" pra nao poluir a URL
com parametros vazios quando nao estao presentes
Porque: quinto item da issue scieloorg#36 (melhorias de UI/UX) — configurar
"itens por pagina" pra 5, buscar por nome ou navegar pra outra pagina
funcionava corretamente, mas ao clicar em "Validar" o redirect sempre
levava de volta a "/?history_id=...", sem nenhum desses parametros, e
a lista voltava pro padrao (25 itens, sem filtro, pagina 1). O
proximo commit (index.html) faz o formulario de validacao enviar a
querystring atual, que e o que este trecho agora repassa adiante.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- ao submeter #validate-form, se window.location.search nao estiver vazio, o "action" do formulario passa a ser "/validate" + essa querystring (ex.: "/validate?page_size=5&page=2") - window.location.search ja reflete o filtro/paginacao atual porque bindLiveHistoryFilters() usa history.replaceState a cada mudanca Porque: index.html e web/routes.py juntos fecham o quinto item da issue scieloorg#36. O POST em si continua indo pro mesmo endpoint; so a querystring anexada e o que routes.py le (request.args) pra decidir com quais q/status/page_size/page redirecionar depois de validar. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- nova _page_range(page, total_pages, window=2): retorna os numeros de pagina ao redor da pagina atual (ate 2 pra cada lado, recortado aos limites [1, total_pages]) - _paginated_history() passa "page_range" pro contexto do template Porque: sexto item da issue scieloorg#36 (melhorias de UI/UX) — trocar a paginacao simples (so "Anterior"/"Proxima") por uma no estilo Django ("Anterior | 10 | 11 | 12 | Proxima"), pedida explicitamente no feedback. A marcacao que consome isso vem no proximo commit. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- substitui o rodape "Anterior/Proxima" por uma <nav class="pagination"> com Anterior | numeros de pagina (page_range) | Proxima - pagina atual exibida como <span> (nao clicavel, destacada); Anterior e Proxima tambem viram <span> desabilitado nas pontas da lista - reaproveita a classe "page-link" e o atributo data-page ja usados pela delegacao de evento existente em bindLiveHistoryFilters() no index.html — nenhuma mudanca de JS foi necessaria Porque: fecha o sexto item da issue scieloorg#36 (melhorias de UI/UX). Testado com Playwright (page_size=3 pra forcar varias paginas): janela de paginas corrige corretamente ao navegar, tanto pelo link <a> quanto pela atualizacao via AJAX (fetch em /history-list). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- novo CSS pra .pagination/.pagination-links/.page-link: pilulas compactas, pagina atual em vermelho de marca (.page-link-current), Anterior/Proxima desabilitados em cinza claro (.page-link-disabled) - ".page-link" com maior especificidade que o "a" global evita que o vermelho de link padrao vaze pros numeros de pagina nao-atuais Porque: complementa a marcacao do commit anterior (issue scieloorg#36, sexto item) — sem esse CSS os numeros de pagina ficariam sem distincao visual entre "atual" e "clicavel". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- _load_version() ja distinguia "rodando do codigo-fonte" (pyproject.toml presente ao lado do pacote) de "build empacotado" (PyInstaller, sem pyproject.toml) pra decidir se confia em build_info.py; essa checagem vira a funcao publica is_running_from_source(), sem mudar o comportamento de _load_version() Porque: primeiro passo do setimo item da issue scieloorg#36 (melhorias de UI/UX, "Built for mac" aparecendo no Linux) — o proximo commit (build_metadata.py) reusa essa mesma checagem, que ja existia e resolvia exatamente esse problema pra APP_VERSION mas nao era aplicada ao rodape. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…onte - get_footer_build_label() so considera BUILD_MACOS_VERSION/BUILD_PLATFORM de build_info.py quando NAO esta rodando a partir do codigo-fonte (is_running_from_source() da version.py); do contrario cai direto na deteccao por platform.system(), como ja acontecia pra qualquer plataforma diferente de macOS Porque: setimo item da issue scieloorg#36 (melhorias de UI/UX) e tambem a causa raiz da issue scieloorg#32. spsvalidator/src/spsvalidator/build_info.py e gerado por packaging/generate_build_info.sh e commitado no repo com os valores da ultima vez que alguem rodou o build empacotado num Mac ("BUILD_PLATFORM = macOS"); quem roda o app direto do codigo-fonte (pip install -e . + spsvalidator --browser/--desktop) nunca chama esse script, entao o rodape sempre mostrava "Compilado para macOS ..." mesmo em Linux/Windows, e continuaria mostrando isso ate alguem rodar um build real naquela plataforma. Verificado manualmente: get_footer_build_label() retorna "Build de desenvolvimento (Linux)" neste ambiente apos a correcao. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- as duas secoes que antes eram paineis separados (historico embaixo, artigos considerados por ultimo) viram abas dentro de um unico painel: "Artigos Considerados" e "Pacotes validados" - quando ha latest_result (apos validar ou clicar na data de um item do historico), a aba "Artigos Considerados" comeca ativa/visivel; sem latest_result, so existe o conteudo do historico e nenhuma aba e exibida (comportamento igual ao anterior) - troca de aba em JS puro (bindTabs()): alterna aria-selected nos botoes e o atributo hidden dos paineis, sem requisicao ao servidor - estilo novo (.tabs/.tab/.tab-panel) seguindo a mesma linguagem visual (vermelho de marca na aba ativa) Porque: nono e ultimo item pendente da issue scieloorg#36 (melhorias de UI/UX) — antes, "Artigos Considerados" era renderizado depois da tabela de historico inteira (ate 25 itens por padrao), entao quem validava um pacote ou clicava na data de um item precisava rolar a pagina inteira pra ver os detalhes. Com abas, o conteudo relevante fica visivel imediatamente, sem rolagem, e o historico continua a um clique de distancia. Testado com Playwright: fluxo real de upload+validar (aba "Artigos Considerados" ativa sem rolagem), troca pra aba "Pacotes validados" e de volta, e o caso sem historico selecionado (sem abas, comportamento inalterado). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- renomeia .pdf-chip/.pdf-icon/.pdf-group/.pdf-list (introduzidos no terceiro item da issue scieloorg#36, so pra PDF) pra .chip-link/.chip-icon/ .action-group/.chip-list, sem mudar a aparencia - nova .actions: container vertical que vai agrupar os chips de CSV, HTML e PDF numa unica coluna (proximo commit) Porque: primeiro passo do oitavo e ultimo item da issue scieloorg#36 (melhorias de UI/UX) — consolidar as colunas "Validacao" (download de CSV), "HTML" e "PDF" numa unica coluna "Acoes". O estilo de chip ja existia pra PDF; renomear pra generico evita duplicar CSS quando HTML e o botao de CSV passarem a usar o mesmo padrao visual. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- as 3 colunas ("Validação" com o link de CSV, "HTML", "PDF") viram
uma so coluna "Ações", com todos os links renderizados como
.chip-link dentro de um container .actions
- corrige de passagem o rotulo do link de CSV: era "Relatório" (texto
herdado de antes de existir uma pagina de relatorio separada nesta
branch) com aria-label "Baixar relatório de %(name)s"; agora o
texto visivel e "CSV" e o aria-label vira "Baixar CSV de %(name)s",
condizente com o que o link realmente faz (dispara download_csv)
- cada chip ganha um icone (download pro CSV, "olho" pro preview
HTML, documento pro PDF, este ultimo ja existente) pra diferenciar
o tipo de acao visualmente dentro da coluna unica
- classe "csv-download" mantida no link de CSV (bindCsvDownloads() em
index.html continua funcionando sem alteracao)
Porque: fecha o oitavo e ultimo item da issue scieloorg#36 (melhorias de
UI/UX) — three colunas de acao lado a lado ocupavam bastante largura
e nao deixavam claro que eram todas "coisas que voce pode fazer com
esta validacao". Testado com Playwright: cabecalho unico "Ações",
download de CSV ainda dispara corretamente (mesmo arquivo, mesmo
feedback visual), chips de HTML/PDF lado a lado com quebra de linha.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- adiciona ao catalogo pt/en/es as 8 strings introduzidas pelos commits desta branch: "Validando...", "Ações", "Baixar CSV de %(name)s", "Baixar CSV", "CSV", "Pré-visualização HTML", "PDF principal" e "Paginação" - remove o msgid "Relatório" (ligado ao antigo link de download de CSV, cujo texto virou "CSV" no commit que consolidou as colunas de acao); nao ha mais nenhuma referencia a ele no codigo - pt fica com msgstr vazio (idioma fonte, como as demais entradas do catalogo); en e es traduzidos manualmente - .mo recompilados com pybabel compile Isolamento: a diff foi construida comparando um dump de .pot extraido desta branch contra um dump equivalente extraido de "main" (mesmos arquivos, so routes.py/index.html/_history_list.html/build_metadata.py/ version.py), pra pegar so o que estas mudancas introduziram — nao um "pybabel update" cru, que teria reformatado o arquivo inteiro e puxado dezenas de strings que ja estavam faltando nos catalogos antes desta branch (ex.: "HTML"/"PDF"/status labels/paginacao antiga do historico, nunca extraidos desde que foram adicionados em PRs anteriores). Esse debt de i18n pre-existente continua sem tradução, deliberadamente fora do escopo deste commit. Porque: fecha o lote de traducao da issue scieloorg#36 (melhorias de UI/UX), seguindo o mesmo padrao usado no commit db1d5ea da issue scieloorg#34. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
# Conflicts: # spsvalidator/src/spsvalidator/translations/en/LC_MESSAGES/messages.po # spsvalidator/src/spsvalidator/translations/es/LC_MESSAGES/messages.po # spsvalidator/src/spsvalidator/translations/pt/LC_MESSAGES/messages.po # spsvalidator/src/spsvalidator/web/templates/_history_list.html
- Substitui o cabecalho simples por header com marca (circulo com "S"), eyebrow "SciELO · <nome do app>", titulo do pacote e acoes em botoes (Historico, CSV, Limpar marcacoes). - Adiciona cards de resumo (total, contagem por gravidade, corrigidas) com barra de progresso segmentada por gravidade logo abaixo. - Adiciona toolbar com filtro por gravidade (botoes "Todos"/CRITICAL/ ERROR/WARNING/...) e busca por texto livre, que soma/oculta categorias e ocorrencias via atributos data-search-text calculados no proprio Jinja (mensagem + acao de correcao + detalhes tecnicos). - Troca a paleta neutra (Arial puro, sem cor de marca) pelas variaveis de tema (--brand #da202c e derivadas, --critical/--error/--warning/ --success) usadas tanto no cabecalho quanto nas secoes de gravidade, categorias e ocorrencias (chevrons, field-label colorido, contadores monoespacados). - Mantem intacta a logica de checklist ja existente (checkbox por ocorrencia e por grupo, localStorage por history_id, botao "Limpar marcacoes"), so adaptando os seletores as novas classes. Porque: a issue scieloorg#36 pediu CSS mais cuidado com identidade visual do SciELO no app geral, mas o relatorio ficou de fora do escopo original porque so existia no PR scieloorg#35 (issue scieloorg#34), ainda nao mesclado. Com o merge de main nesta branch, apareceu a oportunidade - e a comparacao direta com o mockup de referencia (compartilhado localmente, nao versionado) mostrou que o relatorio simples nao correspondia ao que foi pedido. Estrutura de dados (grouped_report, occurrence.key/advise/ details) e rotas do backend nao mudaram - e so template, CSS, JS e traducao. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JMzp8hGLSHNcMaNPCZSf5h
- Roda pybabel extract/update e traduz para en/es as 9 strings introduzidas pela reconstrucao visual do relatorio HTML: "Historico", "Acoes do relatorio", "Resumo do relatorio", "Total de ocorrencias", "Filtrar por gravidade", "Todos (%(count)s)", "Buscar no relatorio", "Buscar problema, acao ou detalhe" e "Nenhum resultado para os filtros atuais.". - O merge de main trouxe tambem strings do PR scieloorg#35 (ex.: "Relatorio", "Pacote", "Gravidade") que o pybabel update tentou casar por similaridade (fuzzy matching) com strings ja existentes - duas ficaram erradas ("Validando..." virou "Validate", "Baixar CSV de %(name)s" virou "Download CSV of %(name)s") e foram corrigidas aqui para o texto correto ja usado antes do merge. Nao mexido (fora do escopo): duas strings ja tinham traducao errada em en *antes* deste merge, herdada do main/PR scieloorg#35 - "Valido" e "Limpar" ambas com msgstr "Validate" - registrado para uma issue de i18n futura, nao corrigido aqui pra nao misturar com o trabalho desta branch. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JMzp8hGLSHNcMaNPCZSf5h
pitangainnovare
left a comment
There was a problem hiding this comment.
Sugiro alguns pontos:
A) Inverter as tabs e colocar termo menor, ou seja:
Mostrar
Pacotes | Artigos
Em lugar de
Pacotes validados | Artigos Considerados
B) Apresentar o valor da data de maneira mais amigável
Mostrar
2026-07-31 13:47:00
Em lugar de
2026-07-31T13:47:00+00:00
C) Pode ocorrer rótulo incorreto para PDFs com prefixo semelhante, pois _short_pdf_label() considera qualquer nome iniciado por xml_stem como um PDF relacionado por sufixo. Por exemplo, xml_stem="art" e filename="article.pdf" resultam no rótulo icle. O encurtamento deveria ocorrer apenas quando houver um separador - ou _; caso contrário, deve manter o nome completo. (CONFIRMAR com a Roberta)
D) O termo ``Compilado para macOS'' ainda aparece em builds Linux/Windows. Quando o app está empacotado, is_running_from_source() retorna `False` e o código confia no `build_info.py`, que contém valores estáticos de macOS. Como os scripts de build para Linux e Windows não regeneram esse arquivo, os binários dessas plataformas continuam exibindo incorretamente “Compilado para macOS”.
| @@ -80,11 +113,6 @@ msgstr "" | |||
| msgid "Exceptions" | |||
| msgstr "" | |||
There was a problem hiding this comment.
Vamos traduzir esse termo também?
| @@ -80,11 +113,6 @@ msgstr "" | |||
| msgid "Exceptions" | |||
| msgstr "" | |||
There was a problem hiding this comment.
Vamos traduzir esse termo também?
- Adiciona a chamada a `generate_build_info.sh` em `build_linux.sh`, igual ao que `build_macos.sh` já fazia. Porque: `build_info.py` e um arquivo estatico versionado com valores de macOS (BUILD_PLATFORM = "macOS"). Como `build_linux.sh` nunca regenerava esse arquivo antes de empacotar, o binario Linux herdava o conteudo commitado e o rodape da aplicacao continuava exibindo "Compilado para macOS" mesmo rodando em Linux. `generate_build_info.sh` ja tratava corretamente plataformas nao-Darwin (grava BUILD_PLATFORM real via `uname -s` e BUILD_MACOS_VERSION = "development"); so faltava ser chamado nesse script. Causa raiz identificada durante a review do PR scieloorg#37 (pitangainnovare) e relacionada a issue scieloorg#32. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YThTF9o31pFcaYTS6MnhLP
…orico
- `_short_pdf_label()`: so encurta o nome do PDF quando o caractere
logo apos o `xml_stem` for "-" ou "_"; caso contrario mantem o nome
completo do arquivo.
- `_format_validated_at()`: troca `isoformat(timespec="seconds")` por
`strftime("%Y-%m-%d %H:%M:%S")`.
Porque: `_short_pdf_label()` tinha um bug de fronteira de string —
`stem.startswith(xml_stem)` e verdadeiro pra qualquer nome de arquivo
que comece com o stem, mesmo sem separador. Com `xml_stem="art"` e
`filename="article.pdf"`, o corte gerava o rotulo errado "icle" em vez
do nome completo. `_format_validated_at()` ainda expunha o "T" do ISO
8601 e o offset "+00:00" (o timespec="seconds" so removia os
microssegundos), o que e ruido pra leitura na tabela de historico; o
valor gravado continua em UTC, so sem indicar o timezone
explicitamente. Ambos os pontos foram levantados na review do PR scieloorg#37
(pitangainnovare).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YThTF9o31pFcaYTS6MnhLP
- Troca `_("Exceptions")` por `_("Exceções")` no cabecalho da tabela
de historico.
Porque: a review do PR scieloorg#37 (pitangainnovare) apontou que o termo
aparecia sem traducao tanto no catalogo pt quanto no es. A causa nao
era falta de traducao em es — era o msgid de origem estar em ingles
por engano, diferente das colunas vizinhas ("Ações", "Relatório"), que
ja nascem em pt-BR. Alinhar o msgid ao idioma-fonte do app resolve os
dois comentarios de uma vez: pt continua com msgstr vazio (convencao
ja usada no resto do catalogo) e en/es passam a ter uma traducao
explicita de verdade.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YThTF9o31pFcaYTS6MnhLP
- Rotulos das abas: "Artigos Considerados"/"Pacotes validados" viram "Artigos"/"Pacotes". - Ordem visual invertida: "Pacotes" aparece antes de "Artigos". Porque: rotulos mais curtos foram sugeridos na review do PR scieloorg#37 (pitangainnovare); a ordem foi invertida depois, a pedido do usuario durante a validacao manual da tela. A aba "Artigos" continua selecionada por padrao (`aria-selected="true"`) pra preservar o comportamento do item 9 da issue scieloorg#36 — o resultado da validacao fica visivel imediatamente apos validar um pacote, sem precisar trocar de aba; so a posicao visual dos botoes mudou. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YThTF9o31pFcaYTS6MnhLP
- msgid "Exceptions" -> "Exceções" (coluna do historico). - msgid "Artigos Considerados" -> "Artigos" (aba). - Nova entrada msgid "Pacotes" (aba), referenciando index.html:335. Porque: pt e o idioma-fonte do catalogo (msgstr fica vazio em todas as entradas, o proprio msgid ja e o texto exibido), entao esse commit so acompanha as mudancas de msgid feitas em `_history_list.html` e `index.html` nesta mesma leva de correcoes da review do PR scieloorg#37. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YThTF9o31pFcaYTS6MnhLP
- msgid "Exceções" -> msgstr "Exceptions". - msgid "Artigos" -> msgstr "Articles" (era "Articles Considered"). - Nova entrada msgid "Pacotes" -> msgstr "Packages". Porque: acompanha a mudanca de msgid feita em `_history_list.html` (coluna de excecoes, que estava sem traducao explicita em ingles) e a mudanca de rotulo das abas em `index.html`, apontadas na review do PR scieloorg#37 (pitangainnovare). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YThTF9o31pFcaYTS6MnhLP
- msgid "Exceções" -> msgstr "Excepciones" (antes "Exceptions", sem traducao pro espanhol). - msgid "Artigos" -> msgstr "Artículos" (era "Artículos Considerados"). - Nova entrada msgid "Pacotes" -> msgstr "Paquetes". Porque: resolve diretamente o comentario da review do PR scieloorg#37 (pitangainnovare) perguntando se "Exceptions" devia ser traduzido no catalogo es, e acompanha a mudanca de rotulo das abas em `index.html`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YThTF9o31pFcaYTS6MnhLP
pitangainnovare
left a comment
There was a problem hiding this comment.
Entendo que faz sentido ajustar só mais duas coisas:
- As abas deveriam representar listas consistentes: atualmente, “Articles” só aparece como detalhe do último pacote selecionado. Sugiro manter “Packages | Articles” sempre visíveis e fazer “Articles” listar todos os snapshots, ordenados pela data da validação — mais recentes primeiro — com as colunas adicionais “Data da validação” e “Pacote”. Ao clicar em um pacote, a interface deveria abrir “Articles” com history_id como filtro ativo, indicando claramente o pacote selecionado e permitindo remover o filtro, o que então passaria a mostrar todos os articles de todos os pacotes. A estrutura atual já suporta isso por meio de um JOIN entre package_article_snapshot e package_validation_history, sem necessidade de migração do banco. Então, precisaria colocar filtros na aba Articles (package, doi, pid, status, etc, veja o que é relevante).
- O build Windows ainda usa metadados estáticos de macOS:
build_windows.ps1deveria gerarbuild_info.pyantes do PyInstaller, preenchendoAPP_VERSIONa partir depyproject.toml,BUILD_PLATFORM = "Windows"eBUILD_MACOS_VERSION = "development". Recomendo também validarplatform.system() == "Darwin"antes de exibir os metadados de macOS, evitando que um arquivo antigo volte a produzir um rodapé incorreto. Idealmente, essa geração deveria ser movida para um script Python multiplataforma compartilhado pelos builds de macOS, Linux e Windows.
Referência para o detalhe 1
Poderia ser sempre assim:
Referência para o detalhe 2
A solução correta tem duas camadas:
- Gerar
build_info.pydurante o build Windows. - Impedir defensivamente que metadados de macOS sejam usados fora do macOS.
No build_windows.ps1, antes do PyInstaller:
$BuildInfoPath = Join-Path $RootDir "src\spsvalidator\build_info.py"
$AppVersion = python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])"
@"
APP_VERSION = "$AppVersion"
BUILD_MACOS_VERSION = "development"
BUILD_PLATFORM = "Windows"
"@ | Set-Content -Path $BuildInfoPath -Encoding UTF8E em build_metadata.py:
if (
platform.system() == "Darwin"
and not is_running_from_source()
and build_info.BUILD_MACOS_VERSION != "development"
and build_info.BUILD_PLATFORM == "macOS"
):- Adiciona `platform.system() == "Darwin"` a condicao que decide se mostra "Compilado para macOS", alem das checagens ja existentes (is_running_from_source, BUILD_MACOS_VERSION, BUILD_PLATFORM). Porque: build_info.py e um arquivo estatico que pode ficar desatualizado (ex.: herdado de um build anterior de outra plataforma, como aconteceu com Linux antes do fix fcc8075). Sem essa checagem extra, um build_info.py com BUILD_PLATFORM="macOS" faria o rodape mentir sobre a plataforma real sempre que o script de empacotamento de uma nova plataforma esquecer de regenerar o arquivo - exatamente o padrao de bug ja visto duas vezes. Apontado na 2a rodada de review do PR scieloorg#37 (pitangainnovare). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015N4tShpu6YUfgyPJR1PKnD
- Porta pro PowerShell a mesma logica de generate_build_info.sh: le a versao do pyproject.toml via tomllib e grava build_info.py com BUILD_PLATFORM = "Windows" e BUILD_MACOS_VERSION = "development". Porque: build_windows.ps1 nunca gerava um build_info.py real, entao o binario Windows empacotava o arquivo estatico versionado no repo (com valores de macOS) e exibia "Compilado para macOS" incorretamente - mesmo bug ja corrigido no Linux (fcc8075), agora tambem no Windows. Apontado na 2a rodada de review do PR scieloorg#37 (pitangainnovare). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015N4tShpu6YUfgyPJR1PKnD
- Adiciona a chamada a generate_build_info.ps1 antes do pyinstaller, no mesmo ponto em que build_linux.sh/build_macos.sh chamam o script equivalente em bash. Porque: sem essa chamada, o build_info.py gerado pelo script anterior nunca chega a ser usado - ver commit anterior pro contexto completo do bug. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015N4tShpu6YUfgyPJR1PKnD
- 3 testes: rodape correto quando roda em macOS de verdade, rodape ignora build_info.py com BUILD_PLATFORM="macOS" quando platform.system() nao e Darwin, e modo de desenvolvimento. Porque: fixa em teste o comportamento da checagem defensiva adicionada no commit anterior, pra nao regredir se alguem mexer nessa funcao no futuro sem se dar conta do bug que ela previne. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015N4tShpu6YUfgyPJR1PKnD
- Novas funcoes espelhando list_validations/count_validations, mas com JOIN entre package_article_snapshot e package_validation_history; filtros por nome de pacote, doi, pid, status do artigo e history_id. - get_package_name(): lookup simples pra exibir o nome do pacote quando a aba de Artigos estiver filtrada por history_id. Porque: primeiro passo pra atender a 2a rodada de review do PR scieloorg#37 (pitangainnovare) - a aba "Artigos" precisa listar todos os snapshots de artigos, nao so os do ultimo pacote selecionado, com filtros proprios. O schema ja suporta isso sem migracao (history_id ja e chave estrangeira em package_article_snapshot). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015N4tShpu6YUfgyPJR1PKnD
- Testes de join com nome/data do pacote, filtro por history_id, nome de pacote, doi, pid, status, paginacao (limit/offset) e contagem. Porque: fixa em teste o comportamento das funcoes adicionadas no commit anterior antes de conecta-las as rotas. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015N4tShpu6YUfgyPJR1PKnD
…t_result
- Nova `_paginated_articles()` (mesmo padrao de `_paginated_history()`),
endpoint `/articles-list` pra paginacao/filtro via AJAX, parametros
de querystring com prefixo `article_` pra nao colidir com os do
historico de pacotes (q/status/page/page_size).
- `index()` simplificado: nao usa mais get_validation_details/
latest_result pra decidir o que mostrar; so calcula `default_tab`
("articles" quando history_id esta na query, "history" caso
contrario) - a aba Artigos passa a ser sempre calculada e sempre
disponivel.
- `history_id` na querystring agora e um filtro da aba Artigos (via
_paginated_articles), nao mais um gatilho pra carregar um pacote
especifico.
- Redirect apos validar preserva tambem os parametros article_* (mesma
logica ja aplicada a q/status/page/page_size).
Porque: pedido explicito da 2a rodada de review do PR scieloorg#37
(pitangainnovare) - "Articles" deve sempre listar todos os snapshots
(JOIN ja existente, sem migracao), ordenados por data, e ao clicar num
pacote deve abrir Artigos filtrado por history_id, com filtro
removivel.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015N4tShpu6YUfgyPJR1PKnD
- Espelha _history_list.html: tabela com pacote/data/xml/titulo/ autores/doi/pid/status, paginacao numerada, mensagem de "nenhum artigo encontrado" sensivel aos filtros ativos, e chip "Filtrando por pacote: X" com link "Limpar filtro" quando history_id esta setado. Porque: parte do redesenho da aba Artigos pedido na 2a rodada de review do PR scieloorg#37; usado tanto no carregamento inicial de `/` quanto no endpoint `/articles-list` (AJAX), igual ao papel de _history_list.html pro historico de pacotes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015N4tShpu6YUfgyPJR1PKnD
… artigos
- Remove o gate `{% if latest_result %}` que escondia as abas e o
conteudo de Artigos quando nenhum pacote estava selecionado; a aba
ativa por padrao agora vem de `default_tab` (calculado nas rotas).
- Adiciona formulario de filtro da aba Artigos (pacote/doi/pid/status/
itens por pagina), espelhando o formulario ja existente pro
historico de pacotes.
- Generaliza `bindLiveHistoryFilters()` em `bindLiveFilters(config)`,
reaproveitado pras duas abas; corrige o bug de `window.history.
replaceState` sobrescrever a querystring inteira em vez de mesclar -
cada bloco agora parte de `new URLSearchParams(window.location.
search)` e so altera os proprios campos, entao filtrar/paginar numa
aba nao apaga o estado da outra na URL.
- Adiciona estilos `.status-ok`/`.status-issue` (badges da aba Artigos)
e `.active-filter` (chip de filtro por pacote).
Porque: fecha a 2a rodada de review do PR scieloorg#37 (pitangainnovare) -
"Articles" precisa ser uma lista sempre visivel e completa, nao um
detalhe do ultimo pacote validado. Testado com Playwright headless
contra dados reais (filtro por nome/doi/pid/status, clique em pacote,
limpar filtro, preservacao cruzada de querystring entre as abas) -
screenshots conferidos visualmente antes deste commit.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015N4tShpu6YUfgyPJR1PKnD


O que esse PR faz?
Implementa os 9 itens de UI/UX listados na issue #36, a partir de feedback de usabilidade recebido sobre o app (originalmente fora do escopo do relatório de validação, que é a issue #34/PR #35):
is_running_from_source()nova emversion.py, reaproveitada embuild_metadata.py).Atualização depois do merge de
main(PR #35 já mesclado): o relatório HTML (report.html), que veio pronto do PR #35 com um layout simples (Arial puro, sem cor de marca), foi reconstruído nesta branch com a mesma identidade visual usada no restante do app — cabeçalho com marca, cards de resumo por gravidade, barra de progresso, filtro por gravidade e busca por texto livre. A estrutura de dados e as rotas do backend não mudaram, só template/CSS/JS/tradução. A coluna "Ações" (item 5) também passou a incluir o chip "Relatório" nesta atualização.Atualização depois da 2ª rodada de review (pitangainnovare):
build_windows.ps1nunca gerava umbuild_info.pyreal (diferente debuild_linux.sh/build_macos.sh), então o binário Windows empacotava o arquivo estático versionado no repo (com valores de macOS) e exibia "Compilado para macOS" incorretamente. Criadogenerate_build_info.ps1(porta pro PowerShell a mesma lógica do script.shequivalente) e adicionada a chamada embuild_windows.ps1. Além disso,get_footer_build_label()ganhou uma checagem defensiva extra (platform.system() == "Darwin"), pra não confiar cegamente numbuild_info.pydesatualizado se algum build futuro esquecer de regenerá-lo — o mesmo padrão de bug já apareceu duas vezes (Linux, depois Windows).package_article_snapshotepackage_validation_history, sem necessidade de migração), com paginação e filtros próprios (pacote, DOI, PID, status), ordenados por data de validação. Clicar num pacote na aba "Pacotes" abre a aba "Artigos" já filtrada por aquelehistory_id, com um chip "Filtrando por pacote: X" e um link para remover o filtro. Novo endpointGET /articles-listserve essa listagem via AJAX (mesmo padrão já usado por/history-list).Inclui também tradução (en/es) das strings novas introduzidas por todos esses itens.
Onde a revisão poderia começar?
spsvalidator/src/spsvalidator/web/routes.py—_paginated_articles()/_paginated_history(), endpoint/articles-list,index()simplificado (default_tabem vez delatest_result).spsvalidator/src/spsvalidator/db/repository.py—list_articles/count_articles/get_package_name, novos, com testes emtests/test_articles_repository.py.spsvalidator/src/spsvalidator/web/templates/index.html— abas sempre visíveis, formulário de filtro da aba Artigos, JS generalizado (bindLiveFilters) reaproveitado pelas duas abas.spsvalidator/src/spsvalidator/web/templates/_articles_list.html— novo, espelha_history_list.html.spsvalidator/src/spsvalidator/build_metadata.pyespsvalidator/packaging/generate_build_info.ps1/build_windows.ps1— fix do rodapé no build Windows, com testes emtests/test_build_metadata.py.spsvalidator/src/spsvalidator/web/templates/report.html— reconstrução visual do relatório, reaproveitando os dados debuild_grouped_reportjá existentes.Como este poderia ser testado manualmente?
spsvalidator --browsere validar um pacote SPS real.Algum cenário de contexto que queira dar?
Feedback qualitativo recebido de um colega de equipe sobre a impressão de qualidade do app, focado em pontos que "custam pouco e pesam na percepção de acabamento" — inclusive uma comparação direta com um mockup de referência do relatório HTML, que motivou a reconstrução visual descrita acima. Cada item foi implementado e testado individualmente (Playwright headless) antes de avançar para o próximo, incluindo os itens endereçados na 2ª rodada de review.
Esta branch partiu de
mainantes do PR #35 ser mesclado; depois que o PR #35 foi integrado aomaindo upstream, fiz merge demainnesta branch e resolvi os conflitos (esperados) em_history_list.htmle nos catálogos de tradução — a coluna "Relatório" do PR #35 foi incorporada dentro do.actions/.chip-linkjá existente aqui, em vez de ficar em coluna separada.Screenshots
Quais são os tickets relevantes?
Closes #36. Relacionado a #32 (rodapé "Built for macOS" estático) e #34/#35 (relatório HTML, já mesclado e reconstruído visualmente aqui).
Referências
Feedback de UI/UX recebido informalmente da equipe.
Segurança da informação (NSI.04)
Este PR manipula dados sensíveis ou pessoais (LGPD)?
Este PR altera autenticação, autorização, controle de acesso ou gerenciamento de sessão?
Este PR introduz, atualiza ou remove dependências de terceiros?
Este PR foi validado pelo pipeline de segurança (SonarQube / Trivy)?
Este PR concatena, monta ou executa comandos SQL, HTML ou JavaScript a partir de entrada externa?
|safe); os filtros novos da aba Artigos (pacote/doi/pid/status) são usados em SQL sempre via parâmetros posicionais (?), nunca concatenados na string da query.Este PR expõe novos endpoints, telas ou serviços?
GET /articles-list, mesmo padrão do/history-listjá existente (retorna um fragmento HTML paginado/filtrado, consumido via AJAX pela própria aplicação; não expõe dado além do que já era acessível pela aba Artigos).Algum segredo, senha, chave ou token está sendo adicionado ao código-fonte?