🐛 Fix mode switching requiring manual browser refresh#760
Conversation
Replace static `isDemoMode()` function calls with reactive `useDemoMode()` hook in all `useCachedData` wrapper hooks. The problem was that `enabled: !isDemoMode()` evaluated once at mount time. When demo mode changed, this value never updated because: 1. The parent component didn't re-render (no dependency on demo mode) 2. `enabled` was computed at mount time and stayed fixed The fix: Use `useDemoMode()` hook which subscribes to demo mode changes and triggers re-renders. This causes `useCache` to receive the updated `enabled` value when mode switches. Hooks updated: - useCachedPods - useCachedEvents - useCachedPodIssues - useCachedDeploymentIssues - useCachedDeployments - useCachedServices - useCachedProwJobs - useCachedLLMdServers - useCachedLLMdModels - useCachedSecurityIssues Co-Authored-By: Claude Opus 4.5 <[email protected]> Signed-off-by: Andrew Anderson <[email protected]>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
✅ Deploy Preview for kubestellarconsole ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Welcome to KubeStellar! 🚀 Thank you for submitting this Pull Request. Before your PR can be merged, please ensure: ✅ DCO Sign-off - All commits must be signed off with ✅ PR Title - Must start with an emoji: ✨ (feature), 🐛 (bug fix), 📖 (docs), 🌱 (infra/tests), Getting Started with KubeStellar: Contributor Resources:
🌟 Help KubeStellar Grow - We Need Adopters! Our roadmap is driven entirely by adopter feedback. Whether you're using KubeStellar yourself or know someone who could benefit from multi-cluster Kubernetes: 📋 Take our Multi-Cluster Survey - Share your use cases and help shape our direction! A maintainer will review your PR soon. Feel free to ask questions in the comments or on Slack! |
|
🎉 Thank you for your contribution! Your PR has been successfully merged. 🌟 Help KubeStellar Grow - We Need Adopters! Our roadmap is driven entirely by adopter feedback - nothing else. Whether you're using KubeStellar yourself or know organizations that could benefit from multi-cluster Kubernetes, we need your help: 📋 Take our Multi-Cluster Survey - Share your use cases and help shape our direction! 🗣️ Spread the word - Tell colleagues, write blog posts, present at meetups 💬 Share feedback on Slack #kubestellar-dev Every adopter story helps us prioritize what matters most. Thank you for being part of the KubeStellar community! |
There was a problem hiding this comment.
Pull request overview
Fixes stale cached-hook behavior when toggling demo ↔ live mode by making the cache “enabled” flag reactive to demo mode changes, so hooks refetch (or stop fetching) immediately without requiring a browser refresh.
Changes:
- Import and use
useDemoMode()in cached data hooks to derive a reactiveenabledvalue. - Update multiple
useCached*hooks to useenabled: !demoModeinstead ofenabled: !isDemoMode(). - Ensures mode toggles propagate into the caching layer, allowing immediate data refresh behavior.
| const { isDemoMode: demoMode } = useDemoMode() | ||
| const { limit = 20, category = 'realtime' } = options || {} | ||
| const key = `events:${cluster || 'all'}:${namespace || 'all'}:${limit}` | ||
|
|
||
| const result = useCache({ | ||
| key, | ||
| category, | ||
| initialData: getDemoEvents(), | ||
| enabled: !isDemoMode(), | ||
| enabled: !demoMode, |
There was a problem hiding this comment.
Same as above: consider removing the per-hook useDemoMode() + enabled: !demoMode and rely on useCache’s internal demo-mode gating to reduce repeated subscriptions/boilerplate.
| const { isDemoMode: demoMode } = useDemoMode() | ||
| const { category = 'pods' } = options || {} | ||
| const key = `podIssues:${cluster || 'all'}:${namespace || 'all'}` | ||
|
|
||
| const result = useCache({ | ||
| key, | ||
| category, | ||
| initialData: getDemoPodIssues(), | ||
| enabled: !isDemoMode(), | ||
| enabled: !demoMode, |
There was a problem hiding this comment.
Same as above: useCache already handles demo mode; using useDemoMode() here is redundant and adds repeated subscriptions/boilerplate across hooks.
| const { isDemoMode: demoMode } = useDemoMode() | ||
| const { category = 'deployments' } = options || {} | ||
| const key = `deploymentIssues:${cluster || 'all'}:${namespace || 'all'}` | ||
|
|
||
| const result = useCache({ | ||
| key, | ||
| category, | ||
| initialData: getDemoDeploymentIssues(), | ||
| enabled: !isDemoMode(), | ||
| enabled: !demoMode, |
There was a problem hiding this comment.
Same as above: the useDemoMode() + enabled: !demoMode pattern is redundant with useCache’s internal demo-mode gating and could be removed to keep these hooks smaller.
| const { isDemoMode: demoMode } = useDemoMode() | ||
| const { category = 'deployments' } = options || {} | ||
| const key = `deployments:${cluster || 'all'}:${namespace || 'all'}` | ||
|
|
||
| const result = useCache({ | ||
| key, | ||
| category, | ||
| initialData: getDemoDeployments(), | ||
| enabled: !isDemoMode(), | ||
| enabled: !demoMode, |
There was a problem hiding this comment.
Same as above: consider relying on useCache’s internal demo-mode gating instead of adding useDemoMode() + enabled: !demoMode in each cached hook.
| category, | ||
| initialData: getDemoServices(), | ||
| enabled: !isDemoMode(), | ||
| enabled: !demoMode, |
There was a problem hiding this comment.
Same as above: useCache already disables fetching in demo mode; consider omitting the enabled: !demoMode override here to avoid duplicated demo-mode subscriptions.
| enabled: !demoMode, |
| const { isDemoMode: demoMode } = useDemoMode() | ||
| const key = `llmd-servers:${clusters.join(',')}` | ||
|
|
||
| const result = useCache({ | ||
| key, | ||
| category: 'gitops', | ||
| initialData: getDemoLLMdServers(), | ||
| enabled: !isDemoMode(), | ||
| enabled: !demoMode, |
There was a problem hiding this comment.
Same as above: consider removing the per-hook demo-mode subscription and letting useCache’s internal demo-mode gating control fetching/returned data.
| const { isDemoMode: demoMode } = useDemoMode() | ||
| const { category = 'pods' } = options || {} | ||
| const key = `securityIssues:${cluster || 'all'}:${namespace || 'all'}` | ||
|
|
||
| const result = useCache({ | ||
| key, | ||
| category, | ||
| initialData: getDemoSecurityIssues(), | ||
| enabled: !isDemoMode(), | ||
| enabled: !demoMode, |
There was a problem hiding this comment.
Same as above: useCache already disables fetching/returns initialData in demo mode; consider removing the extra useDemoMode() + enabled override here.
| const { isDemoMode: demoMode } = useDemoMode() | ||
| const { limit = 100, category = 'pods' } = options || {} | ||
| const key = `pods:${cluster || 'all'}:${namespace || 'all'}:${limit}` | ||
|
|
||
| const result = useCache({ | ||
| key, | ||
| category, | ||
| initialData: getDemoPods(), | ||
| enabled: !isDemoMode(), | ||
| enabled: !demoMode, |
There was a problem hiding this comment.
useCache already subscribes to demo mode internally and gates fetching / returned data based on demo mode (see web/src/lib/cache/index.ts where effectiveEnabled = enabled && !demoMode). Because of that, you can omit the enabled override here (or leave enabled for non-demo conditions) and avoid adding useDemoMode() + duplicated state subscriptions in every cached hook.
| const { isDemoMode: demoMode } = useDemoMode() | ||
| const key = `prowjobs:${prowCluster}:${namespace}` | ||
|
|
||
| const result = useCache({ | ||
| key, | ||
| category: 'gitops', | ||
| initialData: getDemoProwJobs(), | ||
| enabled: !isDemoMode(), | ||
| enabled: !demoMode, |
There was a problem hiding this comment.
Same as above: since useCache already gates on demo mode internally, the added useDemoMode() + enabled: !demoMode here is redundant and could be simplified.
| const { isDemoMode: demoMode } = useDemoMode() | ||
| const key = `llmd-models:${clusters.join(',')}` | ||
|
|
||
| const result = useCache({ | ||
| key, | ||
| category: 'gitops', | ||
| initialData: getDemoLLMdModels(), | ||
| enabled: !isDemoMode(), | ||
| enabled: !demoMode, |
There was a problem hiding this comment.
Same as above: useCache already gates demo mode internally; the useDemoMode() + enabled override here is redundant boilerplate.
Replace static `isDemoMode()` function calls with reactive `useDemoMode()` hook in all `useCachedData` wrapper hooks. The problem was that `enabled: !isDemoMode()` evaluated once at mount time. When demo mode changed, this value never updated because: 1. The parent component didn't re-render (no dependency on demo mode) 2. `enabled` was computed at mount time and stayed fixed The fix: Use `useDemoMode()` hook which subscribes to demo mode changes and triggers re-renders. This causes `useCache` to receive the updated `enabled` value when mode switches. Hooks updated: - useCachedPods - useCachedEvents - useCachedPodIssues - useCachedDeploymentIssues - useCachedDeployments - useCachedServices - useCachedProwJobs - useCachedLLMdServers - useCachedLLMdModels - useCachedSecurityIssues Signed-off-by: Andrew Anderson <[email protected]> Co-authored-by: Claude Opus 4.5 <[email protected]>
Fixes #8175 The `builds wss: URL when page uses https` test in useExecSession-expand was asserting the pre-phase3d URL shape — `wss://<page-host>/ws/exec` — built from `window.location.protocol`. After #8168 migrated pod exec to kc-agent (#7993), the hook uses the `LOCAL_AGENT_WS_URL` constant (`ws://127.0.0.1:8585/ws`) unconditionally, because the SPDY exec stream now runs under the user's own kubeconfig on the local loopback rather than through the page origin. The page protocol no longer influences the URL, so the old assertion has been stale since #8168 merged. This is a pre-existing flake that Coverage Suite run #760 happened to surface on top of b828c87 (#8169). #8169 only touched useDashboardHealth, MSW handlers, and useDashboardHealth.test.ts — none of which are related to exec session URL construction. Confirmed by running the test in isolation and together with useDashboardHealth.test.ts (both pass after the fix; isolated failure reproduces on unmodified main against useExecSession.ts:235). Fix: rename the test to "builds kc-agent /ws/exec URL regardless of page protocol" and assert the new, stable target. Documented the rationale inline with source pointer to useExecSession.ts:235 so future readers don't reintroduce the old assertion. Signed-off-by: Andy Anderson <[email protected]>
Fixes #8175 The `builds wss: URL when page uses https` test in useExecSession-expand was asserting the pre-phase3d URL shape — `wss://<page-host>/ws/exec` — built from `window.location.protocol`. After #8168 migrated pod exec to kc-agent (#7993), the hook uses the `LOCAL_AGENT_WS_URL` constant (`ws://127.0.0.1:8585/ws`) unconditionally, because the SPDY exec stream now runs under the user's own kubeconfig on the local loopback rather than through the page origin. The page protocol no longer influences the URL, so the old assertion has been stale since #8168 merged. This is a pre-existing flake that Coverage Suite run #760 happened to surface on top of b828c87 (#8169). #8169 only touched useDashboardHealth, MSW handlers, and useDashboardHealth.test.ts — none of which are related to exec session URL construction. Confirmed by running the test in isolation and together with useDashboardHealth.test.ts (both pass after the fix; isolated failure reproduces on unmodified main against useExecSession.ts:235). Fix: rename the test to "builds kc-agent /ws/exec URL regardless of page protocol" and assert the new, stable target. Documented the rationale inline with source pointer to useExecSession.ts:235 so future readers don't reintroduce the old assertion. Signed-off-by: Andy Anderson <[email protected]>
Summary
Fix mode switching (demo ↔ live) requiring manual browser refresh to see updated content.
Problem
When switching between demo mode and live mode, cards showed "Demo" badges but content remained skeletons. Data only appeared after manually refreshing the browser.
Root Cause
The
useCachedDatawrapper hooks usedisDemoMode()function which evaluates once at mount time:When demo mode changed, this value never updated because the parent component had no dependency on demo mode.
Fix
Replace static
isDemoMode()function with reactiveuseDemoMode()hook:The hook subscribes to demo mode changes and triggers component re-renders, which causes
useCacheto receive the updatedenabledvalue.Hooks Updated
useCachedPodsuseCachedEventsuseCachedPodIssuesuseCachedDeploymentIssuesuseCachedDeploymentsuseCachedServicesuseCachedProwJobsuseCachedLLMdServersuseCachedLLMdModelsuseCachedSecurityIssuesTest Plan
🤖 Generated with Claude Code