Skip to content

fix refresh button and add backend sync logic#35

Merged
jagrat7 merged 8 commits intodevfrom
claude/issue-34-20260323-0052
Mar 24, 2026
Merged

fix refresh button and add backend sync logic#35
jagrat7 merged 8 commits intodevfrom
claude/issue-34-20260323-0052

Conversation

@jagrat7
Copy link
Copy Markdown
Owner

@jagrat7 jagrat7 commented Mar 23, 2026

Fix for issue #34 where the Refresh button had no visual feedback after the initial load.

  • Fixed by exposing isFetching from useWallpapers and passing it to the GridHeader instead of isLoading.
  • Hard refresh button: Refresh now calls an invalidateCache mutation (clears server-side 5-min cache) before refetching, ensuring users always get fresh data.
  • tRPC invalidation subscription: Central invalidationService (EventEmitter pub/sub) pushes invalidation keys to the renderer via observable-based tRPC subscription, which invalidates the matching react-query cache entries.
  • Auto-refresh via fs.watch: Workshop directories are monitored for new wallpaper downloads. Changes are debounced (1.5s) and pushed to the renderer via a tRPC subscription, so new wallpapers appear automatically.
  • Real-time compatibility dots: After auto-detection completes, the compatibility map is pushed to the renderer so dots update without manual refresh.

isLoading is only true on the initial query load (no cached data).
During refetch(), React Query sets isFetching=true but isLoading stays
false, so the refresh button had no visual feedback after first load.

Fixes #34

Co-authored-by: Jagrat Rao <jagrat7@users.noreply.github.com>
@jagrat7
Copy link
Copy Markdown
Owner Author

jagrat7 commented Mar 23, 2026

@claude that doesnt explain why the user was reporting stale data for his wallpapers

@claude
Copy link
Copy Markdown

claude bot commented Mar 23, 2026

Claude finished @jagrat7's task in 1m 29s —— View job


Analysis: Stale Wallpaper Data

Good question — the PR only fixes the visual feedback. The stale data issue is a separate problem rooted in the backend cache not being bypassed on manual refresh.

Here's what's happening:

The Root Cause

src/main/services/wallpaper/wallpaper.ts has an in-memory cache with a 5-minute TTL:

private wallpaperCache: Wallpaper[] | null = null
private cacheTimestamp: number | null = null
const CACHE_TTL = 5 * 60 * 1000 // 5 minutes

The getWallpapers method accepts a refresh flag that bypasses this cache:

async getWallpapers(options: GetWallpapersOptions = {}): Promise<Wallpaper[]> {
  const { search, refresh = false } = options
  if (refresh || !this.wallpaperCache || cacheExpired) {
    this.wallpaperCache = await this.scanWallpapers()
  }
}

The tRPC procedure also exposes this flag:

// src/main/trpc/routes/wallpaper.ts
getWallpapers: trpc.procedure
  .input(z.object({
    search: z.string().optional(),
    refresh: z.boolean().default(false),  // ← exists but unused
  }))
  .query(async ({ input }) => wallpaperService.getWallpapers(input))

However, the frontend never passes refresh: true. When a user clicks the Refresh button, refetch() is called, which re-runs the tRPC query — but with the same { search } input. The backend gets the request, sees its in-memory cache is still valid, and returns the same stale data. The 5-minute cache is never busted.

The Fix

In src/renderer/hooks/use-wallpapers.ts, the query needs a way to force the backend to bypass its cache. One approach: track a forceRefresh flag in the query input.

// use-wallpapers.ts
const [forceRefresh, setForceRefresh] = useState(false)

const { data, isFetching, refetch } = trpc.wallpaper.getWallpapers.useQuery(
  { search: debouncedSearch, refresh: forceRefresh },
  { ... }
)

const refresh = useCallback(async () => {
  setForceRefresh(true)
  await refetch()
  setForceRefresh(false)
}, [refetch])

Or more simply, pass refresh: true directly when constructing a manual refetch by using queryClient.fetchQuery with refresh: true, or by switching from useQuery to a pattern that passes the flag on demand.

Additional Contributing Factors

  • No file system watching: There's no chokidar/fs.watch on the Steam Workshop directory, so newly installed wallpapers are invisible until the cache expires — regardless of clicking Refresh.
  • Frontend staleTime is 30s, backend cache is 5min: React Query may think data is stale and refetch, but it still gets cached backend data.

Fix this →

@jagrat7 jagrat7 self-assigned this Mar 23, 2026
jagrat7 added 3 commits March 23, 2026 16:20
…ry changes

Implemented fs.watch on workshop directories with 1.5s debounce to automatically invalidate the wallpaper cache when files change. Replaced manual refresh parameter with invalidateCache mutation that triggers a fresh scan on next query. This enables automatic detection of newly added/removed wallpapers without requiring manual refresh.
@jagrat7 jagrat7 linked an issue Mar 23, 2026 that may be closed by this pull request
@jagrat7 jagrat7 marked this pull request as draft March 23, 2026 23:52
@jagrat7 jagrat7 requested a review from RainAfterDark March 23, 2026 23:52
jagrat7 added 2 commits March 23, 2026 20:34
…atic cache updates

Implemented an event-based invalidation system to automatically refresh React Query caches when backend data changes. Created invalidationService with EventEmitter to broadcast invalidation events, exposed via tRPC subscription, and added useInvalidation hook to listen for events and invalidate corresponding queries. Integrated emissions in wallpaper file watcher and compatibility override updates. Simplified
Renamed the 'start' script to 'dev' in package.json to better align with common development conventions. Updated all references in CONTRIBUTING.md to use 'bun dev' instead of 'bun start'.
@jagrat7 jagrat7 marked this pull request as ready for review March 24, 2026 00:58
@jagrat7 jagrat7 changed the title fix: use isFetching for refresh button loading state fix refresh button and add backend sync logic Mar 24, 2026
jagrat7 added 2 commits March 24, 2026 01:35
…cks and wallpaper cache invalidation

Decreased compatibility service cleanup timeout from 3000ms to 2500ms and wallpaper filesystem watcher debounce from 1500ms to 500ms to improve UI responsiveness when detecting changes.
…t compatibility detection

Extended the timeout before classifying wallpapers as perfectly compatible to reduce false positives from delayed stderr output.
@jagrat7 jagrat7 merged commit 2d77bae into dev Mar 24, 2026
@jagrat7 jagrat7 deleted the claude/issue-34-20260323-0052 branch March 26, 2026 00:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refresh option doesn't work

1 participant