Files
guarddog-nexus/guarddog_nexus/web/templates/dashboard_stats.html
Marker689 1341404568 fix: аудит — 19 фиксов безопасности, надёжности, UI и 16 новых тестов
- S4: bump jinja2>=3.1.4, python-multipart>=0.0.18, httpx>=0.28.0
- S5: _detect_ecosystem — DEFAULT_ECOSYSTEM для неизвестных форматов
- S6: harvester — log.exception() вместо log.error()
- S8: _scan_component — urlencode параметров
- P1: scanner — proc.kill() при таймауте
- P3: api_packages — selectinload(Scan.findings), убран N+1
- P4+P5: утечка _url_locks и _llm_locks при early return
- P6: DB reaper — сброс {'status':'analyzing'} при старте
- UI: htmx-пагинация, фильтры не теряют flagged, 404 с layout
- UI: мобильные таблицы overflow-x, полная стата на дашборде
- UI: i18n статусов в _status_badge, urlencode package_name
- 16 новых тестов: analyze endpoint (6), scanner errors (4),
  webhook signature (2), llm client (4)
2026-05-10 10:45:44 +03:00

66 lines
3.4 KiB
HTML

{% if total_findings %}
<div style="display:flex; gap:1.5rem; padding:0.3rem 0; margin-bottom:1rem; border-bottom:1px solid var(--pico-color-gray-500); font-size:0.82rem; opacity:0.8; flex-wrap:wrap;">
<span>{{ t('total_scans_label', request.state.lang) }}: <strong>{{ total_scans }}</strong></span>
<span>{{ t('flagged_scans_label', request.state.lang) }}: <strong>{{ flagged_scans }}</strong></span>
<span>{{ t('col_findings', request.state.lang) }}: <strong>{{ total_findings }}</strong></span>
<span>{{ t('llm_analyzed', request.state.lang) }}: <strong>{{ llm_analyzed }}</strong></span>
<span>{{ t('llm_pending', request.state.lang) }}: <strong>{{ llm_pending }}</strong></span>
</div>
{% endif %}
{% if top_rules %}
<article class="dash-block" style="margin-bottom:1rem;">
<h3>{{ t('heading_top_rules', request.state.lang) }}</h3>
<table class="compact">
<tbody>
{% for r in top_rules %}
<tr><td><strong>{{ r.rule }}</strong></td><td>{{ r.count }}</td></tr>
{% endfor %}
</tbody>
</table>
</article>
{% endif %}
{% if latest_flagged %}
<article class="dash-block dash-block-warn">
<h3>{{ t('heading_latest_flagged', request.state.lang) }}</h3>
<table class="compact">
<thead><tr><th>{{ t('col_package', request.state.lang) }}</th><th>{{ t('col_version', request.state.lang) }}</th><th>{{ t('col_findings', request.state.lang) }}</th><th>{{ t('col_time', request.state.lang) }}</th></tr></thead>
<tbody>
{% for s in latest_flagged %}
<tr>
<td><a href="/scans/{{ s.id }}"><strong class="flagged">{{ s.package_name }}</strong></a></td>
<td>{{ s.package_version }}</td>
<td><span class="flagged">{{ s.total_findings }}</span></td>
<td>{{ s.started_at.strftime('%m-%d %H:%M') if s.started_at }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</article>
{% endif %}
<article class="dash-block" style="margin-top: 0;">
<h3>{{ t('heading_latest_scans', request.state.lang) }}</h3>
<table class="compact">
<thead>
<tr><th>{{ t('col_package', request.state.lang) }}</th><th>{{ t('col_version', request.state.lang) }}</th><th>{{ t('col_repo', request.state.lang) }}</th><th>{{ t('col_status', request.state.lang) }}</th><th></th><th>{{ t('col_time', request.state.lang) }}</th></tr>
</thead>
<tbody>
{% for s in latest_scans %}
<tr>
<td><a href="/packages/{{ s.package_name | urlencode }}/{{ s.package_version | urlencode }}">{{ s.package_name }}</a></td>
<td>{{ s.package_version }}</td>
<td><small>{{ s.repository }}</small></td>
<td>
{% with status=s.status %}{% include "_status_badge.html" %}{% endwith %}
</td>
<td>{% if s.flagged %}<span class="flagged">⚠ {{ s.total_findings }}</span>{% elif s.status == 'completed' %}<span class="clean"></span>{% else %}<span>-</span>{% endif %}</td>
<td>{{ s.started_at.strftime('%m-%d %H:%M') if s.started_at }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<small><a href="/scans">{{ t('view_all_scans', request.state.lang) }}</a></small>
</article>
<small style="opacity: 0.4;">{{ t('refresh_hint', request.state.lang, now.strftime('%H:%M:%S')) }}</small>