{# 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). #}
{# 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 %}