Implementação de compatibilidade HTTP
This commit is contained in:
parent
668f2eb26b
commit
4676412325
@ -62,3 +62,9 @@ Usuário reportou erro genérico ao tentar reprocessar os mesmos dois arquivos "
|
||||
Causa raiz: `_aplica_upsert_nao_conformidades` (rodada 88) fazia `update_or_create`/`get_or_create` **um item por vez** — aceitável nos ~300 registros da amostra inicial (~2 idas ao banco por item), mas o export real de "com finalizadas" tem ~1700 ocorrências/~3400 ações/~9000 acompanhamentos — quase 28 mil idas ao banco. Reescrito pra lote: pré-carrega o que já existe (poucos `SELECT ... WHERE codigo IN (...)`) e aplica tudo de uma vez (`bulk_create`/`bulk_update` por model, `batch_size=500`) — e, mais importante pro caso real de reimportação periódica, **pula por completo quem não mudou nada** desde a última importação (reimportar o Sigsistem inteiro todo mês traz de volta o histórico completo, não só o que é novo). Resultado medido com os arquivos reais: primeira carga ~21s (a maioria virando "atualizada" pela primeira vez), reimportação do mesmo arquivo sem nenhuma mudança real caiu de ~60s pra **~4s** (a maior parte disso é upload do arquivo de 23MB + parsing, não mais banco).
|
||||
|
||||
Efeito colateral documentado (não é regressão, é a semântica correta): `resumo["ocorrencias_atualizadas"]`/`["acoes_atualizadas"]` agora contam só quem teve algum campo realmente alterado, não "já existia e foi vista de novo". Nenhuma migração, nenhuma mudança de contrato de API — só a implementação interna do upsert. Detalhe técnico em `portal_api/nao_conformidades/CLAUDE.md`, seção "Upsert".
|
||||
|
||||
### Rodada 107 — "Não foi possível copiar o texto." no botão Copiar do Resumo (produção HTTP)
|
||||
|
||||
Usuário reportou o aviso "Não foi possível copiar o texto." ao clicar em "Copiar" no popover do Resumo de Gestão, em produção. Causa: `navigator.clipboard.writeText()` (única chamada à Clipboard API no Portal) só funciona em contexto seguro (HTTPS ou `localhost`) — a produção deste Portal roda em HTTP puro hoje, sem TLS, e não há previsão de migrar pra HTTPS no momento (decisão de infraestrutura fora do escopo desta aplicação).
|
||||
|
||||
Correção: `resumoCopiarBtn` agora chama `pidNcfCopiarTexto()`, que usa `navigator.clipboard.writeText()` quando `window.isSecureContext` é verdadeiro e, senão, cai num fallback com `document.execCommand("copy")` via um `<textarea>` temporário fora da tela (`pidNcfCopiarTextoFallback`). Sem migração, sem mudança de contrato de API — só o handler de clique em `nao-conformidades.js`. Detalhe em `portal_api/nao_conformidades/CLAUDE.md`, seção "Frontend".
|
||||
|
||||
@ -95,6 +95,7 @@ Uma página com 3 abas (`.pa-tabs`, reaproveitado de `perfis-acesso.css`): **Das
|
||||
- **Filtro combinável de Ações**: duas fileiras de chips independentes, Prazo (`?status_prazo=`) e Tratativa (`?status_tratativa=`), combinam com AND (dois `<select>` de fato seriam mais familiares, mas o padrão chip já é o mesmo do período do Dashboard). A tabela mostra as duas dimensões em colunas separadas ("Prazo" e "Tratativa") — nunca juntar num "Status" só, é exatamente essa mistura que gerou confusão antes.
|
||||
- **Expandir linha** (`pidNcfCriarLinhaExpandivel`, mesmo padrão de `.cc-painel-fiscal__toggle` de `custo-contratacao.css`/`.js` — chevron que gira via `[aria-expanded="true"] svg{transform:rotate(90deg)}`) é o único mecanismo de "ver mais" das 3 listas: ocorrência (relato completo, causa, cliente, riscos etc. — parte já vem da própria listagem, o resto é buscado lazy em `GET /ocorrencias/{id}/`) e ação (texto completo + histórico de acompanhamentos, mais recente primeiro, 3 visíveis + "Mostrar mais", buscado lazy em `GET /acoes/{id}/`). Não usar modal pra isso — o modal de histórico existiu numa rodada anterior e foi removido a pedido do usuário (ficava colado no botão "Marcar como tratado").
|
||||
- **Busca compartilhada da Gestão** (`#ncf-gestao-search`): filtra as 3 listas ao mesmo tempo, sempre client-side sobre os dados já carregados (sem round-trip) — colaborador/responsável/emissor/cliente/assunto.
|
||||
- **Botão "Copiar" do Resumo de Gestão** (`resumoCopiarBtn`): `navigator.clipboard.writeText()` só funciona em contexto seguro (HTTPS/`localhost`) — como a produção deste Portal roda em HTTP puro (sem TLS, decisão de infraestrutura fora do escopo desta aplicação), `pidNcfCopiarTexto()` cai num fallback com `document.execCommand("copy")` (via um `<textarea>` temporário fora da tela) sempre que `navigator.clipboard`/`window.isSecureContext` não estiverem disponíveis. Único uso de Clipboard API no Portal hoje — se o ambiente ganhar HTTPS no futuro, o fallback deixa de ser exercitado sozinho (a checagem de `isSecureContext` já prioriza a API nativa), não precisa remover nada.
|
||||
|
||||
Reaproveita `.status-pill` (definido em `perfis-acesso.css`) com modificadores novos (`--ok`/`--danger`/`--warning`/`--neutral`, em `nao-conformidades.css`) em vez de inventar um componente de badge próprio. Chips de filtro/período (`.ncf-chip`/`.ncf-chip-row`) duplicam o visual de `.ind-departamento-chip` (`indicador-desempenho.css`) porque essa folha não é carregada nesta página.
|
||||
|
||||
|
||||
@ -942,9 +942,37 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
resumoBtn.setAttribute("aria-expanded", String(!jaAberto));
|
||||
});
|
||||
|
||||
function pidNcfCopiarTextoFallback(texto) {
|
||||
const textarea = document.createElement("textarea");
|
||||
textarea.value = texto;
|
||||
textarea.style.position = "fixed";
|
||||
textarea.style.top = "-1000px";
|
||||
textarea.style.left = "-1000px";
|
||||
document.body.appendChild(textarea);
|
||||
textarea.focus();
|
||||
textarea.select();
|
||||
let ok = false;
|
||||
try {
|
||||
ok = document.execCommand("copy");
|
||||
} catch (e) {
|
||||
ok = false;
|
||||
}
|
||||
document.body.removeChild(textarea);
|
||||
return ok;
|
||||
}
|
||||
|
||||
async function pidNcfCopiarTexto(texto) {
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
await navigator.clipboard.writeText(texto);
|
||||
return true;
|
||||
}
|
||||
return pidNcfCopiarTextoFallback(texto);
|
||||
}
|
||||
|
||||
resumoCopiarBtn.addEventListener("click", async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(resumoTextoAtual);
|
||||
const copiado = await pidNcfCopiarTexto(resumoTextoAtual);
|
||||
if (!copiado) throw new Error("copy fallback failed");
|
||||
const textoOriginal = resumoCopiarBtn.textContent;
|
||||
resumoCopiarBtn.textContent = "Copiado!";
|
||||
setTimeout(() => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user