- /plugins/syslog/sources/<id>: the lines newest first, loading as you scroll, filtered by severity and worse, app, text and time, with day dividers and times to the second in the reader's zone. - The Syslog page links each source and shows its lines in the last hour. - A Syslog panel on a host's page and an SNMP device's: the newest lines of the sources bound to it or at its address. - MCP: list_syslog_sources and search_syslog (source, host, text, severity and worse, app, range, paging by next_before). - Shared: escape_like moves to steward/core/like.py and cut_middle to the MCP shaping module, replacing four inline copies; |when takes seconds=. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
42 lines
2.8 KiB
HTML
42 lines
2.8 KiB
HTML
{# plugins/syslog/templates/syslog/source.html — one source's kept lines,
|
|
newest first, under a filter bar: severity and worse, app, text, time
|
|
(#6000). The table loads further pages as the reader scrolls. #}
|
|
{% extends "base.html" %}
|
|
{% from "_macros.html" import crumbs, page_header %}
|
|
{% block title %}{{ source.name }} — Syslog — Steward{% endblock %}
|
|
{% block breadcrumb %}{{ crumbs([("Syslog", "/plugins/syslog/"), (source.name, "")]) }}{% endblock %}
|
|
{% block content %}
|
|
{% call page_header(source.name, source.address) %}
|
|
{% if session.user_role == 'admin' %}<a href="/plugins/syslog/sources/{{ source.id }}/edit" class="btn btn-sm btn-ghost">Edit</a>{% endif %}
|
|
{% endcall %}
|
|
|
|
<p class="page-verdict">
|
|
{%- if source.state != 'accepted' %}<span class="tone-warn">Not added: its lines are counted, not kept.</span>
|
|
{%- else %}{{ "{:,}".format(source.rate or 0) }} line{{ "s" if source.rate != 1 }} in the last hour{% endif %}
|
|
· last heard {{ source.last_seen_at|ago }}
|
|
{%- if source.host %} · on <a href="/hosts/{{ source.host.id }}">{{ source.host.name }}</a>{% endif %}
|
|
{%- if source.hostname_seen and source.hostname_seen != source.name %} · calls itself {{ source.hostname_seen }}{% endif %}
|
|
</p>
|
|
|
|
<form class="filter-bar" method="get" action="/plugins/syslog/sources/{{ source.id }}" role="search"
|
|
hx-target="#syslog-lines" hx-push-url="true" hx-include="closest form">
|
|
<input type="search" name="q" value="{{ f.text }}" class="input" placeholder="Search lines"
|
|
aria-label="Search the lines' text" autocomplete="off"
|
|
hx-get="/plugins/syslog/sources/{{ source.id }}" hx-trigger="input changed delay:250ms, search">
|
|
<select name="severity" aria-label="Severity" hx-get="/plugins/syslog/sources/{{ source.id }}" hx-trigger="change">
|
|
<option value="">Any severity</option>
|
|
{% for value, label in severities %}<option value="{{ value }}"{% if f.severity is not none and f.severity|string == value %} selected{% endif %}>{{ label }}</option>{% endfor %}
|
|
</select>
|
|
<select name="app" aria-label="App" hx-get="/plugins/syslog/sources/{{ source.id }}" hx-trigger="change">
|
|
<option value="">Any app</option>
|
|
{% for a in apps %}<option value="{{ a }}"{% if f.app == a %} selected{% endif %}>{{ a }}</option>{% endfor %}
|
|
{% if f.app and f.app not in apps %}<option value="{{ f.app }}" selected>{{ f.app }}</option>{% endif %}
|
|
</select>
|
|
<select name="range" aria-label="How far back" hx-get="/plugins/syslog/sources/{{ source.id }}" hx-trigger="change">
|
|
{% for r in ranges %}<option value="{{ r }}"{% if f.range == r %} selected{% endif %}>Last {{ r }}</option>{% endfor %}
|
|
</select>
|
|
<noscript><button type="submit" class="btn btn-sm">Filter</button></noscript>
|
|
</form>
|
|
<div id="syslog-lines">{% include "syslog/_lines_table.html" %}</div>
|
|
{% endblock %}
|