Skip to content

dashboard: manual refresh is silently cancelled when local sync fails #146

Description

@pitimon

What

The dashboard's manual refresh can silently skip every data/quota refresh when local sync fails.

handleManualRefresh places await triggerLocalSync() and await refreshAll(...) inside the same try. In local mode, any sync rejection jumps directly to the catch block, so refreshAll is never called. The refresh button stops loading after logging to the console, but the dashboard remains stale.

This was reproduced during PR #142's Vite smoke because /api/local-auth returned 404 and triggerLocalSync() rejected. It is pre-existing and deliberately excluded from #142, whose scope is scheduled quota-cache behavior.

Evidence

Current control flow in dashboard/src/pages/DashboardPage.jsx, handleManualRefresh:

try {
  if (isLocalMode) {
    await triggerLocalSync();
  }
  await refreshAll({ forceUsageLimits: true });
} catch (error) {
  console.error("[DashboardPage] Refresh failed:", error);
}

The sync step and refresh step have different failure semantics but share one catch boundary.

Impact

A user explicitly pressing refresh receives no fresh dashboard or quota data if local sync has a transient/API failure. Because the button returns to normal and the error is console-only, this looks like a successful no-op.

Suggested shape

Treat sync and refresh as independent deposits:

  • Attempt local sync and preserve/report its failure.
  • Still run refreshAll({ forceUsageLimits: true }) so already-available data and provider quotas refresh.
  • Keep loading state correct until both attempted operations finish.
  • Avoid converting the failure into silent success; use the existing user-visible error mechanism if one exists, otherwise track the missing UX explicitly.

Definition of done

  • In local mode, a rejected triggerLocalSync() does not prevent refreshAll().
  • Manual refresh still forces usage limits.
  • Successful local sync behavior is unchanged.
  • Refresh failure remains distinguishable from sync failure.
  • Behavioral test renders DashboardPage, rejects the sync mock, and asserts the refresh hooks still run.
  • The test fails on the current implementation and passes with the fix.
  • npm run ci:local passes.

Scope

Do not change scheduled refresh semantics from PR #142 in this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions