The M5 search endpoint returns 503 Service Unavailable when Meilisearch is not configured (AppState.search == None), and 500 for an actual query failure. The frontend SearchPanel currently renders the same search.loadError ("Search is unavailable") message for any isError, so a transient backend error and a "search feature is turned off" condition look identical to the user.
Ask
In web/src/search/search-panel.tsx (and the useSearch hook in web/src/api/queries.ts if needed), distinguish the two:
On 503, show a calm, explanatory message: search isn't enabled on this server (it's an optional feature — Meilisearch not configured). Don't imply a transient failure or invite retry.
On other errors (500/network), show the generic retry-friendly error.
Notes
useSearch's queryFn currently throws a generic Error on error || !data. To branch in the UI, capture the HTTP status (e.g. throw a typed error carrying response.status, or expose it) so SearchPanel can render search.unavailable vs search.loadError.
Add a search.unavailable i18n key (en + sv) and a test that a 503 renders it (MSW handler returning 503).
Minor UX polish, not urgent — surfaced in the M5 final review.
## Context
The M5 search endpoint returns **`503 Service Unavailable`** when Meilisearch is not configured (`AppState.search == None`), and `500` for an actual query failure. The frontend `SearchPanel` currently renders the same `search.loadError` ("Search is unavailable") message for any `isError`, so a transient backend error and a "search feature is turned off" condition look identical to the user.
## Ask
In `web/src/search/search-panel.tsx` (and the `useSearch` hook in `web/src/api/queries.ts` if needed), distinguish the two:
- On `503`, show a calm, explanatory message: search isn't enabled on this server (it's an optional feature — Meilisearch not configured). Don't imply a transient failure or invite retry.
- On other errors (`500`/network), show the generic retry-friendly error.
## Notes
- `useSearch`'s `queryFn` currently throws a generic `Error` on `error || !data`. To branch in the UI, capture the HTTP status (e.g. throw a typed error carrying `response.status`, or expose it) so `SearchPanel` can render `search.unavailable` vs `search.loadError`.
- Add a `search.unavailable` i18n key (en + sv) and a test that a 503 renders it (MSW handler returning 503).
- Minor UX polish, not urgent — surfaced in the M5 final review.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Context
The M5 search endpoint returns
503 Service Unavailablewhen Meilisearch is not configured (AppState.search == None), and500for an actual query failure. The frontendSearchPanelcurrently renders the samesearch.loadError("Search is unavailable") message for anyisError, so a transient backend error and a "search feature is turned off" condition look identical to the user.Ask
In
web/src/search/search-panel.tsx(and theuseSearchhook inweb/src/api/queries.tsif needed), distinguish the two:503, show a calm, explanatory message: search isn't enabled on this server (it's an optional feature — Meilisearch not configured). Don't imply a transient failure or invite retry.500/network), show the generic retry-friendly error.Notes
useSearch'squeryFncurrently throws a genericErroronerror || !data. To branch in the UI, capture the HTTP status (e.g. throw a typed error carryingresponse.status, or expose it) soSearchPanelcan rendersearch.unavailablevssearch.loadError.search.unavailablei18n key (en + sv) and a test that a 503 renders it (MSW handler returning 503).