{# One line of the server table, from the ``row`` in context. Returned on its own as the answer to a toggle, which is why it is a template rather than a macro and why it starts at the ````: htmx replaces the row it came from with exactly this. Every action is a real form with a real ``action``, and htmx only intercepts it. Without the script the operator still gets a button posting to the same route, which is also what makes the routes testable without a browser. #} {% from "partials/status_badge.html" import status_badge %} {% from "partials/confirm.html" import confirm %} {% from "partials/tool_counts.html" import tool_counts %} {% from "partials/toggle_button.html" import toggle_button %} {# A name, and nothing else. The flags that used to sit here are status, and they are now under the heading that says so (task 106). #} {{ row.server.name }} {# The built-in server has no base URL because it makes no request. The cell says what it does instead, rather than showing an empty box the operator would read as a broken row (task 102) — and says the whole of it here, including that it cannot be deleted, so that the Actions column holds nothing but buttons (task 106). #} {% if row.origin_note %} {{ row.origin_note }} {% else %} {{ row.server.base_url }} {% endif %} {# What the server is doing: the counts first, because they are true of it whatever else is going on, then the news. There is no Enabled or Disabled badge — the Actions column says which by offering the other one, and a green 0 beside a button reading Enable is not ambiguous (task 106). #} {{ tool_counts(row.counts) }} {% if row.server.counts.new %} {{ status_badge("new", label="%d new"|format(row.server.counts.new)) }} {% endif %} {# Two flags, and they are not the same news. A refresh diff is work waiting on the operator; a server the gateway itself took out of the list is something broken upstream. The second says so in its own words, under its own badge, so neither can be mistaken for the other (task 100). #} {% if row.flagged_by_gateway %} {{ status_badge(row.attention_status, label=row.attention_label, title=row.attention_title) }} {{ row.server.attention_reason }} {% elif row.server.needs_attention %} {{ status_badge("attention", title=row.unreviewed_title) }} {% endif %} {# The built-in server has no document to read, so it gets a word rather than a badge dating an event that cannot happen to it (task 102). #} {% if row.spec_note %} {{ row.spec_note }} {% else %} {{ status_badge(row.state, label=row.refreshed, title=row.refresh_title) }} {% endif %} {# The way in to everything that can be changed. The name links here too, but a name does not look like a way in, and the operator looking for one is looking in this column. Shown for the built-in server as well: the page it opens is where that server's tools are listed, even though its settings are not an operator's to change. #} Edit {# The switch, as an action. It posts what the checkbox posted, to the route the checkbox posted to, so htmx still swaps this row in place and a browser that never ran the script still works. The same partial the detail page's toolbar uses, told to answer with a row and to come back here (task 112). #} {{ toggle_button(row, back="list", target="closest tr") }} {# A real form and a whole page, not an htmx swap: a refresh fetches an upstream document, and the answer belongs on a page that shows what came of it. ``back`` says which of the two pages offering this button it was pressed on, and is two literals rather than a path — a redirect target taken from a form is a redirect target an attacker can write. #} {% if row.refreshable %}
{% endif %} {# No Delete for the gateway's own server, and nothing in its place: the Base URL cell has already said why, and a column of buttons is a poor home for a sentence (task 106). The rule that refuses it lives in the repository, so a hand-made request is refused too (task 102). #} {% if row.deletable %} {{ confirm( row.delete_path, "Delete", row.delete_question, target=list_target, swap="outerHTML") }} {% endif %}