Skip to content

v0.73.1

Choose a tag to compare

@adrianfiio adrianfiio released this 02 Aug 02:25

AFService Map v0.73.1 — Hotfix estrutural do runtime do mapa

Backup/ponto de rollback desta rodada: branch backup/mapa-pre-v0722-20260802
(pointer no commit ef12a9a, v0.73.0). Pacote preparado pelo ChatGPT como
"v0.72.2" sobre o commit 16a125a (v0.72.1) — antes do reskin dos
dashboards (v0.73.0) ter entrado no main. Aplicado via
apply_map_ui_v0722.py (validado antes com --dry-run, checksums
SHA-256 conferidos um a um). Sem migration.

Sobre o número de versão

O pacote chamava a si mesmo de "v0.72.2" porque foi preparado sobre o
commit da v0.72.1, sem saber ainda que a v0.73.0 (reskin dos dashboards)
já tinha entrado no main. Confirmei que os dois pacotes não têm
nenhuma sobreposição de arquivo (este só toca em templates/map.html,
.gitignore e cria os arquivos novos do mapa; o reskin só tocou em
templates/base.html, static/css/app.css e os 3 templates de
dashboard) — mas apliquei renomeando a versão final pra 0.73.1 em vez
de 0.72.2, pra manter o changelog em ordem cronológica real (este pacote
chegou e foi aplicado depois da v0.73.0, mesmo tendo sido preparado
antes).

Causa raiz confirmada lendo o código, não só a explicação do pacote

Antes de aceitar a explicação do ChatGPT, comparei o map-ui-v0721.js
antigo com o map-ui-v0722.js novo pra confirmar que os bugs descritos
realmente existiam:

1. Laço de reconstrução do popup. Em v0.72.1, schedulePopup()
registrava um MutationObserver no conteúdo do popup, além de 3 timers
(80/260/650ms). O observador tinha uma trava de debounce (scheduled)
contra reagir à própria mutação — isso eu já tinha conferido na release
da v0.72.1. O que não tinha percebido: map-ui-v072.js (a base, carregada
antes) também tem seu próprio sistema de decoração de popup
(decoratePopup, registrado em state.map.on("popupopen", ...)) que
mexe no mesmo .leaflet-popup-content. Dois sistemas diferentes
mutando a mesma área, um com observador ativo — o terreno certo pra
reconstrução em cascata, mesmo com debounce individual em cada um.
popupIdentity() também recalculava nome/tipo/código toda vez lendo o
DOM ao vivo, sem cache — se uma leitura acontecesse no meio de uma
mutação (o content.replaceChildren() do próprio código, ou a decoração
concorrente do map-ui-v072.js), o texto capturado podia vir de um
estado intermediário e ser usado como base pra próxima reconstrução.

O hotfix v0.72.2 remove o MutationObserver dos popups por completo.
Restam só 2 checagens finitas depois de abrir o popup (100ms e 420ms —
suficiente pra Master Suite/monitoramento injetarem as ações delas antes
da normalização final) e a identidade é capturada uma única vez e
cacheada em content._uiV0722Identity, nunca mais recalculada por cima
de um DOM que o próprio código já reconstruiu.

2. Botões de ação perdendo a função. Em v0.72.1, actionKey()
reconhecia um botão pela chave de um atributo de uma lista fixa:
showElementCables, manageContainer, editElement, deleteElement,
masterAssetSheet, showUnifilar, openMonitorLinks. Qualquer botão
com outro atributo (data-insert-cable, data-reserve-cable,
data-cable-route, etc. — usados em Reserva, Inserir caixa, Rota do
cabo) caía no fallback por texto (button.textContent...), e a
deduplicação (if (keys.has(key)) return;) descartava silenciosamente
qualquer botão cujo texto colidisse com outro já visto. Achei essa lista
fixa lendo o código da v0.72.1 — é uma explicação plausível e verificável
pros botões que "paravam de responder" sem gerar nenhum erro no console
(o botão simplesmente não ia parar no popup final).

