{% extends "base.html" %} {% block title %}{{ t('schedules.title') }} — painfree{% endblock %} {% block body %}

{{ t('schedules.heading') }}

{{ t('schedules.lede') }}

{# The reason an operator opens this page. Above the table, before any filter. `failing` is derived from the engine's own return-code table, so a `090005` cannot end up here. #} {% if failing %}

{{ t('schedules.failing_heading', count=failing | length) }}

{{ t('schedules.failing_why') }}

{% endif %} {% if behind %}

{{ t('schedules.behind_heading', count=behind | length) }}

{{ t('schedules.behind_why') }}

{% endif %}
{% if may('schedules:manage') %} {{ t('schedules.add') }} {% endif %}
{% if schedules %} {# Four columns and a picture. Health is the stripe down the left edge rather than a column of its own, and the BTF triplet -- read when a bank changes it and not before -- folds into the schedule's own cell. #} {% for row in schedules %} {% set window = windows[row.schedule_id] %} {% endfor %}
{{ t('schedules.schedule') }}{{ t('schedules.coverage') }} {{ t('schedules.last_run') }}{{ t('schedules.next_due') }}
{{ row.description or row.label }} {{ row.label }} {{ t('schedules.on') }} {{ row.connection_id }} · {{ row.cadence.total_seconds() | int | cadence }} {{ row.health }} {% if row.running %}{{ t('schedules.running_now') }}{% endif %} {# Every value in here is a protocol identifier and none is translated. #}
{{ t('schedules.fetches') }} {{ t('schedules.service') }} {{ row.service_name }}{% if row.scope %}, {{ t('schedules.scope') }} {{ row.scope }}{% endif %}{% if row.container %}, {{ row.container }}{% endif %} {{ row.schedule_id }}
{% if window.dated %} {# Fetched solid, outstanding hatched. The span is the window the next run asks for, so an up-to-date schedule is one day of it and a schedule a fortnight behind is thirteen. #} {# Three states, and the middle one is why the arithmetic and the words have to agree: a schedule that has never fetched anything is not *behind*, however wide the window it is about to ask for. Red is overdue, neutral is not started, solid is covered. #}
{% if row.fetched_through %}{{ t('schedules.covered_through') }} {{ row.fetched_through | day }} {% else %}{{ t('schedules.nothing_yet') }}{% endif %} {% if window.behind %}{{ t('schedules.days_outstanding', count=window.days_behind) }} {% elif row.fetched_through %}{{ t('schedules.up_to_date') }} {% else %}{{ t('schedules.days_outstanding', count=window.days_pending) }}{% endif %}
{% else %} {{ t('schedules.no_date_range') }} {% endif %}
{% if last_runs[row.schedule_id] %} {% set run = last_runs[row.schedule_id] %} {{ run.state }} {% if run.state == 'empty' %}{{ t('schedules.bank_had_nothing') }} {% elif run.state == 'complete' %}{{ t('schedules.statement_count', count=run.statements) }} {% elif run.return_code %}{{ run.return_code }}{% endif %} {{ row.last_run_at | moment }} {% else %} {{ t('schedules.never_run') }} {% endif %} {{ row.due_at | moment }}
{% else %}

{{ t('schedules.empty') }}

{% endif %}
{% endblock %}