Skip to content

[Frontend][Board] Boards list needs a Retry control and error hygiene now that the list read is bounded (follow-ups from the #2688 review) #2689

Description

@Chris0Jeky

Follow-ups from the fresh-context review of PR #2688 (#2685: the shared board-list read is bounded with timeout: BOARD_REQUEST_TIMEOUT_MS and skipRetry: true, matching the detail read). None blocks that merge; together they are the product cost of the bound, which is now load-bearing on the boards list.

  1. BoardsListView has no Retry control (MEDIUM in the review). src/views/BoardsListView.vue ~134-137 renders boardStore.error in a bare role="alert" block; its only read is onMounted. With skipRetry on the list read, a one-off 503 or a restart of the API during mount (routine in the dotnet run loop) no longer heals itself in the retry layer: the alert stays until the user navigates away and back, and because the read is shared, every unfiltered caller on the page fails on the same blip. Add a Retry affordance the way PaperTriageTable.vue (retryBoardLoad, ~328-330) has one, calling fetchBoards() (the share is released and the throttle stamp is unset on failure, so the retry issues a fresh request).
  2. MetricsView.loadBoards has no catch (LOW). src/views/MetricsView.vue ~33-41 and ~82-89: try { await boardStore.fetchBoards() } finally { ... } with no catch, inside an onMounted async callback, so a failed list read is an unhandled rejection that installWindowErrorListeners forwards to Sentry where present. Pre-existing, but the bound makes the failing path routine. Catch and rely on the store's error surface, as every other caller does.
  3. A timeout surfaces raw axios copy in a localized alert (LOW). getErrorMessage (utils/errorMessage.ts ~18-20) prefers err.message, so a 10 s timeout puts "timeout of 10000ms exceeded" into state.error and the toast, rendered verbatim beside $t copy. The detail read has the same shape today. Map ECONNABORTED (and an aborted request, should one ever reach handleApiError) to a translated message.
  4. state.error is never cleared by a successful read (LOW, pre-existing, amplified). boardCrudStore.ts clears error at the start of a read but not on success, so two concurrent list reads (the activity selector's includeArchived read still in flight from the previous route while the boards list mounts an unfiltered one) where the earlier fails and the later succeeds leave error set beside a populated boards, and BoardsListView's v-if loading / v-else-if error / ... / v-else grid chain shows the alert instead of the grid. The bound makes the failing half deterministic at 10 s. Clear error on the success path of a current-generation read.
  5. Four direct callers of boardsApi.getBoards outside the store remain unbounded (worker note, not reviewed). ArchiveView.vue, useAutomationChat.ts, useProposalDisplayNames.ts, useReviewProposals.ts call the API directly, so they get neither the share nor the bound. Decide per caller whether they need a bound (they are not joined to the share, so the page-wide stall does not apply to them).

Refs #2685, #1961, PR #2681, PR #2688.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    frontendPrimary implementation impact in Vue/TypeScript UI and client runtime.uxDiscoverability, accessibility, interaction model, and user workflow quality.

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions