Use Mantine Indicator with processing animation instead of custom CSS. Switch from HoverCard to Menu with grouped sections. Remove beep, position dot next to board logo, hide in edit mode.
4.5 KiB
4.5 KiB
name, overview, todos, isProject
| name | overview | todos | isProject | |||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Widget Refresh Indicator | Add a board-header refresh indicator for widget/server-state queries using TanStack Query as the shared state source, then continue the PR #5768 pattern by removing widget-level blocking spinners where needed. |
|
false |
Widget Refresh Indicator Plan
Findings
- PR #5768 is on
agent/cebd0dadand currently only changes packages/widgets/src/calendar/component.tsx:useSuspenseQuerybecameuseQuery, with a small widget-local loader. - The current workspace is on
feat/add-integration-from-dashboard, so implementation should first move toagent/cebd0dadafter approval. - Homarr already uses Jotai for small client UI state in apps/nextjs/src/components/layout/header/burger.tsx, but there is no Zustand pattern. For this feature, TanStack Query itself should be the shared store.
- The client
QueryClientlives in apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx. TanStack Query v5 supportsuseIsFetching()for a global fetching count andqueryClient.getQueryCache().subscribe()/findAll()for cache inspection. - The board header actions are in apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx; the indicator should be inserted immediately before
<EditModeMenu />, which places it to the left of the edit button.
Implementation Approach
- Add a small client hook/component, likely apps/nextjs/src/components/layout/header/query-refresh-indicator.tsx, that reads from
useQueryClient()and subscribes to the query cache. - Derive a normalized list from cached queries: query path/key, fetching status,
status,dataUpdatedAt, stale state via the query object, error state, and integration IDs found in query inputs/data where present. - Count active refreshes with
fetchStatus === "fetching", using auseIsFetching()value as a cheap re-render trigger and cache subscription for details. - Render a Mantine
HeaderButton/ActionIconwith a tinyIndicator: orange while one or more relevant queries are fetching, green briefly after a refresh batch completes, then idle/disabled when nothing is active. - Use a Mantine
HoverCardfor the details: overall status, number of refreshing queries, last updated/stale state, and a compact list of current integration/widget query entries. - Add a small Web Audio beep when the indicator transitions from fetching to complete. It should be best-effort and fail silently if the browser blocks audio before user interaction.
- Add translation keys only to packages/translation/src/lang/en.json; other locales fall back to English through the existing merge in packages/translation/src/request.ts.
Widget Migration Scope
- Keep PR #5768’s calendar behavior, but remove the widget-local loader if the header indicator fully replaces it.
- Do not attempt to convert all
useSuspenseQuerywidgets in the same pass unless the branch goal expands. The first version can show global activity for all query cache entries, while follow-up widget migrations replace blockinguseSuspenseQuerywithuseQuerywhere each widget can render meaningful stale/empty content.
Verification
- Run a targeted typecheck such as
pnpm -F nextjs typecheckandpnpm -F widgets typecheckafter implementation. - Skip lint cleanup unless explicitly requested, matching your preference to ignore linter errors.