feat(hosts): the Hosts list searches, filters by group and status, sorts by column, and shows each host's groups (#5294)
CI / lint (push) Successful in 2s
CI / integration (push) Failing after 52s
CI / unit (push) Successful in 1m17s
CI / publish (push) Skipped

#5294 "Hosts list: search, group and status filters; sortable columns; a Groups column".
Ansible inventory groups are Steward's grouping system (operator's ruling): a host's
groups are its linked target's, and membership overlaps, so the list filters by group
rather than sectioning by it.

- Filter bar: search on name or address, a group (or "No group"), a status (Down,
  Agent silent, Up, No monitors). The table swaps in alone and the URL keeps the filters.
- Name, Status, Latency, 30d uptime, CPU and Memory headers sort (sort_th in _macros);
  problems-first stays the default, and a host with no value goes last either way.
- A Groups column of chips, each filtering to its group; shown when any group exists.
- A swap is keyed on HX-Target, so Back to a pushed URL still gets the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 18:53:03 -04:00
co-authored by Claude Opus 5.5
parent a92eb8001b
commit 2990113e10
8 changed files with 423 additions and 85 deletions
+10
View File
@@ -101,3 +101,13 @@
{%- if cols %}<tr><td colspan="{{ cols }}"><span class="field-hint" role="status">{{ text }}</span></td></tr>
{%- else %}<p class="field-hint" role="status">{{ text }}</p>{% endif %}
{%- endmacro %}
{# A table header that sorts its column (#5294). `url` is the list with this
column as the sort (the route builds it, keeping the other filters);
`active` and `desc` say whether it is the current sort and which way.
A plain link: the whole page reloads, so the filter bar stays in step. #}
{% macro sort_th(label, url, active=false, desc=false, cls=none, title=none) -%}
<th{% if cls %} class="{{ cls }}"{% endif %}{% if title %} title="{{ title }}"{% endif %} aria-sort="{{ ('descending' if desc else 'ascending') if active else 'none' }}">
<a class="sort-link{% if active %} sort-active{% endif %}" href="{{ url }}">{{ label }}<span class="sort-arrow" aria-hidden="true">{% if active %}{{ '↓' if desc else '↑' }}{% endif %}</span></a>
</th>
{%- endmacro %}