fix(filter-builder): id labels resolve at render — refresh keeps names
Refresh showed raw uuids in id-kind value cells (feed/library/ collection/added_by). Two defects, one story: 1. Only ids persist in filter trees; the client's id→label cache dies with the page. The quiet re-resolution fetch reused the suggest facet, whose rows are MEDIA-CONSTRAINED (INNER JOIN media_items + the tree's sibling rules as a constraint) — so an id whose media doesn't match got no row and no label. Live repro: "feed in [A,B,C] AND title contains Chapter" labeled one feed of three (live-request evidence: 200 with total:1). A label is a property of the entity row, not of what currently matches. Fix: pages that render a tree resolve labels SERVER-SIDE at render and embed the map on the mount (data-id-labels) — the collection editor (stored tree) and the bookshelf (URL qf). New SearchService.FilterTreeLabels reads the entity tables with no media join and no tree constraint; scoping rides the request identity through the scoped handle (podcast_feeds/collections RLS — an invisible id resolves to nothing; pinned), libraries mirror the facet's visibility join. A feed with ZERO episodes resolves its title — pinned; that case was structurally impossible before. 2. The bookshelf drawer never hydrated at page load at all: the only load-time hydrate calls live in the PARENT's x-init (initBookshelf), and Alpine initializes parents before nested components — builderData() was null there, so hydrateFromForm no-oped and a URL-qf refresh left the drawer with an empty seeded rule while the grid stayed filtered. The drawer now hydrates in its OWN init when the mount carries no data-tree; the init-order contract is pinned in vitest (185/185). The quiet suggest fetch remains only as a fallback for trees the SSR never saw; embedded labels make it a no-op on refresh. Interactive menus are untouched (their constrained, count-bearing behavior is correct for choosing). Pins: TestRulesPageEmbedsIdLabels (zero-episode feed labels at render, bookshelf qf library label, hidden library NOT labeled); filter/episode-tree/search-contract/RLS/playlist container slices green; contract_pins entry documents the embed contract.
This commit is contained in:
1 parent
c448fa438f
commit
65f257f377
12 files changed
+533
-80
No files matched your search
@@ -17,6 +17,7 @@ templ BookShelf(
|
||||
limit int,
|
||||
offset int,
|
||||
count int,
|
||||
labelsJSON string,
|
||||
) {
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@@ -178,6 +179,7 @@ templ BookShelf(
|
||||
the tree (depth = indent); groups nest via + group. -->
|
||||
<div x-data="filterBuilderExtra" x-cloak
|
||||
data-filter-fields={ JSONArg(services.FilterFieldsPayload("books")) }
|
||||
data-id-labels={ labelsJSON }
|
||||
x-effect="filtersOpen === true && ensureReadyRule()"
|
||||
>
|
||||
@FilterBuilderRows("book")
|
||||
|
||||
Reference in new issue
Block a user