feat(ui): distinct error feedback when @mention search fails #634
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
PR #629's
runSearchinPersonMentionEditor.sveltecatches non-OK responses and swallowed exceptions by settingdropdownState.items = []. The user sees the same "Keine Personen gefunden" copy as for a genuine no-results state — no signal that the system is unhealthy.Sara (#10935, #10970, #11080) and Elicit (#10926, #11058) flagged this.
Decision
Distinct empty-state copy with retry button for 5xx / network failures, dedicated session-expired copy for 401, and the existing empty-state copy for other 4xx. Picked over the alternatives because:
Rejected:
Acceptance (Given-When-Then)
Given the dropdown is open with a typed query, when
/api/personsresponds with4xx(excluding401), then the dropdown shows the existing empty-state copy (m.person_mention_popup_empty()— "Keine Personen gefunden") — treated as no-match.Given the dropdown is open with a typed query, when
/api/personsresponds with401, then the dropdown showsm.person_mention_error_session_expired()("Sitzung abgelaufen — bitte neu anmelden") with a link to/logininside the dropdown body. The link usestarget="_blank" rel="noopener noreferrer"consistent with the create-new escape hatch.Given the dropdown is open with a typed query, when
/api/personsresponds with5xxOR the fetch promise rejects (network failure), then the dropdown showsm.person_mention_error_retry()("Suche fehlgeschlagen — erneut versuchen") with a button that re-fires the lastrunSearch(query). The button hasmin-h-[44px]and respects WCAG 2.5.5 touch-target size.Given the user clicks the retry button, when the re-fired request succeeds, then the dropdown transitions to the populated state and the persistent live region announces the new result count (Leonie #3 from PR #629).
Given the user clicks the retry button, when the re-fired request still fails, then the same retry UI re-renders (idempotent — no banner stacking, no double-fetch).
i18n strings
person_mention_error_session_expiredperson_mention_error_retryperson_mention_error_retry_btnperson_mention_error_session_linkTest plan
PersonMentionEditor.svelte.spec.ts("server failure" and "fetch reject"): both currently pin the empty-state copy. Update each to assert the new error UX per AC-3./api/personsreturning 401; assert the session-expired copy +/loginlink rendered.Out of scope
code = SESSION_EXPIREDmapping. If the backend returns401but a JSON body with a genericcode, treat HTTP 401 as the signal.Reviewer rationale: Sara #10935 / #10970 / #11080 (round 3 — commit to a design + Given-When-Then), Elicit #10926 / #11058, Tobi #11054 (401 callout).