feat(filters): panel removal + All-Books field-values fix (faceted plan Phase 8)

- Remove the Phase 7 facet-panel UI: SSR route, facet_panel.templ,
  FacetCountsForView, drawer panel block, panel TS + .facet-* CSS.
  The ENGINE stays (FacetCountsUnderFilters, all-facets endpoint,
  drift guard) — it becomes the Phase 9 builder's machinery.
- Fix the All-Books bug: field-values autocomplete (author/genre/
  tags/narrator/series/language) treats library_id as OPTIONAL —
  absent aggregates every VISIBLE library (family lens in-query);
  explicit out-of-set library_id is now 403, never a silent pass.
  The four scalar Search*Values queries get the nullable shape.
- toast.ts: suggestion fetches are exempt from error toasts
  (console-only) — a failed background hint never interrupts.
- TestFacetPanelPartial deleted with the behavior; TestFieldValuesAll-
  Libraries pins the fix (200 + cross-library aggregation, family
  lens, 403). Contract-pins changelog entry added.
This commit is contained in:
John O'Keefe committed 2026-10-20 12:20:51 -04:00
1 parent f52bb6f073
commit ebb7f4a5b0
14 files changed
+192 -643

No files matched your search

+26 -3
View File
@@ -176,6 +176,18 @@ const setupHTMXListeners = (): void => {
});
};
// Suggestion fetches — field-value autocomplete (author=, genre=, …)
// on the search endpoint — are background hints for typed inputs. A
// failed hint must never interrupt the user with a toast: it logs to
// the console only. The grid's real search (q=/sort= params) is NOT a
// suggestion fetch and keeps its toasts.
const suggestionFieldRe = /[?&](author|genre|tags|narrator|series|language)=/;
function isSuggestionFetch(input: Parameters<typeof fetch>[0]): boolean {
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
if (!url.includes("/api/media-items/search?")) return false;
return suggestionFieldRe.test(url) && !/[?&](q|sort)=/.test(url);
}
// Setup fetch interceptor
const setupFetchInterceptor = (): void => {
const originalFetch = window.fetch;
@@ -209,17 +221,28 @@ const setupFetchInterceptor = (): void => {
return response;
}
// Handle other errors
// Handle other errors. Suggestion fetches are exempt (console
// only) — a failed background hint never interrupts.
if (!response.ok) {
const errorMessage = await parseFetchError(response);
showToast(errorMessage, "error");
if (isSuggestionFetch(args[0])) {
console.warn(
`Suggestion fetch failed (${response.status}): ${errorMessage}`,
);
} else {
showToast(errorMessage, "error");
}
}
return response;
} catch (error) {
// Don't show toast for redirect errors
if ((error as Error).message !== "Session expired") {
showToast("Network error: Unable to connect to server", "error");
if (isSuggestionFetch(args[0])) {
console.warn("Suggestion fetch failed: network error", error);
} else {
showToast("Network error: Unable to connect to server", "error");
}
}
throw error;
}