Files
FabledSteward/steward/templates/ansible/schedules.html
T
bvandeusenandClaude Opus 5.5 0c72892f58
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 59s
CI / unit (push) Failing after 1m22s
CI / publish (push) Skipped
feat(ansible): schedules read as sentences, each with its own page (#5332)
- The Schedules tab: a verdict line (failing first, paused, next due),
  each schedule as one line (what runs where, how often, when next, how it
  last went); the row opens its page; Run now and Pause stay in the row.
- /ansible/schedules/new and /ansible/schedules/<id>: the form on classes,
  dry run beside the button, the playbook's variables rendered with the
  page; at the foot Delete behind the confirm dialog. ?source=&playbook=
  start a new one on a playbook (Schedule it on the playbook's page).
- A run started by a schedule links to that schedule's page.
- The run page's id guard allows the Run again link's ?from=.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 23:51:15 -04:00

69 lines
3.5 KiB
HTML

{# ansible/schedules.html — the Schedules tab (#5332): a verdict line, then
each schedule as one sentence (what runs where, how often, when next, how
it last went), failing first and paused last. The whole row opens the
schedule's page; Run now and Pause stay in the row. #}
{% extends "base.html" %}
{% from "_macros.html" import crumbs, page_header, status_badge, empty_state %}
{% from "ansible/_tabs.html" import ansible_tabs %}
{% from "ansible/_macros.html" import interval_words %}
{% block title %}Ansible Schedules — Steward{% endblock %}
{% block breadcrumb %}{{ crumbs([("Ansible", "/ansible/"), ("Schedules", "")]) }}{% endblock %}
{% block content %}
{% set can_edit = session.user_role in ('operator', 'admin') %}
{{ ansible_tabs("schedules") }}
{% call page_header("Schedules") %}
{% if can_edit %}<a href="/ansible/schedules/new" class="btn">New schedule</a>{% endif %}
{% endcall %}
{% if not rows %}
<div class="card">{{ empty_state("Nothing runs on a schedule yet.", "New schedule" if can_edit else none, "/ansible/schedules/new" if can_edit else none) }}</div>
{% else %}
<p class="page-verdict">
{%- if failing %}<span class="tone-crit">{{ failing }} of {{ rows|length }} failing</span>
{%- else %}<span class="tone-ok">{{ rows|length }} schedule{{ 's' if rows|length != 1 }}, {{ 'none' if rows|length > 1 else 'not' }} failing</span>{% endif %}
{%- if paused %} · {{ paused }} paused{% endif %}
{%- if next %} · next: <a href="/ansible/schedules/{{ next.id }}">{{ next.name }}</a> {% if next.at %}{{ next.at|ago }}{% else %}due now{% endif %}{% endif -%}
</p>
<div class="card-flush">
<table class="table">
<thead><tr><th>Schedule</th><th>When</th><th>Last run</th><th></th></tr></thead>
<tbody>
{% for row in rows %}
{% set s = row.s %}
<tr class="row-link{% if not s.enabled %} row-off{% endif %}">
<td class="cell-name playbook-cell">
<a class="row-target" href="/ansible/schedules/{{ s.id }}">{{ s.name }}</a>
<div class="cell-sub"><span class="mono">{{ s.playbook_path }}</span> on {{ row.scope_label }}
{%- if (s.params or {}).get('check') %} · <span class="tone-info">dry run</span>{% endif %}</div>
</td>
<td class="nowrap">
{{ interval_words(s.interval_seconds) }}
<div class="cell-sub">{% if not s.enabled %}paused{% elif row.next and row.next.at %}next {{ row.next.at|ago }}{% else %}due now{% endif %}</div>
</td>
<td>
{%- if row.last_run %}{{ status_badge(row.last_run.status) }} <span class="tone-muted">{{ row.last_run.started_at|ago }}</span>
{%- elif not s.last_error %}<span class="tone-dim">never run</span>{% endif %}
{%- if s.last_error %}
{#- With a run beside it, the last firing was skipped because that run was
still going (#5158); without one, the firing couldn't start a run. #}
<div class="cell-sub {{ 'tone-muted' if row.last_run else 'tone-crit' }}" title="{{ s.last_error }}">{{ s.last_error }} · {{ s.last_run_at|ago }}</div>
{%- endif %}
</td>
<td class="td-actions">
{% if can_edit %}
<form method="post" action="/ansible/schedules/{{ s.id }}/run-now" class="inline-form">{{ csrf_field() }}
<button class="btn btn-sm btn-ghost" type="submit">Run now</button>
</form>
<form method="post" action="/ansible/schedules/{{ s.id }}/toggle" class="inline-form">{{ csrf_field() }}
<button class="btn btn-sm btn-ghost" type="submit">{{ "Pause" if s.enabled else "Resume" }}</button>
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% endblock %}