{% extends "ui/_layout.html" %} {% block title %}Images - bty-web{% endblock %} {% block subnav %} {# In-page jump links: List + Activity. The Downloads / Hashes sub-sections are gone -- their live status lives on /ui/downloads + /ui/hashing. #} {% endblock %} {% block intro %} {% from "ui/_intro_box.html" import render as intro_box %} {% call intro_box() %} Pre-built system images bty flashes onto target disks, content- addressed by sha256. This is the merged catalog (dir scan + catalog entries): the header carries Fetch latest catalog (pull the bty release catalog) and Upload catalog (a catalog.toml). Files dropped into {{ image_root }} are picked up and hashed automatically; per-row Fetch / Hash buttons enqueue jobs visible on the Downloads / Hashing pages. Add a single image (URL or upload) from Downloads. {% endcall %} {% endblock %} {% block content %} {# Catalog list: the operator's "what images do I have" view. Header carries the two catalog-shape actions (Upload catalog / Fetch latest catalog). The per-row Action column triggers fetch / hash / cache- delete / entry-delete; results show on /ui/downloads + /ui/hashing. #}
Images
{% for u in unified %} {% endfor %} {% if not unified %} {% endif %}
Name(s) Content SHA Format Sources Cached Action
{% for n in u.names %} {{ n }}{% if not loop.last %}, {% endif %} {% endfor %} {% if u.sha256 %} {{ u.sha256[:12] }}... {% else %} unhashed {% endif %} {{ u.format or "?" }} {% for s in u.sources %} {% if s.kind == "local" %} {{ s.location }} {% elif s.kind == "url" %} {{ s.location }} {% else %} {{ s.location }} {% endif %} {% if not loop.last %}
{% endif %} {% endfor %}
{% if u.cached %} cached {% else %} available {% endif %} {# Dispatch by source shape, not just sha presence: - Has a ``local`` source and no sha -> file on disk needs hashing. Hash button. - No local source -> bytes need fetching. Fetch button. Works for un-sha'd URL / oras entries (the DownloadManager downloads + computes sha + back-fills catalog_entries.disk_image_sha) AND for sha-pinned entries not yet in cache. #} {% set has_local = u.sources|selectattr('kind','equalto','local')|list|length > 0 %} {% set has_remote = u.sources|selectattr('kind','in',['manifest','url'])|list|length > 0 %} {% set entry_src = u.sources|selectattr('kind','in',['manifest','url'])|map(attribute='location')|first %} {# Render per-row actions as a Bootstrap btn-group so the buttons sit flush -- same idiom as the Backups page's Download + Delete. The group is omitted entirely when no action applies (sha- pinned + cached + has_remote=False), in which case the cell shows a muted dash. #} {% if has_remote or u.cached or (not u.sha256 and has_local) %}
{% if not u.sha256 and has_local %} {% elif not u.cached %} {% endif %} {% if u.cached and has_remote %} {% endif %} {% if has_remote %} {% endif %}
{% else %} - {% endif %}
No images yet. Use Fetch latest or Upload catalog above, drop a .qcow2 / .img / .img.zst / .img.xz / .img.gz / .img.bz2 file into {{ image_root }}, or add one via the Add image card below.
{# Image-relevant event slice (uploads, hashes, catalog adds / deletes). #} {% with events=image_events, title="Recent Events", link_to_full="/ui/events?subject_kind=image", card_id="images-activity" %} {% include "ui/_events_card.html" %} {% endwith %} {% endblock %}