feat: secoes da tela de log comecam fechadas, com clique para abrir
This commit is contained in:
@@ -252,6 +252,25 @@ a.botao:hover { border-color: var(--cor-acento); color: var(--cor-acento); }
|
||||
.status-dot-ativo { background: var(--cor-sucesso); }
|
||||
.status-dot-inativo { background: var(--cor-perigo); }
|
||||
|
||||
.secao-log { margin-bottom: 20px; }
|
||||
.secao-log summary {
|
||||
display: flex; align-items: center; gap: 10px; cursor: pointer;
|
||||
list-style: none; padding: 10px 0; user-select: none;
|
||||
}
|
||||
.secao-log summary::-webkit-details-marker { display: none; }
|
||||
.secao-log summary::before {
|
||||
content: "▸"; display: inline-block; color: var(--cor-texto-secundario);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
.secao-log[open] summary::before { transform: rotate(90deg); }
|
||||
.secao-log-titulo { font-size: 1.17em; font-weight: 700; }
|
||||
.botao-toggle-log {
|
||||
margin-top: 0; padding: 6px 12px; font-size: 0.85rem; font-weight: 400;
|
||||
background: transparent; border: 1px solid var(--cor-borda); color: var(--cor-texto);
|
||||
}
|
||||
.botao-toggle-log:hover { border-color: var(--cor-acento); color: var(--cor-acento); }
|
||||
.secao-log-conteudo { padding-top: 4px; }
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after { transition: none !important; }
|
||||
}
|
||||
|
||||
+83
-56
@@ -4,63 +4,90 @@
|
||||
{% block conteudo %}
|
||||
<h1>Log</h1>
|
||||
|
||||
<h2>Ações no painel</h2>
|
||||
{% if eh_admin %}
|
||||
<form method="post" action="/log/limpar" style="margin-bottom:14px">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<button type="submit" onclick="return confirm('Limpar todo o histórico de ações? Isso não pode ser desfeito.')">Limpar log</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if acoes %}
|
||||
<div class="tabela-wrap">
|
||||
<table>
|
||||
<tr><th>Quando</th><th>Usuário</th><th>Ação</th><th>Entidade</th><th>Status</th><th>Detalhe</th></tr>
|
||||
{% for a in acoes %}
|
||||
<tr>
|
||||
<td>{{ a.CRIADO_EM }}</td>
|
||||
<td>{{ a.USUARIO }}</td>
|
||||
<td>{{ a.ACAO }}</td>
|
||||
<td>{{ a.ENTIDADE }}{% if a.ENTIDADE_ID %} #{{ a.ENTIDADE_ID }}{% endif %}</td>
|
||||
<td><span class="badge {{ 'badge-sucesso' if a.SUCESSO else 'badge-neutro' }}">{{ "OK" if a.SUCESSO else "ERRO" }}</span></td>
|
||||
<td>{{ a.DETALHE or "" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<details class="secao-log">
|
||||
<summary>
|
||||
<span class="secao-log-titulo">Ações no painel</span>
|
||||
<button type="button" class="botao-toggle-log" aria-expanded="false">Mostrar</button>
|
||||
</summary>
|
||||
<div class="secao-log-conteudo">
|
||||
{% if eh_admin %}
|
||||
<form method="post" action="/log/limpar" style="margin-bottom:14px">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<button type="submit" onclick="return confirm('Limpar todo o histórico de ações? Isso não pode ser desfeito.')">Limpar log</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if acoes %}
|
||||
<div class="tabela-wrap">
|
||||
<table>
|
||||
<tr><th>Quando</th><th>Usuário</th><th>Ação</th><th>Entidade</th><th>Status</th><th>Detalhe</th></tr>
|
||||
{% for a in acoes %}
|
||||
<tr>
|
||||
<td>{{ a.CRIADO_EM }}</td>
|
||||
<td>{{ a.USUARIO }}</td>
|
||||
<td>{{ a.ACAO }}</td>
|
||||
<td>{{ a.ENTIDADE }}{% if a.ENTIDADE_ID %} #{{ a.ENTIDADE_ID }}{% endif %}</td>
|
||||
<td><span class="badge {{ 'badge-sucesso' if a.SUCESSO else 'badge-neutro' }}">{{ "OK" if a.SUCESSO else "ERRO" }}</span></td>
|
||||
<td>{{ a.DETALHE or "" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p>Nenhuma ação registrada ainda.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p>Nenhuma ação registrada ainda.</p>
|
||||
{% endif %}
|
||||
</details>
|
||||
|
||||
<h2>Envios automáticos de chave (n8n)</h2>
|
||||
{% if not envios_configurado %}
|
||||
<div class="cartao">
|
||||
<p>
|
||||
Integração com o n8n não configurada — defina <code>N8N_API_URL</code> e
|
||||
<code>N8N_API_KEY</code> no ambiente (ver <code>.env.example</code>) para ver
|
||||
aqui os envios automáticos de chave feitos pelo workflow do n8n.
|
||||
</p>
|
||||
<details class="secao-log">
|
||||
<summary>
|
||||
<span class="secao-log-titulo">Envios automáticos de chave (n8n)</span>
|
||||
<button type="button" class="botao-toggle-log" aria-expanded="false">Mostrar</button>
|
||||
</summary>
|
||||
<div class="secao-log-conteudo">
|
||||
{% if not envios_configurado %}
|
||||
<div class="cartao">
|
||||
<p>
|
||||
Integração com o n8n não configurada — defina <code>N8N_API_URL</code> e
|
||||
<code>N8N_API_KEY</code> no ambiente (ver <code>.env.example</code>) para ver
|
||||
aqui os envios automáticos de chave feitos pelo workflow do n8n.
|
||||
</p>
|
||||
</div>
|
||||
{% elif not envios %}
|
||||
<p>Nenhum envio encontrado (ou não foi possível consultar o n8n agora).</p>
|
||||
{% else %}
|
||||
<div class="tabela-wrap">
|
||||
<table>
|
||||
<tr>
|
||||
<th>Data</th><th>Cliente</th><th>Código</th><th>Competência</th><th>Status</th>
|
||||
<th>Telefones enviados</th><th>Telefones com erro</th>
|
||||
</tr>
|
||||
{% for e in envios %}
|
||||
<tr>
|
||||
<td>{{ e.data_processamento }}</td>
|
||||
<td>{{ e.nome_cliente }}</td>
|
||||
<td>{{ e.codigo_cliente }}</td>
|
||||
<td>{{ e.competencia }}</td>
|
||||
<td>{{ e.status }}</td>
|
||||
<td>{{ e.telefones_enviados }}</td>
|
||||
<td>{{ e.telefones_com_erro or "" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% elif not envios %}
|
||||
<p>Nenhum envio encontrado (ou não foi possível consultar o n8n agora).</p>
|
||||
{% else %}
|
||||
<div class="tabela-wrap">
|
||||
<table>
|
||||
<tr>
|
||||
<th>Data</th><th>Cliente</th><th>Código</th><th>Competência</th><th>Status</th>
|
||||
<th>Telefones enviados</th><th>Telefones com erro</th>
|
||||
</tr>
|
||||
{% for e in envios %}
|
||||
<tr>
|
||||
<td>{{ e.data_processamento }}</td>
|
||||
<td>{{ e.nome_cliente }}</td>
|
||||
<td>{{ e.codigo_cliente }}</td>
|
||||
<td>{{ e.competencia }}</td>
|
||||
<td>{{ e.status }}</td>
|
||||
<td>{{ e.telefones_enviados }}</td>
|
||||
<td>{{ e.telefones_com_erro or "" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
</details>
|
||||
|
||||
<script>
|
||||
document.querySelectorAll(".secao-log").forEach(function (secao) {
|
||||
var botao = secao.querySelector(".botao-toggle-log");
|
||||
var atualizar = function () {
|
||||
var aberto = secao.hasAttribute("open");
|
||||
botao.textContent = aberto ? "Ocultar" : "Mostrar";
|
||||
botao.setAttribute("aria-expanded", aberto ? "true" : "false");
|
||||
};
|
||||
secao.addEventListener("toggle", atualizar);
|
||||
atualizar();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -105,3 +105,16 @@ def test_limpar_log_usuario_padrao_toma_403():
|
||||
app_teste.dependency_overrides[exigir_login] = lambda: UsuarioLogado(login="fulano", nome="Fulano", perfil="PADRAO")
|
||||
resposta = client.post("/log/limpar", data={"csrf_token": CSRF_TESTE})
|
||||
assert resposta.status_code == 403
|
||||
|
||||
|
||||
def test_pagina_log_secoes_comecam_fechadas(monkeypatch):
|
||||
monkeypatch.setattr(router_log.db_log, "listar", lambda limite=20: [])
|
||||
monkeypatch.setattr(router_log.n8n_client, "listar_envios", lambda limite=50: [])
|
||||
monkeypatch.setattr(router_log.n8n_client, "configurado", lambda: False)
|
||||
|
||||
resposta = client.get("/log")
|
||||
assert resposta.status_code == 200
|
||||
texto = resposta.text
|
||||
assert texto.count('<details class="secao-log">') == 2
|
||||
assert "<details class=\"secao-log\" open>" not in texto
|
||||
assert "<details class='secao-log' open>" not in texto
|
||||
|
||||
Reference in New Issue
Block a user