{# One window of usage: the selector, the charts, the strip, the failures. An ordinary template rather than a macro, like the server list: it is also returned on its own, as the answer to a range button and to the timer, and a macro rendered as a response would produce an empty body. Its context is what ``monitoring.context`` builds. All of it lives inside ``usage_id`` on purpose. Everything here describes one span of time, so everything here is replaced at once — a swap that left the failures list from the previous range beside the new charts would be two answers to two different questions on one screen. The selector is inside the region too, because which range is current is part of the answer: the button that lights up has to change with the charts. Each is a real link as well as an htmx request, so a browser running no script at all still changes range, by loading the whole page. #}

{{ view.covers }}, one point per {{ view.resolution }}.

{# Un-hidden by the script when an update did not arrive. The wording is here rather than in the script so that what the page says when it is failing is a sentence with a test behind it. #}
Tool calls
{{ view.tool_calls }}
Failed
{{ view.totals.errors }}
{# Beside the calls rather than only on its own chart: the charts need a script and this does not, and a page that could not draw the fourth one would otherwise say nothing at all about a limit that is being hit. #}
Throttled
{{ view.totals.throttled }}
Sent
{{ view.sent }}
Received
{{ view.received }}
tools/list
{{ view.listings }}
{% for chart in view.charts %}

{{ chart.title }}

{{ chart.note }}

{# The one thing on this page that survives a swap. Chart.js works out the pixel size of a canvas when it builds a chart on it, and building one in the middle of a swap means measuring a box the browser has not finished with — which leaves a canvas that draws as nothing until something changes its size. htmx puts this node back where it was, so the measurement happens once, at load, and a range switch hands the chart already on this canvas new numbers instead of a new canvas (task 124). The frame and not the figure: the caption, the fallback line and the note an empty window shows all change with the range. #}
{# Replaced by the drawing when there is a script to draw it. #}

{{ no_charts }}

{% if chart.empty %}

{{ chart.empty_note }}

{% endif %}
{% endfor %} {# What the script draws. Not executable: the browser stores it, the script reads it, and Jinja escapes it so that a server named after a closing tag cannot end the block early. #}

Servers

{% if view.servers %} {% from "partials/status_badge.html" import status_badge %} {% for row in view.servers %} {% endfor %}
Server Status Last spec download Calls Errors Sent Received
{% if row.detail_path %} {{ row.name }} {% else %} {{ row.name }} {% endif %} {% if row.deleted %} {{ status_badge("removed", label="Deleted") }} {% else %} {{ status_badge("enabled" if row.enabled else "disabled") }} {% if row.needs_attention %} {{ status_badge("attention") }} {% endif %} {% endif %} {% if row.deleted %} {{ not_recorded }} {% else %} {# One badge carrying the age, exactly as the server list writes it: the two pages answer the same question and must look like it. #} {{ status_badge(row.state, label=row.refreshed, title=row.refreshed_at) }} {% endif %} {{ row.totals.calls }} {{ row.totals.errors }} {{ row.sent }} {{ row.received }}
{% else %}

{{ no_servers }}

{% endif %}

Recent failures

{% if view.failures %} {% for failure in view.failures %} {{ failure.when }} {% endfor %}
When Server Tool Status What happened
{% if failure.server_path %} {{ failure.server }} {% else %} {{ failure.server }} {% endif %} {{ failure.tool }} {{ failure.status }} {{ failure.message }}
{% else %}

{{ no_failures }}

{% endif %}