{% 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 Local copy Action
{% for n in u.names %} {{ n }}{% if not loop.last %}, {% endif %} {% endfor %} {% if u.sha256 %} {% 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 %} yes {% else %} no {% endif %} {# All four actions always render so the column is visually consistent row-to-row; each is ``disabled`` when its applicability gate is false, with a tooltip explaining why. The operator scanning the column sees the same shape every row; what changes is which buttons are bright vs. greyed out. Gates by source shape: - Fetch: has-remote AND not-cached (bytes need to land locally). - Update: has-remote AND cached (re-pull the upstream bytes; rolling oras tags). - Cache delete: has-remote AND cached (drop the local copy; entry stays). - Entry delete: has-remote (remove the catalog row entirely). Local-only uploads aren't deletable here -- the operator manages those via the filesystem. Hashing has no manual button: every path that lands bytes in image_root (PUT /images, lifespan auto-import, DownloadManager fetch) already auto-enqueues / computes the sha. The only state a manual Hash would help is an operator dropping a file via SSH/scp at runtime; that's a rare-enough workflow that "restart bty-web" is the accepted answer. /ui/hashing still shows background hash progress driven by the auto-import sweep. #} {% 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 %} {% set fetch_on = has_remote and not u.cached %} {% set update_on = has_remote and u.cached %} {% set cache_del_on = has_remote and u.cached %} {% set entry_del_on = has_remote %}
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 %}