O hotfix v0.72.2 troca isso por uma chave feita de todos os
atributos data-* do próprio botão (ordenados), então nenhum botão real
se confunde com outro.

O que mais entrou

  • Cancelamento de ferramenta de verdade: a barra agora rastreia qual
    ferramenta está ativa (state.activeTool), mostra um botão
    "Cancelar [ferramenta]" enquanto ela está ativa, cancela com Esc, e
    cancela sozinha ao fechar os diálogos de elemento/cabo no meio da
    operação (#element-dialog/#cable-dialog close) — resolve o
    "próximo clique preso no mapa" relatado.
  • Ícones não interceptam mais o clique: pointer-events: none nos
    ícones/SVGs internos dos botões do popup e da barra.
  • popupclose limpa os timers pendentes — antes, se o popup fosse
    fechado antes dos timers de normalização dispararem, eles rodavam
    mesmo assim contra um popup já fechado.
  • Menu lateral em trilho de 72px, régua que vira cabo, medição de área,
    busca com Ctrl+K, whitelabel, tema claro/escuro, SNMP/InfluxDB/
    Telegraf, backbone, PTP wireless, alertas, fusões, Canvas 2D, matriz de
    manobra, KMZ/KML — tudo preservado sem mudança de comportamento.

Verificação feita

  • Checksums SHA-256 do pacote conferidos um a um contra SHA256SUMS.
  • BASE_COMMIT (16a125a, v0.72.1) confirmado batendo com o estado do
    repositório antes da v0.73.0 ter entrado.
  • Confirmado por leitura do git diff que o pacote não toca em
    templates/base.html nem static/css/app.css
    (arquivos do reskin
    v0.73.0) — as únicas mudanças em templates/map.html foram as duas
    tags v0721v0722, exatamente como o script prometia.
  • Confirmado que map-optical-editor-v3.js, map-link-monitoring.js,
    map-master-suite.js e map-ui-v072.js/.css continuam intactos.
  • Li o map-ui-v0722.js inteiro (não só o resumo do pacote) pra
    confirmar a ausência real do MutationObserver e o cache de
    identidade, e o map-ui-v0722.css inteiro (pointer-events, seletores
    de busca/popup).
  • --dry-run do aplicador, sem erro.
  • python -m py_compile no Python tocado.
  • Sintaxe do map-ui-v0722.js validada com esprima.
  • Chaves do map-ui-v0722.css balanceadas (74/74).
  • {% if %}/{% endif %} de templates/map.html balanceados (10/10).
  • docker-compose.yml validado como YAML.
  • Rodei manualmente as 6 asserções do teste estático incluído
    (test_map_ui_v0722_static.py, sem dependência de banco): ausência do
    MutationObserver, cache de identidade, rótulos limpos dos botões,
    menu Caixas/Cancelar, reset de posição da busca, gaveta de rotas real
    — todas passaram.

A suíte Django completa (manage.py check, manage.py test) e o teste
visual real dependem de banco, GDAL e navegador — não rodam neste
ambiente de preparação.

Atualização

Execute apply no servidor. Sem migration nesta versão. Depois, um
Ctrl+F5 no navegador garante que o JS/CSS novos sejam carregados
(o map-ui-v0721.js/.css não é mais referenciado pelo template, só
fica como arquivo morto no disco).

Teste sugerido: abrir um popup de CTO/CEO/CDO/Torre/Rack/CPD-POP/Poste/
cabo e confirmar que o nome/código não crescem mais e que Editar, Fusões,
Equipamentos, Ficha/QR, Excluir, Rota do cabo, Monitorar enlace,
Adicionar reserva e Inserir caixa respondem ao clique; ativar uma
ferramenta (CTO, Cabo, etc.) e confirmar que aparece "Cancelar" e que
Esc cancela; testar a busca (Ctrl+K) sem deslocamento lateral.