The tabs were drawn in each page's content block, which base.html renders after the breadcrumb, so on every nested Ansible page the strip moved down a line. base.html now has a section_tabs block above the breadcrumb, and every Ansible page fills it. A guard in test_breadcrumbs.py fails any page that calls a tabs macro outside that block. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
41 lines
2.6 KiB
HTML
41 lines
2.6 KiB
HTML
{# ansible/index.html — the Runs tab (#5329): a verdict line (how the last
|
|
30 days went, failures first, what runs next), a filter bar, then every run
|
|
newest first as the reader scrolls (ansible/_runs_table.html). #}
|
|
{% extends "base.html" %}
|
|
{% from "_macros.html" import page_header %}
|
|
{% from "ansible/_tabs.html" import ansible_tabs %}
|
|
{% block title %}Ansible Runs — Steward{% endblock %}
|
|
{% block section_tabs %}{{ ansible_tabs("runs") }}{% endblock %}
|
|
{% block content %}
|
|
{% call page_header("Ansible Runs") %}
|
|
<a href="/ansible/playbooks" class="btn">Run a playbook</a>
|
|
{% endcall %}
|
|
|
|
{% set v = verdict %}
|
|
<p class="page-verdict">
|
|
{%- if not v.total %}<span class="tone-muted">No runs in the last {{ v.days }} days</span>
|
|
{%- elif v.failed %}<span class="tone-crit">{{ v.failed }} of {{ v.total }} run{{ 's' if v.total != 1 }} failed</span> in the last {{ v.days }} days
|
|
{%- if v.latest_failed %} — latest <a href="/ansible/runs/{{ v.latest_failed.run.id }}">{{ v.latest_failed.title }}</a> {{ v.latest_failed.run.started_at|ago }}{% endif %}
|
|
{%- else %}<span class="tone-ok">{{ v.total }} run{{ 's' if v.total != 1 }} in the last {{ v.days }} days, {{ 'all' if v.total > 1 else 'it' }} succeeded</span>{% endif %}
|
|
{%- if v.running %} · <span class="tone-info">{{ v.running }} running now</span>{% endif %}
|
|
{%- if v.next %} · next: <a href="/ansible/schedules/{{ v.next.id }}">{{ v.next.name }}</a> {% if v.next.at %}{{ v.next.at|ago }}{% else %}due now{% endif %}{% endif -%}
|
|
</p>
|
|
|
|
<form class="filter-bar" method="get" action="/ansible/" role="search"
|
|
hx-target="#runs-table" hx-push-url="true" hx-include="closest form">
|
|
<input type="search" name="q" value="{{ f.q }}" class="input" placeholder="Search playbooks"
|
|
aria-label="Search runs by playbook" autocomplete="off"
|
|
hx-get="/ansible/" hx-trigger="input changed delay:250ms, search">
|
|
<select name="status" aria-label="Status" hx-get="/ansible/" hx-trigger="change">
|
|
<option value="">Any status</option>
|
|
{% for key, (label, _) in statuses.items() %}<option value="{{ key }}"{% if f.status == key %} selected{% endif %}>{{ label }}</option>{% endfor %}
|
|
</select>
|
|
<select name="origin" aria-label="Started by" hx-get="/ansible/" hx-trigger="change">
|
|
<option value="">Started by anyone</option>
|
|
{% for key, label in origins.items() %}<option value="{{ key }}"{% if f.origin == key %} selected{% endif %}>{{ label }}</option>{% endfor %}
|
|
</select>
|
|
<noscript><button type="submit" class="btn btn-sm">Filter</button></noscript>
|
|
</form>
|
|
<div id="runs-table">{% include "ansible/_runs_table.html" %}</div>
|
|
{% endblock %}
|