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:
1 parent
f52bb6f073
commit
ebb7f4a5b0
14 files changed
+192
-643
No files matched your search
+26
-3
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user