{# Backups. A backup is only worth anything at the moment someone is frightened, so the three facts that decide whether this is the right archive are in the row itself: when it was taken, how big it is, and what is inside it. Nothing has to be opened to choose. Restoring is the most destructive thing this panel can do. Its question names the archive, names the domain it lands on, and says in plain words that what is deployed there now is overwritten. #} {% extends "base.html" %} {% import "_macros.html" as m %} {% block title %}Backups{% endblock %} {% block content %} {{ m.page_head("Backups", storage.summary if rows else none) }} {# Loaded over htmx rather than rendered inline, so it lives entirely in views/backup_schedules.py and this page's handler does not have to know it exists. Listing the timers also runs two systemctl calls per schedule, which is work the first paint should not wait on. #}

Scheduled backups

Reading timers…
{% if rows %}
{% for backup in rows %} {% call m.row(backup.domain, backup.state, backup.meta, none, "row-" ~ backup.id, backup.note) %} {{ m.action_button("Verify", backup.verify_endpoint, none, backup.id ~ " is sound") }} {{ m.action_button("Restore", backup.restore_endpoint, backup.restore_question, "Restore started for " ~ backup.domain) }} {{ m.danger_button("Delete", backup.delete_endpoint, backup.id, "The archive is removed from disk and cannot be recovered.", backup.delete_question) }} {% endcall %} {% endfor %}
{% else %} {{ m.empty( "No backups yet", "A backup is a single archive holding the application files, its environment and, when you ask for them, its databases and volumes.", command="wasm backup create -d example.com") }} {% endif %} {% endblock %}