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>
82 lines
3.9 KiB
HTML
82 lines
3.9 KiB
HTML
{# ansible/playbook.html — one playbook's page (#5331): what it says it does
|
|
and how it last ran, the form that runs it (operators), the schedules that
|
|
use it, its recent runs, then the playbook itself, folded. #}
|
|
{% extends "base.html" %}
|
|
{% from "_macros.html" import crumbs, page_header, status_badge %}
|
|
{% from "ansible/_tabs.html" import ansible_tabs %}
|
|
{% from "ansible/_macros.html" import interval_words %}
|
|
{% block title %}{{ playbook_path }} — Steward{% endblock %}
|
|
{% block breadcrumb %}{{ crumbs([("Ansible", "/ansible/"), ("Playbooks", "/ansible/playbooks"), (playbook_path, "")]) }}{% endblock %}
|
|
{% block section_tabs %}{{ ansible_tabs("playbooks") }}{% endblock %}
|
|
{% block content %}
|
|
{% set can_run = session.user_role in ('operator', 'admin') %}
|
|
{% call page_header(playbook_path) %}
|
|
{% if editable and session.user_role == 'admin' %}
|
|
<a href="/ansible/playbooks/edit/{{ source_name }}/{{ playbook_path }}" class="btn btn-sm btn-ghost">Edit</a>
|
|
<form method="post" action="/ansible/playbooks/delete"
|
|
data-confirm="Delete {{ playbook_path }}? The file is removed from {{ source_name }}; its past runs stay in the list.">{{ csrf_field() }}
|
|
<input type="hidden" name="source_name" value="{{ source_name }}">
|
|
<input type="hidden" name="playbook_path" value="{{ playbook_path }}">
|
|
<button type="submit" class="btn btn-sm btn-danger">Delete</button>
|
|
</form>
|
|
{% endif %}
|
|
{% endcall %}
|
|
|
|
<p class="page-verdict">
|
|
{%- if category %}<span class="chip">{{ category }}</span> {% endif -%}
|
|
{{ description or "It says nothing about what it does." }}
|
|
{%- if confirm %} · <span class="tone-warn">flagged destructive by its author: a real run asks you to confirm</span>{% endif %}
|
|
· from <span class="mono">{{ source_name }}</span>
|
|
{%- if runs %} · last ran {{ runs[0].run.started_at|ago }} {{ status_badge(runs[0].run.status) }}{% else %} · never run{% endif -%}
|
|
</p>
|
|
|
|
{% if can_run %}
|
|
<section class="card" aria-labelledby="pb-run">
|
|
<h2 id="pb-run" class="section-title">Run it</h2>
|
|
{% include "ansible/_run_form.html" %}
|
|
</section>
|
|
{% endif %}
|
|
|
|
<section class="card-flush" aria-labelledby="pb-schedules">
|
|
<h2 id="pb-schedules" class="table-caption">Schedules
|
|
{%- if schedules %} <span class="tone-muted">{{ schedules|length }}</span>{% endif %}
|
|
{%- if can_run %} <a class="field-hint" href="/ansible/schedules/new?source={{ source_name|urlencode }}&playbook={{ playbook_path|urlencode }}">Schedule it →</a>{% endif %}</h2>
|
|
{% if schedules %}
|
|
<table class="table">
|
|
<tbody>
|
|
{% for row in schedules %}{% set s = row.s %}
|
|
<tr class="row-link{% if not s.enabled %} row-off{% endif %}">
|
|
<td class="cell-name"><a class="row-target" href="/ansible/schedules/{{ s.id }}">{{ s.name }}</a></td>
|
|
<td>on {{ row.scope_label }} · {{ interval_words(s.interval_seconds) }}</td>
|
|
<td class="nowrap">{% if not s.enabled %}<span class="tone-dim">paused</span>
|
|
{%- elif row.next and row.next.at %}next {{ row.next.at|ago }}{% else %}due now{% endif %}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
{% else %}
|
|
<p class="field-hint card-flush-note">No schedule runs it.</p>
|
|
{% endif %}
|
|
</section>
|
|
|
|
<section class="card-flush" aria-labelledby="pb-runs">
|
|
<h2 id="pb-runs" class="table-caption">Recent runs
|
|
{%- if runs %} <a class="field-hint" href="/ansible/?q={{ playbook_path|urlencode }}">All its runs →</a>{% endif %}</h2>
|
|
{% if runs %}
|
|
<table class="table">
|
|
<thead><tr><th>Run</th><th>Result</th><th>Started by</th><th>Started</th><th class="num">Took</th></tr></thead>
|
|
<tbody>
|
|
{% with compact=true, more_url=none %}{% include "ansible/_runs_page.html" %}{% endwith %}
|
|
</tbody>
|
|
</table>
|
|
{% else %}
|
|
<p class="field-hint card-flush-note">It has not been run yet.</p>
|
|
{% endif %}
|
|
</section>
|
|
|
|
<details class="card playbook-source">
|
|
<summary class="section-title">The playbook</summary>
|
|
<pre class="run-log">{{ contents }}</pre>
|
|
</details>
|
|
{% endblock %}
|