v0.21.1 — Admin list-page redesign
[0.21.1] — 2026-05-26
Admin list-page redesign. Pure CSS + template + render-context
change; no Rust public-API impact, no schema, no auth or permission
behaviour shift.
Toolbar split
The pre-0.21 "View ▾" overflow dropdown collapsed Sort, Per-page,
CSV export, and CSV import into one mega-menu — operators had to
scan a 17-row list (8 fields × 2 directions + Default + 4 per-page
- Export + Import) to find any single operation. 0.21.1 splits the
toolbar into two zones with distinct intent:
- Row 1 "Find" — search input (flex:1, ≥360px), up to two
promoted filter chips, a "More filters" overflow for the rest, a
Reset link that surfaces only when there's state to reset
(search OR ≥1 active filter). - Row 2 "Arrange" — Sort field menu, direction toggle, Rows
per page, Saved view, then a flex spacer, then Export / Import
pinned to the trailing edge. Every control carries icon + label.
Find panel surface
.rlp-find sits inside an accent-tinted card (--rio-accent-soft
fill, --rio-accent-border, framework radius). No heading or icon
above the panel — the surface itself is the cue. Arrange stays
transparent so the visual weight stays on Find.
Dark table header
.rio-list-page .rio-table th re-skins to --rio-surface-chrome
(the same slate-900 the sidebar uses). The thead scope locally
redefines --rio-text-strong / --rio-text / --rio-text-muted
/ --rio-text-subtle to slate-50…500 and lifts --rio-accent to
teal-400 — same chrome-cascade trick layout/shell.css already
uses on the sidebar, so hover and active-sort copy stay legible
without per-selector overrides. The header bar reads as one
continuous frame with the sidebar; data rows now contrast hard
against the chrome instead of fading into a neutral.
Sort menu — field-once + direction toggle
SortFieldCtx (one entry per sortable field) replaces the
field×direction menu pattern. Clicking a field row activates
ascending sort; a sibling direction toggle flips to descending and
reads field-type-aware copy:
| Field type | Asc label | Desc label |
|---|---|---|
DateTime |
oldest first | newest first |
String / FilePath |
A → Z | Z → A |
I32 / I64 |
lowest first | highest first |
Bool |
off → on | on → off |
Numeric copy (lowest first / highest first) is new in 0.21.1;
0.21.0 fell back to the generic ascending / descending strip.
The unit test was updated to match the new copy.
Empty state
The pre-0.21 <p class="rio-empty">No <model> yet</p> floated as a
single sentence inside a large blank card. 0.21.1 ships a centered
empty-state block: a tinted-disc inbox icon, an h2 title
("No appointments yet"), a 16px body sentence ("Add the first
appointment to get started."), and the primary Add CTA. Copy
substitutes the model's plural / singular display name so the
same block reads correctly for every model with no project-side
override.
Bottom bar
Row count + pagination move out of the toolbar into a footer-style
bar below the table card. Showing N of M <model-plural> plus
pagination nav; hidden in the empty state because zero-of-zero is
noise.
Responsive
.rio-list-page page padding cascades: 32px desktop ≥1280px →
24px tablet 768–1279px → 16px mobile <768px, driven by a
.rio-main:has(> .rio-list-page) selector so non-list pages keep
their existing padding. The toolbar's flex-wrap lets Row 1 and
Row 2 reflow vertically below 768px without code; the table card
remains the only horizontal-scroll surface.
Render-context additions
ListCtx gains:
sort_fields: Vec<SortFieldCtx>— one entry per sortable field.current_sort_field_label: String— Sort chip caption.current_sort_dir_label: &'static str— direction toggle text.sort_dir_toggle_link: String— flips the active sort's direction.default_sort_link: String— Sort menu's reset row URL.
The legacy sort_options / current_sort_label fields are kept
for back-compat with project templates that haven't migrated to
the new layout.
Assets
- New stylesheet
assets/static/admin/pages/list.css, scoped
under.rio-list-page. Wired into both theadmin.css@import
manifest and theADMIN_CSSconcat block inroutes.rs;
tests/cascade_lockstep.rsverifies the two lists stay aligned. - New icons:
inbox(empty-state disc),rotate-ccw(Reset chip),
arrow-up-down(direction toggle decoration). All inline lucide
stroke paths, no external library.
Known issue (carried forward, not introduced by 0.21.1)
A foreign-key filter declared in ModelAdmin::list_filter() is
silently dropped when the RelationRegistry doesn't carry the
relation — infer_filters_with_registry falls through to
FilterKind::NumericExact, then the list handler hits a _ => {}
catch-all with no rendered widget. Pre-existing in 0.21.0; the
new toolbar makes the gap more visible (the "More filters"
dropdown is the natural place to surface secondary filters and
will obviously be empty when only the FK was configured). Fix
requires real widget design for NumericExact / RelationSelect
and belongs in a later phase, not a UI patch release.
Migration
Existing 0.21.0 projects update by bumping
rustio-admin = "0.21.0" to "0.21.1" in their Cargo.toml and
running cargo update -p rustio-admin. No schema migration. No
template override required — the new layout ships as the embedded
default. Projects that override templates/admin/list.html
locally will continue to use their override; remove it to pick up
the new layout.