Skip to content

v0.21.1 — Admin list-page redesign

Choose a tag to compare

@abdulwahed-sweden abdulwahed-sweden released this 26 May 14:16
· 173 commits to main since this release

[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 the admin.css @import
    manifest and the ADMIN_CSS concat block in routes.rs;
    tests/cascade_lockstep.rs verifies 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.