fix: show technical timestamps in tooltips
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<div class="detail-head"><div><p class="eyebrow">{{ detail.client or "Cliente não identificado" }} / INSTALAÇÃO</p><h1>{{ detail.display_name or detail.hostname or detail.installation_id }}</h1><p class="muted">{{ detail.hostname or "hostname indisponível" }}</p></div><div class="badge-stack"><span class="badge {{ detail.technical_health|lower }} large">Saúde técnica: {{ detail.technical_health_label }}</span><span class="badge fiscal-{{ detail.fiscal_status|lower }} large">Status fiscal: {{ detail.fiscal_status_label }}</span></div></div>
|
||||
<section class="cards compact"><article class="metric"><span>Produtos</span><strong>{{ detail.total_products }}</strong></article><article class="metric"><span>Completos</span><strong>{{ detail.fiscally_complete }}</strong></article><article class="metric"><span>Bloqueados com segurança</span><strong>{{ detail.safe_blocked }}</strong></article><article class="metric"><span>Cobertura fiscal</span><strong>{{ "%.1f"|format(detail.fiscal_completion_percent)|replace(".", ",") }}%</strong><small>{{ detail.fiscally_complete }} / {{ detail.total_products }}</small></article></section>
|
||||
<nav class="tabs" aria-label="Seções da instalação">{% for name,label in [("overview","Resumo"),("fiscal","Fiscal"),("blockers","Blockers"),("jobs","Jobs"),("events","Eventos")] %}<a class="{% if tab==name %}active{% endif %}" href="?tab={{ name }}">{{ label }}</a>{% endfor %}</nav>
|
||||
<section class="split"><article class="panel"><div class="panel-title"><h2>Contexto da empresa</h2><a class="secondary" href="/agents/{{ detail.agent_id }}/reprocess-confirmation">Reprocessar tudo</a></div><dl class="facts"><dt>Cliente</dt><dd>{{ detail.client or "-" }}</dd><dt>Nome de exibição</dt><dd>{{ detail.display_name or "-" }}</dd><dt>Hostname</dt><dd>{{ detail.hostname or "-" }}</dd><dt>Empresa</dt><dd>{{ detail.company_name or detail.company_code or "-" }}</dd><dt>UF</dt><dd>{{ detail.company_uf or "-" }}</dd><dt>CRT</dt><dd>{{ detail.company_crt or "-" }}</dd><dt>Versão do agent</dt><dd>{{ detail.agent_version or "Desconhecida" }} · {{ detail.version_drift|title }}</dd><dt>Último heartbeat</dt><dd title="{{ detail.last_seen_display }}">{{ detail.last_seen_display }} · {{ detail.last_seen_age }}</dd><dt>Firebird</dt><dd>{{ detail.firebird_version or "-" }} · ODS {{ detail.firebird_ods or "-" }}</dd><dt>IDs técnicos</dt><dd>Agent {{ detail.technical_ids.agent_id }} · instalação {{ detail.technical_ids.installation_db_id }}</dd></dl></article>
|
||||
<section class="split"><article class="panel"><div class="panel-title"><h2>Contexto da empresa</h2><a class="secondary" href="/agents/{{ detail.agent_id }}/reprocess-confirmation">Reprocessar tudo</a></div><dl class="facts"><dt>Cliente</dt><dd>{{ detail.client or "-" }}</dd><dt>Nome de exibição</dt><dd>{{ detail.display_name or "-" }}</dd><dt>Hostname</dt><dd>{{ detail.hostname or "-" }}</dd><dt>Empresa</dt><dd>{{ detail.company_name or detail.company_code or "-" }}</dd><dt>UF</dt><dd>{{ detail.company_uf or "-" }}</dd><dt>CRT</dt><dd>{{ detail.company_crt or "-" }}</dd><dt>Versão do agent</dt><dd>{{ detail.agent_version or "Desconhecida" }} · {{ detail.version_drift|title }}</dd><dt>Último heartbeat</dt><dd title="{{ detail.last_seen_at }}">{{ detail.last_seen_display }} · {{ detail.last_seen_age }}</dd><dt>Firebird</dt><dd>{{ detail.firebird_version or "-" }} · ODS {{ detail.firebird_ods or "-" }}</dd><dt>IDs técnicos</dt><dd>Agent {{ detail.technical_ids.agent_id }} · instalação {{ detail.technical_ids.installation_db_id }}</dd></dl></article>
|
||||
<article class="panel"><div class="panel-title"><h2>Eventos recentes</h2><a href="#eventos">Ver eventos</a></div>{% for event in events[:8] %}<div class="event-row"><span class="event-time">{{ event.occurred_display }}</span><span><b>{{ event.event_type }}</b><small>{{ event.message }}{% if event.job_id %} · <a href="/jobs?job_id={{ event.job_id }}">Job {{ event.job_id }}</a>{% endif %}{% if event.product_code %} · <a href="/blockers?agent_id={{ detail.agent_id }}&product_code={{ event.product_code|urlencode }}">Produto {{ event.product_code }}</a>{% endif %}</small></span><em class="severity {{ event.severity|lower }}">Severidade: {{ event.severity }}</em></div>{% else %}<p class="empty-state">Nenhum evento.</p>{% endfor %}</article></section>
|
||||
<section class="panel" id="eventos"><div class="panel-title"><div><h2>Eventos operacionais</h2><p class="muted">Filtros aplicados no servidor.</p></div></div><form class="filters compact-filters" method="get"><input type="hidden" name="tab" value="events"><label>Severidade<select name="severity"><option value="">Todas</option>{% for value in ["INFO","WARNING","ERROR","CRITICAL"] %}<option value="{{ value }}" {% if severity==value %}selected{% endif %}>{{ value }}</option>{% endfor %}</select></label><label>Tipo de evento<input name="event_type" value="{{ event_type }}"></label><label>Job ID<input name="job_id" value="{{ job_id }}" inputmode="numeric"></label><label>Produto<input name="product_code" value="{{ product_code }}"></label><label>Desde<input type="date" name="since" value="{{ since }}"></label><label>Até<input type="date" name="until" value="{{ until }}"></label><button class="secondary" type="submit">Filtrar eventos</button></form><nav class="pagination" aria-label="Paginação de eventos">{% if event_page > 1 %}<a href="/agents/{{ detail.agent_id }}?event_page={{ event_page - 1 }}{% if event_query_base %}&{{ event_query_base }}{% endif %}">Anterior</a>{% endif %}<span>Página {{ event_page }}</span>{% if has_more %}<a href="/agents/{{ detail.agent_id }}?event_page={{ event_page + 1 }}{% if event_query_base %}&{{ event_query_base }}{% endif %}">Próxima</a>{% endif %}</nav></section>
|
||||
<section class="panel"><div class="panel-title"><h2>Blockers abertos</h2><a href="/blockers?agent_id={{ detail.agent_id }}">Ver todos</a></div><div class="bar-grid">{% for key in ["CFOP","ST","ICMS","CSOSN","NCM","OTHER"] %}<div class="bar-row"><span>{{ key }}</span><b>{{ blocker_breakdown[key] }}</b></div>{% endfor %}</div>{% for item in blockers["items"][:8] %}<a class="list-row" href="{{ item.link }}"><span><b>{{ item.product_code }}</b> · {{ item.field }}<small>{{ item.reason }} · {{ item.age }}</small></span><em class="badge blocked">{{ item.blocker_type }}</em></a>{% else %}<p class="empty-state">Nenhum blocker aberto.</p>{% endfor %}</section>
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
{% block title %}Agents | GTI Fiscal{% endblock %}
|
||||
{% block content %}
|
||||
<div class="page-heading"><div><p class="eyebrow">INVENTÁRIO OPERACIONAL</p><h1>Agents / Servidores</h1><p class="muted">Identidade do cliente primeiro; IDs técnicos ficam no detalhe.</p></div><form class="filters" method="get"><label>Cliente, instalação ou hostname<input name="search" value="{{ search }}"></label><label>Saúde técnica<select name="health"><option value="">Todos</option>{% for value in ["ONLINE","DEGRADED","OFFLINE","FAILED","UNKNOWN"] %}<option value="{{ value }}" {% if health_filter==value %}selected{% endif %}>{{ value|title }}</option>{% endfor %}</select></label><label>Ordenação<select name="sort"><option value="display_name" {% if sort=="display_name" %}selected{% endif %}>Nome de exibição</option><option value="worst_coverage" {% if sort=="worst_coverage" %}selected{% endif %}>Pior cobertura fiscal</option></select></label><button class="secondary" type="submit">Filtrar</button></form></div>
|
||||
<div class="panel table-wrap"><table><caption>Instalações monitoradas</caption><thead><tr><th>Cliente</th><th>Nome de exibição</th><th>Hostname</th><th>Saúde técnica</th><th>Status fiscal</th><th>Cobertura fiscal</th><th>Produtos</th><th>Versão</th><th>Último heartbeat</th></tr></thead><tbody>{% for item in result["items"] %}<tr><td><a href="/agents/{{ item.agent_id }}"><b>{{ item.client or "Cliente não identificado" }}</b></a></td><td>{{ item.display_name or "-" }}<small>ID técnico: {{ item.installation_id }}</small></td><td>{{ item.hostname or "-" }}</td><td><span class="badge {{ item.technical_health|lower }}">Saúde técnica: {{ item.technical_health_label }}</span></td><td><span class="badge fiscal-{{ item.fiscal_status|lower }}">Status fiscal: {{ item.fiscal_status_label }}</span>{% if item.safe_blocked %}<small>{{ item.safe_blocked }} bloqueados com segurança</small>{% endif %}</td><td><strong>{{ "%.1f"|format(item.fiscal_completion_percent)|replace(".", ",") }}%</strong><small>{{ item.fiscally_complete }} / {{ item.total_products }}</small></td><td>{{ item.total_products }}<small>{{ item.failed_products }} falhas</small></td><td>{{ item.agent_version or "Desconhecida" }}<small>{{ item.version_drift|title }}</small></td><td title="{{ item.last_seen_display }}">{{ item.last_seen_display }}<small>{{ item.last_seen_age }}</small></td></tr>{% else %}<tr><td colspan="9" class="empty-state">Nenhuma instalação encontrada.</td></tr>{% endfor %}</tbody></table></div>
|
||||
<div class="panel table-wrap"><table><caption>Instalações monitoradas</caption><thead><tr><th>Cliente</th><th>Nome de exibição</th><th>Hostname</th><th>Saúde técnica</th><th>Status fiscal</th><th>Cobertura fiscal</th><th>Produtos</th><th>Versão</th><th>Último heartbeat</th></tr></thead><tbody>{% for item in result["items"] %}<tr><td><a href="/agents/{{ item.agent_id }}"><b>{{ item.client or "Cliente não identificado" }}</b></a></td><td>{{ item.display_name or "-" }}<small>ID técnico: {{ item.installation_id }}</small></td><td>{{ item.hostname or "-" }}</td><td><span class="badge {{ item.technical_health|lower }}">Saúde técnica: {{ item.technical_health_label }}</span></td><td><span class="badge fiscal-{{ item.fiscal_status|lower }}">Status fiscal: {{ item.fiscal_status_label }}</span>{% if item.safe_blocked %}<small>{{ item.safe_blocked }} bloqueados com segurança</small>{% endif %}</td><td><strong>{{ "%.1f"|format(item.fiscal_completion_percent)|replace(".", ",") }}%</strong><small>{{ item.fiscally_complete }} / {{ item.total_products }}</small></td><td>{{ item.total_products }}<small>{{ item.failed_products }} falhas</small></td><td>{{ item.agent_version or "Desconhecida" }}<small>{{ item.version_drift|title }}</small></td><td title="{{ item.last_seen_at }}">{{ item.last_seen_display }}<small>{{ item.last_seen_age }}</small></td></tr>{% else %}<tr><td colspan="9" class="empty-state">Nenhuma instalação encontrada.</td></tr>{% endfor %}</tbody></table></div>
|
||||
<nav class="pagination" aria-label="Paginação de agents">{% if result.page > 1 %}<a href="/agents?page={{ result.page - 1 }}{% if query_base %}&{{ query_base }}{% endif %}">Anterior</a>{% endif %}<span>Página {{ result.page }} · {{ result.total }} instalações</span>{% if result.page * result.page_size < result.total %}<a href="/agents?page={{ result.page + 1 }}{% if query_base %}&{{ query_base }}{% endif %}">Próxima</a>{% endif %}</nav>
|
||||
{% endblock %}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="detail-head"><div><p class="eyebrow">RESOLUÇÃO OPERACIONAL</p><h1>Blocker {{ detail.id }}</h1><p class="muted">{{ detail.client or "Cliente não identificado" }} · {{ detail.product_code }}</p></div><div class="badge-stack"><span class="badge blocked large">Fiscal: {{ detail.blocker_type }}</span><span class="badge priority-{{ detail.priority|lower }} large">Prioridade: {{ detail.priority }}</span></div></div>
|
||||
{% if error %}<div class="panel"><p class="error">{{ error }}</p></div>{% endif %}
|
||||
<section class="split">
|
||||
<article class="panel"><h2>Detalhes do blocker</h2><dl class="facts"><dt>Cliente</dt><dd>{{ detail.client or "-" }}</dd><dt>Instalação</dt><dd>{{ detail.installation.display_name or "-" }}</dd><dt>Servidor</dt><dd>{{ detail.server.hostname or "-" }}</dd><dt>Produto</dt><dd>{{ detail.product_code }}</dd><dt>Descrição</dt><dd>{{ detail.description or "-" }}</dd><dt>Campo</dt><dd>{{ detail.field or "OTHER" }}</dd><dt>Tipo</dt><dd>{{ detail.blocker_type }}</dd><dt>Motivo</dt><dd>{{ detail.reason }}</dd><dt>Idade</dt><dd>{{ detail.age }}</dd><dt>Última ocorrência</dt><dd title="{{ detail.last_seen_display }}">{{ detail.last_seen_display }}</dd><dt>Evidência</dt><dd><pre class="evidence">{{ detail.evidence|tojson(indent=2) }}</pre></dd></dl></article>
|
||||
<article class="panel"><h2>Detalhes do blocker</h2><dl class="facts"><dt>Cliente</dt><dd>{{ detail.client or "-" }}</dd><dt>Instalação</dt><dd>{{ detail.installation.display_name or "-" }}</dd><dt>Servidor</dt><dd>{{ detail.server.hostname or "-" }}</dd><dt>Produto</dt><dd>{{ detail.product_code }}</dd><dt>Descrição</dt><dd>{{ detail.description or "-" }}</dd><dt>Campo</dt><dd>{{ detail.field or "OTHER" }}</dd><dt>Tipo</dt><dd>{{ detail.blocker_type }}</dd><dt>Motivo</dt><dd>{{ detail.reason }}</dd><dt>Idade</dt><dd>{{ detail.age }}</dd><dt>Primeira ocorrência</dt><dd title="{{ detail.first_seen_at }}">{{ detail.first_seen_display }}</dd><dt>Última ocorrência</dt><dd title="{{ detail.last_seen_at }}">{{ detail.last_seen_display }}</dd><dt>Evidência</dt><dd><pre class="evidence">{{ detail.evidence|tojson(indent=2) }}</pre></dd></dl></article>
|
||||
<article class="panel"><h2>Contexto atual</h2><p class="muted">Valor atual por chave persistida para esta empresa.</p>{% for entry in context_entries %}<div class="list-row"><span><b>{{ entry.key }}</b><small>{{ entry.scope }} / {{ entry.scope_key or "empresa" }}</small></span><em>{{ entry.value }}</em></div>{% else %}<p class="muted">Nenhum valor definido.</p>{% endfor %}</article>
|
||||
</section>
|
||||
<section class="panel"><h2>Salvar contexto e reprocessar</h2><p class="muted">Escolha uma chave fiscal validada. O reprocessamento será limitado ao produto deste blocker.</p><form method="post" action="/blockers/{{ detail.id }}/resolve-context"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><div class="form-grid"><label for="context-key">Chave de contexto<select id="context-key" name="key" required>{% for key in context_keys %}<option value="{{ key }}">{{ key }}</option>{% endfor %}</select></label><label for="context-value">Valor<input id="context-value" name="value" required maxlength="512"><small>Valores aceitos: {{ value_choices|join(", ") }}</small></label><label for="context-scope">Escopo<select id="context-scope" name="scope" required><option value="PRODUCT">PRODUCT</option><option value="GROUP">GROUP</option><option value="COMPANY">COMPANY</option></select></label><label for="scope-key">Chave do escopo<input id="scope-key" name="scope_key" value="{{ detail.product_code }}" required></label><label class="wide" for="context-reason">Nota<textarea id="context-reason" name="reason" required maxlength="2000"></textarea></label></div><div class="panel-title"><a href="/blockers">Cancelar</a><button type="submit">Salvar contexto e reprocessar</button></div></form></section>
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
<section class="cards compact"><article class="metric"><span>Blockers abertos</span><strong>{{ summary.open_blockers }}</strong></article><article class="metric"><span>Produtos afetados</span><strong>{{ summary.affected_products }}</strong></article><article class="metric"><span>Clientes afetados</span><strong>{{ summary.affected_clients }}</strong></article><article class="metric"><span>Resultado filtrado</span><strong>{{ result.total }}</strong></article></section>
|
||||
<section class="panel"><form class="filters blocker-filters" method="get">{% if request.query_params.get('agent_id') %}<input type="hidden" name="agent_id" value="{{ request.query_params.get('agent_id') }}">{% endif %}{% if request.query_params.get('product_code') %}<input type="hidden" name="product_code" value="{{ request.query_params.get('product_code') }}">{% endif %}<label>Cliente<input name="client" value="{{ client_filter }}"></label><label>Instalação / Agent / Servidor<input name="installation" value="{{ installation_filter }}"></label><label>Campo<select name="field"><option value="">Todos</option>{% for value in ["CFOP","ST","ICMS","CSOSN","NCM","OTHER"] %}<option value="{{ value }}" {% if field_filter==value %}selected{% endif %}>{{ value }}</option>{% endfor %}</select></label><label>Tipo de blocker<input name="blocker_type" value="{{ blocker_type_filter }}"></label><label>Status<select name="status"><option value="OPEN" {% if status_filter=="OPEN" %}selected{% endif %}>Abertos</option><option value="RESOLVED" {% if status_filter=="RESOLVED" %}selected{% endif %}>Resolvidos</option><option value="ALL" {% if status_filter=="ALL" %}selected{% endif %}>Todos</option></select></label><label>Idade<input name="age" value="{{ age_filter }}" placeholder="ex.: 1d"></label><label>Produto ou busca<input name="search" value="{{ search }}"></label><button class="secondary" type="submit">Filtrar blockers</button></form></section>
|
||||
<section class="panel"><div class="panel-title"><h2>Distribuição dos blockers filtrados</h2></div><div class="bar-grid">{% for key in ["CFOP","ST","ICMS","CSOSN","NCM","OTHER"] %}<div class="bar-row"><span>{{ key }}</span><b>{{ summary.blocker_breakdown[key] }}</b></div>{% endfor %}</div></section>
|
||||
<div class="panel table-wrap"><table><caption>Fila de blockers</caption><thead><tr><th>Cliente</th><th>Instalação</th><th>Produto</th><th>Campo</th><th>Tipo de blocker</th><th>Prioridade</th><th>Problema</th><th>Última ocorrência</th><th>Ação</th></tr></thead><tbody>{% for item in result["items"] %}<tr><td>{{ item.client or "Cliente não identificado" }}</td><td>{{ item.display_name or "-" }}<small>{{ item.hostname or "hostname indisponível" }}</small></td><td><b>{{ item.product_code }}</b><small>{{ item.description or "" }}</small></td><td>{{ item.field or "OTHER" }}</td><td><span class="badge blocked">Fiscal: {{ item.blocker_type }}</span></td><td><span class="badge priority-{{ item.priority|lower }}">Prioridade: {{ item.priority }}</span></td><td>{{ item.reason }}<small>{{ item.age }}</small></td><td title="{{ item.last_seen_display }}">{{ item.last_seen_display }}<small>{{ item.retry_count }} tentativas</small></td><td><a class="secondary" href="{{ item.link }}">Ver detalhe</a></td></tr>{% else %}<tr><td colspan="9" class="empty-state">Nenhum blocker corresponde aos filtros.</td></tr>{% endfor %}</tbody></table></div>
|
||||
<div class="panel table-wrap"><table><caption>Fila de blockers</caption><thead><tr><th>Cliente</th><th>Instalação</th><th>Produto</th><th>Campo</th><th>Tipo de blocker</th><th>Prioridade</th><th>Problema</th><th>Última ocorrência</th><th>Ação</th></tr></thead><tbody>{% for item in result["items"] %}<tr><td>{{ item.client or "Cliente não identificado" }}</td><td>{{ item.display_name or "-" }}<small>{{ item.hostname or "hostname indisponível" }}</small></td><td><b>{{ item.product_code }}</b><small>{{ item.description or "" }}</small></td><td>{{ item.field or "OTHER" }}</td><td><span class="badge blocked">Fiscal: {{ item.blocker_type }}</span></td><td><span class="badge priority-{{ item.priority|lower }}">Prioridade: {{ item.priority }}</span></td><td>{{ item.reason }}<small>{{ item.age }}</small></td><td title="{{ item.last_seen_at }}">{{ item.last_seen_display }}<small>{{ item.retry_count }} tentativas</small></td><td><a class="secondary" href="{{ item.link }}">Ver detalhe</a></td></tr>{% else %}<tr><td colspan="9" class="empty-state">Nenhum blocker corresponde aos filtros.</td></tr>{% endfor %}</tbody></table></div>
|
||||
<nav class="pagination" aria-label="Paginação de blockers">{% if result.page > 1 %}<a href="/blockers?page={{ result.page - 1 }}{% if query_base %}&{{ query_base }}{% endif %}">Anterior</a>{% endif %}<span>Página {{ result.page }} · {{ result.total }} blockers</span>{% if result.page * result.page_size < result.total %}<a href="/blockers?page={{ result.page + 1 }}{% if query_base %}&{{ query_base }}{% endif %}">Próxima</a>{% endif %}</nav>
|
||||
{% endblock %}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</section>
|
||||
<section class="panel attention"><div class="panel-title"><div><p class="eyebrow">FILA DE AÇÃO</p><h2>ATENÇÃO NECESSÁRIA</h2></div><a href="/blockers">Ver todos</a></div>{% for item in summary.attention_items[:10] %}<a class="list-row" href="{{ item.link }}"><span><b>{{ item.client or "Cliente não identificado" }}</b> · {{ item.display_name or "Instalação" }}<small>{{ item.hostname or "hostname indisponível" }} · {{ item.problem }}</small></span><em class="badge {{ item.technical_health|lower }}">{{ item.age }}</em></a>{% else %}<p class="empty-state">Nenhum item requer atenção imediata.</p>{% endfor %}</section>
|
||||
<section class="split">
|
||||
<article class="panel"><div class="panel-title"><h2>Jobs com falha</h2><a href="/jobs?status=FAILED">Ver jobs</a></div>{% if summary.failed_jobs %}<p class="metric-inline"><strong>{{ summary.failed_jobs }}</strong> jobs aguardam investigação.</p><div class="table-wrap"><table><caption>Falhas recentes (máximo 10)</caption><thead><tr><th>Cliente</th><th>Instalação</th><th>Job ID / Tipo</th><th>Erro</th><th>Criado</th><th>Finalizado</th></tr></thead><tbody>{% for job in summary.recent_failed_jobs %}<tr><td>{{ job.client or "-" }}</td><td>{{ job.display_name or "-" }}<small>{{ job.hostname or "hostname indisponível" }}</small></td><td><a href="{{ job.link }}">{{ job.job_id }}</a><small>{{ job.kind }}</small></td><td>{{ job.error or "Sem detalhe de erro" }}</td><td title="{{ job.created_age }}">{{ job.created_display }}<small>{{ job.created_age }}</small></td><td title="{{ job.finished_age }}">{{ job.finished_display }}<small>{{ job.finished_age }}</small></td></tr>{% endfor %}</tbody></table></div>{% else %}<p class="empty-state">Nenhum job com falha.</p>{% endif %}</article>
|
||||
<article class="panel"><div class="panel-title"><h2>Jobs com falha</h2><a href="/jobs?status=FAILED">Ver jobs</a></div>{% if summary.failed_jobs %}<p class="metric-inline"><strong>{{ summary.failed_jobs }}</strong> jobs aguardam investigação.</p><div class="table-wrap"><table><caption>Falhas recentes (máximo 10)</caption><thead><tr><th>Cliente</th><th>Instalação</th><th>Job ID / Tipo</th><th>Erro</th><th>Criado</th><th>Finalizado</th></tr></thead><tbody>{% for job in summary.recent_failed_jobs %}<tr><td>{{ job.client or "-" }}</td><td>{{ job.display_name or "-" }}<small>{{ job.hostname or "hostname indisponível" }}</small></td><td><a href="{{ job.link }}">{{ job.job_id }}</a><small>{{ job.kind }}</small></td><td>{{ job.error or "Sem detalhe de erro" }}</td><td title="{{ job.created_at }}">{{ job.created_display }}<small>{{ job.created_age }}</small></td><td title="{{ job.finished_at }}">{{ job.finished_display }}<small>{{ job.finished_age }}</small></td></tr>{% endfor %}</tbody></table></div>{% else %}<p class="empty-state">Nenhum job com falha.</p>{% endif %}</article>
|
||||
<article class="panel"><div class="panel-title"><h2>Agents desatualizados</h2><a href="/agents?sort=worst_coverage">Ver agents</a></div>{% for item in summary.outdated_agents[:10] %}<a class="list-row" href="/agents/{{ item.agent_id }}"><span><b>{{ item.client }}</b> · {{ item.display_name }}<small>{{ item.hostname or "hostname indisponível" }} · {{ item.agent_version or "versão desconhecida" }}</small></span><em class="badge warning">Desatualizado</em></a>{% else %}<p class="empty-state">Nenhum agent desatualizado.</p>{% endfor %}</article>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
{% block content %}
|
||||
<div class="page-heading"><div><p class="eyebrow">EXECUÇÕES</p><h1>Jobs globais</h1><p class="muted">Acompanhe o que está em andamento e onde falhou.</p></div></div>
|
||||
<section class="panel"><form class="filters" method="get"><label>Status<select name="status"><option value="">Todos</option>{% for value in ["PENDING","RUNNING","COMPLETED","FAILED"] %}<option value="{{ value }}" {% if status_filter==value %}selected{% endif %}>{{ value }}</option>{% endfor %}</select></label><label>Cliente, instalação ou busca<input name="search" value="{{ search }}"></label><label>Tipo<input name="kind" value="{{ kind_filter }}"></label><button class="secondary" type="submit">Filtrar jobs</button></form></section>
|
||||
<div class="panel table-wrap"><table><caption>Execuções recentes</caption><thead><tr><th>Cliente</th><th>Nome de exibição</th><th>Hostname</th><th>Job ID</th><th>Tipo</th><th>Status</th><th>Criado</th><th>Finalizado</th><th>Duração</th><th>Erro</th></tr></thead><tbody>{% for item in result["items"] %}<tr><td>{{ item.client or "Cliente não identificado" }}</td><td>{{ item.display_name or "-" }}</td><td>{{ item.hostname or "-" }}</td><td>#{{ item.job_id }}<small>Agent técnico {{ item.agent_id }}</small></td><td>{{ item.kind }}</td><td><span class="badge status-{{ item.status|lower }}">Status: {{ item.status }}</span></td><td title="{{ item.created_display }}">{{ item.created_display }}</td><td title="{{ item.finished_display }}">{{ item.finished_display }}</td><td>{{ item.duration }}</td><td class="error-text">{{ item.error or "-" }}</td></tr>{% else %}<tr><td colspan="10" class="empty-state">Nenhum job encontrado para os filtros atuais.</td></tr>{% endfor %}</tbody></table></div>
|
||||
<div class="panel table-wrap"><table><caption>Execuções recentes</caption><thead><tr><th>Cliente</th><th>Nome de exibição</th><th>Hostname</th><th>Job ID</th><th>Tipo</th><th>Status</th><th>Criado</th><th>Finalizado</th><th>Duração</th><th>Erro</th></tr></thead><tbody>{% for item in result["items"] %}<tr><td>{{ item.client or "Cliente não identificado" }}</td><td>{{ item.display_name or "-" }}</td><td>{{ item.hostname or "-" }}</td><td>#{{ item.job_id }}<small>Agent técnico {{ item.agent_id }}</small></td><td>{{ item.kind }}</td><td><span class="badge status-{{ item.status|lower }}">Status: {{ item.status }}</span></td><td title="{{ item.created_at }}">{{ item.created_display }}</td><td title="{{ item.finished_at }}">{{ item.finished_display }}</td><td>{{ item.duration }}</td><td class="error-text">{{ item.error or "-" }}</td></tr>{% else %}<tr><td colspan="10" class="empty-state">Nenhum job encontrado para os filtros atuais.</td></tr>{% endfor %}</tbody></table></div>
|
||||
<nav class="pagination" aria-label="Paginação de jobs">{% if result.page > 1 %}<a href="/jobs?page={{ result.page - 1 }}{% if query_base %}&{{ query_base }}{% endif %}">Anterior</a>{% endif %}<span>Página {{ result.page }} · {{ result.total }} jobs</span>{% if result.page * result.page_size < result.total %}<a href="/jobs?page={{ result.page + 1 }}{% if query_base %}&{{ query_base }}{% endif %}">Próxima</a>{% endif %}</nav>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user