Summary
Every page labels its left-hand list "Resource types" (resources-types-heading, queries-rail-heading, sp-rail-types all resolve to the same English string), but there are three different implementations of that rail, with different markup, different interaction models, and different capabilities. The gap is most visible between Resources (/ui/resources) and Search Parameters (/ui/search-parameters).
Notably, crates/ui/templates/pages/search-parameters.html:31-34 describes its rail as "the primitive the Resources screen will share" — the Resources screen ended up not sharing it.
The three variants
|
Search Parameters |
Search / Saved Queries |
Resources |
| Template |
pages/search-parameters.html |
pages/search.html, pages/queries.html |
pages/resources.html |
| Placement |
aside.card.filter-rail inside content |
aside.card.filter-rail inside content |
{% block nav_panel %} — .nav-panel, flush against the sidebar |
| Item markup |
<a class="filter-rail__item" href=…> |
<button class="filter-rail__item" data-rail-type> |
<button class="nav-panel__item" data-rail-type> |
| Selected state |
aria-current="true" (server) |
none |
.nav-panel__item--on (client, JS-toggled) |
| Type filter box |
server-side: htmx GET with q, hidden fields round-trip other filters |
client-side show/hide (saved-queries.js:1268) |
client-side show/hide (same code) |
| Counts |
server-rendered |
hydrated client-side |
hydrated client-side |
| Count meaning |
# of SearchParameters with that base type |
# of stored resource instances |
# of stored resource instances |
| "All types" row |
✅ (rail_all) |
❌ |
❌ |
| "Recently used" group |
✅ (resource-filter.js, localStorage hfs-recent-types) |
❌ |
❌ |
| URL reflects selection |
✅ (linkable / bookmarkable / back-button) |
❌ |
❌ |
| Works without JS |
✅ fully server-rendered |
❌ rail is inert |
❌ rail is inert |
| Type list source |
base types present in the SearchParameter registry (search_params.rs:410-433) |
compartments.resource_type_names(tenant, version) |
compartments.resource_type_names(tenant, version) |
Why it matters
- Same label, same visual slot, three different behaviors — a user who learns the rail on one page has to relearn it on the next.
- Selecting a type on Resources doesn't change the URL, so the view can't be linked, bookmarked, or reached with the back button; on Search Parameters it can.
- Resources/Search/Queries counts render blank until N client-side
/{Type}?_summary=count&_total=accurate fetches land (4-at-a-time, ~145 types), and stay blank on failure. Search Parameters counts are always present.
- The "Recently used" affordance and the "All types" escape hatch exist only on the page where they matter least.
- The two count columns look identical but mean different things (search-parameter definitions vs. stored instances), with nothing in the UI distinguishing them.
Suggested direction (needs a decision)
Pick one canonical rail component and have all four pages use it. Open questions:
- Which placement wins — the sidebar-flush
nav-panel (Resources, per the Figma "Resources" frame 142:2) or the in-content filter-rail card (Search Parameters, Search, Queries)?
- Server-driven links vs. client-driven buttons. The Search Parameters rail is a plain filtered list view and works without JS; the Resources rail drives an in-page search that never navigates. Reconciling these probably means the shared component takes real
hrefs and progressively enhances.
- Counts: keep both meanings but label/annotate them, and decide whether the instance counts should be server-rendered rather than hydrated by ~145 client fetches.
- Should "All types" and "Recently used" be part of the shared primitive (i.e. show up on Resources too)?
Acceptance criteria
Pointers
crates/ui/templates/pages/{resources,search,queries,search-parameters}.html
crates/ui/assets/saved-queries.js:1202-1280 (rail click, filter, count hydration)
crates/ui/assets/resource-filter.js (recents)
crates/ui/src/search_params.rs:410-445 (server-rendered rail + counts)
crates/ui/src/lib.rs:945-1015 (type list for Resources / Search / Queries)
crates/ui/assets/app.css:3602-3630 (.nav-panel__item), .filter-rail__*
Summary
Every page labels its left-hand list "Resource types" (
resources-types-heading,queries-rail-heading,sp-rail-typesall resolve to the same English string), but there are three different implementations of that rail, with different markup, different interaction models, and different capabilities. The gap is most visible between Resources (/ui/resources) and Search Parameters (/ui/search-parameters).Notably,
crates/ui/templates/pages/search-parameters.html:31-34describes its rail as "the primitive the Resources screen will share" — the Resources screen ended up not sharing it.The three variants
pages/search-parameters.htmlpages/search.html,pages/queries.htmlpages/resources.htmlaside.card.filter-railinside contentaside.card.filter-railinside content{% block nav_panel %}—.nav-panel, flush against the sidebar<a class="filter-rail__item" href=…><button class="filter-rail__item" data-rail-type><button class="nav-panel__item" data-rail-type>aria-current="true"(server).nav-panel__item--on(client, JS-toggled)GETwithq, hidden fields round-trip other filterssaved-queries.js:1268)rail_all)resource-filter.js, localStoragehfs-recent-types)search_params.rs:410-433)compartments.resource_type_names(tenant, version)compartments.resource_type_names(tenant, version)Why it matters
/{Type}?_summary=count&_total=accuratefetches land (4-at-a-time, ~145 types), and stay blank on failure. Search Parameters counts are always present.Suggested direction (needs a decision)
Pick one canonical rail component and have all four pages use it. Open questions:
nav-panel(Resources, per the Figma "Resources" frame 142:2) or the in-contentfilter-railcard (Search Parameters, Search, Queries)?hrefs and progressively enhances.Acceptance criteria
Pointers
crates/ui/templates/pages/{resources,search,queries,search-parameters}.htmlcrates/ui/assets/saved-queries.js:1202-1280(rail click, filter, count hydration)crates/ui/assets/resource-filter.js(recents)crates/ui/src/search_params.rs:410-445(server-rendered rail + counts)crates/ui/src/lib.rs:945-1015(type list for Resources / Search / Queries)crates/ui/assets/app.css:3602-3630(.nav-panel__item),.filter-rail__*