sortable.js 0.8.0 (abandoned since 2014) sorted only a table's first
body: in the grouped VM list the first host's row moved among its VMs
and the other hosts never sorted, and memory sorted as text ("1024 MB"
before "512 MB"). tablesort 5.7.1 sorts each table body on its own and
keeps a row marked data-sort-method="none" in place, so hosts stay in
name order with their row on top and their VMs sort below it. Memory,
vCPUs and volume sizes sort by their numbers (data-sort). Headers are
reachable by keyboard and carry aria-sort.
base.html loads tablesort for every table marked data-sortable; the
per-page sortable includes and sortable-theme-bootstrap.css go, so these
tables take the theme's table style like the others. The grouped list's
row numbers go (meaningless once sorted). The VM owners and VM logs
tables were marked sortable but never loaded the script; they stay
unsorted.
The search box floats right of the short Volumes heading and hung
below it, so the table beside it shrank and its headers met the box.
The heading's wrapper now clears the float.
Twenty-five prompts asked only "Are you sure?", and on the storage page
one handler asked the same before every button, Start and Enable
included. Each destructive button now names its object and says what
happens: a stopped network cuts running VMs off, a deleted pool keeps
its files, a deleted volume loses its data, a reverted snapshot loses
the changes made since. Saves no longer ask, and disabled buttons lose
prompts they could not show. The VM QoS messages said to restart the
network where the VM has to be powered off and on.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Twenty tables had no .table-responsive wrapper, so on a phone the user
list, compute list, VM lists, network and network filter pages scrolled
sideways as a whole. Each table now scrolls inside its box, as the
other ten already did. The page test walks the network page too, and
checks that every table on every page has the wrapper.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The pool, network and interface cards had a solid green or red header
with light text, and status words (Connected, ON, OFF, the DRBD state)
were in the theme's green or red text colour. axe found them below the
WCAG AA 4.5:1 contrast on the live theme (4.29:1, 3.52:1), on the
default zephyr theme, whose green is light (2.5:1), and on dark themes
(darkly 1.18:1).
The card headers, and the status words as badges, are now the theme's
pale status background with its dark status text (bg-*-subtle with
text-*-emphasis). Bootstrap derives the pair from each theme's palette,
and it does not depend on the page's background: the dark Bootswatch
themes keep light-mode emphasis colours, which on their own would be
dark text on a dark page. The card border keeps the status colour.
An accessibility scan of the pages on a real host (the earlier scans ran
on libvirt's test driver) found unnamed elements the test driver never
renders: the network page's add fixed address buttons and their dialog
fields, the XML box of each nwfilter's details dialog and the convert
checkbox of the volume clone dialog. The buttons get a title, the labels
a for= and the fields an id, the XML box an aria-label.
create_storage_ceph and create_storage_netfs wrote the pool, host, user,
secret and format values into the pool XML unescaped and unchecked: the
page's patterns were the only guard, and a direct POST could break or
extend the XML. The values now go through util.xml_escape, as the
network code does. The page's host fields stopped at 20 characters, so
nfs01.storage.example.com could not be typed: they take a host name's
253; the Ceph pool and user fields lose the limit the server never had.
An accessibility scan with every modal opened found 49 fields without a
name: the labels of the instance create forms (custom, template and each
flavor's modal), the interface, network, secret and storage pool modals
did not point at their fields. Each label now has a for= and its field an
id, prefixed per form (and per flavor), so a click on the label focuses
the field too. The "Advanced" collapse buttons and the memory and
processing bars are named.
The VCPU config select had id="vcpu_mode" in each of these forms, nine
times on the create page; the unique-ID test did not see it as the test
driver reports no CPU modes. The id goes (nothing used it), and the test
now renders that branch.
The create pool modals kept their own pattern attributes, older and
stricter than the server's check: a logical source took only lower-case
letters, digits and "/", dir and NFS paths no "." or ":", and the NFS
fields stopped at 40 characters (the form allows 100). The browser
refused /dev/mapper/vg0-data, /dev/disk/by-id/wwn-..., /srv/vm.images or
/export/vm_images.v2 before the server saw them. The path fields keep
"required" and leave the check to the server, which shows its message.
An accessibility scan (axe-core, WCAG 2 A/AA) of every page found 87
elements without a name. Icon-only buttons and links (the navbar's
administration menu on every page, the add/create buttons, the flavor
delete and back buttons) get a title, which is also their tooltip; the
labels of the language, architecture, chipset and filter selects point
at them; the memory bar is named. The shared delete confirmation page
had an empty <title> and heading, as no view passes "title": it says
"Delete <object>". The power-off form's aria-label was misspelled.
Rendered through every URL on libvirt's test driver, the pages had
duplicate IDs and markup browsers repaired silently:
- Each flavor modal's "Advanced" button toggled #flav-add-collapse, the
first modal's section; every modal now has its own. The flavor and
template copies of the custom tab's control IDs, and the template
tab's unused images input, are gone.
- The VM page's action icons and the XML editors were styled by
repeated IDs; they use classes.
- Modal forms opened inside modal-body and closed after modal-footer;
they wrap both. Stray end tags and duplicate attributes are removed,
paragraphs no longer hold modals or rows, table heads have a row, and
the create page closes its row and column.
- html lang is the active language instead of "en".
A test walks every URL as a superuser and fails on a repeated ID. The
console page still has no doctype: its full-height layout relies on
quirks mode and needs its own check.
The job panel follows an ISO upload, so the dialog closes when the first
chunk is accepted and its progress bar goes; the dialog opens again with
the error if the upload stops. The browser still sends the file, so the
page asks before it is left while an upload runs. The storage page no
longer includes the please-wait dialog, which nothing on it opened.
The upload session lives in a job instead of flocks and .meta/.done
files; the job panel shows and cancels it; an upload idle for an hour is
ended and its partial file deleted; the page no longer reloads after an
upload.