A superuser's page of a user was a heading, two unlabelled icon buttons
and three tabs: the VMs a table of check columns, the SSH keys a table
that pushed the page sideways on a phone.
Now a card at the top shows the user's name, role, Blocked when they
are, username, email, groups, last login and joining date, with Edit
user and Email OTP QR code as labelled buttons and links to the sections
below with their counts. The VMs card shows each VM with its host and
what the user may do beyond power and console as badges in the VM Users
tab's words (Change settings, Delete the VM, Change console settings),
with Change access and Remove from user in a menu, and Add VM in its
header. The SSH keys and the API tokens are cards; the key rows are now
one include with the user's own Profile, and both lists say when they
are empty. The full key shows over its fingerprint.
The tab script had no page left and goes.
The Profile page was three tabs, each a box inside a box with horizontal
labels: the SSH keys a centred bare row with a grey trash icon, a tall
empty textarea under them, and the user known only by the heading.
Now the user's name, username, role, email and last login head a card
that holds the profile form and the password link; beside it the SSH
keys and the API tokens are cards with their count, a line on what
they are for, one row each with Delete in a menu, and the form to add
one behind a button. Adding or deleting a key returns to #sshkeys.
The token rows are a list-group include that the administrator's view
of a user shares.
webvirtcloud.css still carried the upstream panel's rules for what
Bootstrap 5.3 has as utilities and components:
- the page's bottom space (body padding) is pb-5 on base.html's body,
and the console page no longer has to undo it;
- the VM page's action tabs (.action-button, .action-block with a
fixed 65px width) are text-center with a d-block icon; its tab panes
(#power ... #undefine, one rule each) mt-3;
- the bordered sub-tab panes (.tab-pane-bordered, a fixed #eee border
that dark themes could not change) border border-top-0 p-3;
- the search box and header buttons (.search, .btn-header) m-1 and
mt-1; the SSH key select (.keyselect) a form-select;
- the boot order list (.multipleselect, fixed size, #c0c0c0 border) a
list-group of form-check-input items; its unused .multipleselect-on
goes;
- table cells centred by a global rule are align-middle on each table.
Two rules against Bootstrap's behaviour go: menus opened on hover on
wide screens (Bootstrap opens them on a click, and keyboard and touch
users had no hover), and "a { outline: 0 }", which hid the keyboard
focus ring.
The paragraph and page-header margins and the 900px container stay
for a separate change: they set every page's layout.
On a superuser's page of a user the VM permissions read True/False; they
are now check marks as on the Users list. A user without VMs gets "No VMs."
instead of an empty table. A superuser can delete one of the user's SSH
keys, as with API tokens: the same view takes the user, the row names
whose key it was.
Closes#218
The user page a superuser opens from the user list has an API Tokens
tab: the user's tokens with their name, first characters, creation,
expiry and last use, and a delete button for one that may have leaked.
The token itself is never shown; only its digest is kept.
The delete reuses the owner's delete view with the user's id; only a
superuser may name another user. The confirmation and the log row say
whose token it was ("API token backup of alice"); the owner's own
confirmation now reads "Delete "API token backup"?" too. The profile
and the user page share one token table, and one script that opens a
tab named in the address (#apitokens).
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>
django-qr-code was used for one thing: the QR code in the OTP e-mail,
as an inline SVG and a PNG. It brought pydantic, pydantic-core,
annotated-types and typing-inspection (about 10 MB) and, from 5.0 on,
Pillow. segno, which it used underneath, now draws both images with the
same options (error correction M, 4-module border, 1.8 mm SVG modules,
12 px PNG modules); the SVG, the PNG and the alt text are byte for byte
what django-qr-code 4.2 produced. account.html loaded the tag library
without using it.
- user_block, user_unblock and admin_email_otp changed state on GET, so an
<img> tag could lock a user out or trigger OTP emails through an
admin's session. They now require POST; the buttons are CSRF forms.
- The console token cookie is set with httponly, SameSite=Lax and, on
HTTPS, secure. Only novncd reads it; the page gets the token directly.