Skip to content

Conversation

@adityathebe
Copy link
Member

@adityathebe adityathebe commented Jan 6, 2026

image

resolves: flanksource/mission-control#2597

Summary by CodeRabbit

  • New Features

    • Added cache status indicators to show whether view data is fresh or cached.
    • Displays last refreshed timestamp on views.
    • Enhanced "View Not Found" error handling with clearer messaging.
  • Bug Fixes

    • Improved refresh error handling with dedicated error dialog and notifications.
    • Optimized data refresh logic for better performance.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Jan 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
aws-preview Ready Ready Preview Jan 6, 2026 0:24am
flanksource-ui Ready Ready Preview Jan 6, 2026 0:24am

@coderabbitai
Copy link

coderabbitai bot commented Jan 6, 2026

Walkthrough

Adds refresh metadata to ViewResult, surfaces refresh errors in SingleView via a dialog and adjusted error/loading branches, and refactors useViewData to compute a central query key and perform selective query invalidation for specific view sections.

Changes

Cohort / File(s) Summary
Type definitions
src/pages/audit-report/types/index.ts
Added optional fields to ViewResult: `refreshStatus?: "cache"
View UI / refresh error handling
src/pages/views/components/SingleView.tsx
Added useState/useEffect for refresh error dialog, Dialog UI and conditional ErrorViewer; changed error/loading branch ordering and added "Not Found" handling; uses viewResult.refreshStatus/refreshError/responseSource.
Data fetching / cache invalidation
src/pages/views/hooks/useViewData.ts
Introduced viewQueryKey for query key centralization; compute currentName/currentNamespace from latest result; compute refsToInvalidate and replace blanket invalidation with targeted batch invalidation of view-result, view-table, and view-variables keys (preserving plugin-mode invalidation).

Sequence Diagram

sequenceDiagram
    participant User
    participant SingleView
    participant useViewData
    participant QueryClient

    User->>SingleView: Request refresh (force refresh)
    SingleView->>useViewData: handleForceRefresh()
    activate useViewData
    useViewData->>useViewData: Compute viewQueryKey
    useViewData->>useViewData: Read latest result -> currentName/currentNamespace
    useViewData->>useViewData: Compute refsToInvalidate
    useViewData->>QueryClient: Invalidate keys for refsToInvalidate (view-result, view-table, view-variables)
    deactivate useViewData

    QueryClient->>useViewData: Trigger refetches
    useViewData->>SingleView: Return updated viewResult (may include refreshStatus/refreshError/responseSource)
    alt refreshStatus == "error" and responseSource == "cache"
        SingleView->>SingleView: open refresh error Dialog (shows refreshError)
        SingleView->>User: display dialog + cached content
    else normal refresh
        SingleView->>User: display refreshed content
    end
Loading

Possibly related PRs

Suggested reviewers

  • moshloop

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: view error handling' is directly related to the main changes in the changeset, which focus on improving error handling in the view component.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/view-error

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c6f846d and 5688cc2.

📒 Files selected for processing (3)
  • src/pages/audit-report/types/index.ts
  • src/pages/views/components/SingleView.tsx
  • src/pages/views/hooks/useViewData.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/pages/audit-report/types/index.ts
🧰 Additional context used
🧬 Code graph analysis (2)
src/pages/views/components/SingleView.tsx (3)
src/components/ErrorViewer.tsx (1)
  • ErrorViewer (174-201)
src/components/ui/dialog.tsx (5)
  • Dialog (110-110)
  • DialogContent (115-115)
  • DialogHeader (116-116)
  • DialogTitle (118-118)
  • DialogDescription (119-119)
src/ui/Age/Age.tsx (1)
  • Age (24-105)
src/pages/views/hooks/useViewData.ts (2)
src/components/Canary/labels.js (1)
  • result (182-182)
src/query-client.ts (1)
  • queryClient (6-26)
🔇 Additional comments (9)
src/pages/views/hooks/useViewData.ts (4)

52-63: Centralized query key logic looks good.

The viewQueryKey computation correctly centralizes the conditional key logic and is reused in the useQuery call. This improves maintainability.


125-134: Selective invalidation logic addresses past review feedback.

The dependency array now correctly includes viewResult?.namespace and viewResult?.name (lines 156-157), addressing the stale closure concern from the previous review.

The filtering logic correctly excludes the current view from invalidation to prevent redundant refetching since the current view is already refreshed via refetch().


142-154: Targeted invalidation improves efficiency.

Using flatMap to selectively invalidate only the relevant section queries (view-result, view-table, view-variables) is a good approach. This avoids unnecessary cache invalidation while ensuring related queries are refreshed.


155-164: Dependency array is now complete.

The callback dependencies correctly include all values referenced within the function body. The addition of viewResult?.namespace and viewResult?.name ensures the fallback values on lines 125-126 stay current.

src/pages/views/components/SingleView.tsx (5)

31-33: Good defensive computation of refresh error state.

The conditional assignment ensures refreshError is only set when the refresh status explicitly indicates an error, preventing false positives.


35-39: Dialog auto-open logic looks correct.

Including viewResult?.requestFingerprint in the dependency array ensures the dialog can re-trigger for new request cycles with fresh errors, even if the error message is identical. The dialog appropriately requires manual dismissal, allowing users to acknowledge cached data.


41-68: Error and loading branch ordering is correct.

Prioritizing error state over loading state (when no cached data exists) ensures users see failures immediately. The !viewResult guards correctly preserve cached data display when available.


89-103: Refresh error dialog provides clear user feedback.

The dialog clearly explains the situation to users and optionally displays technical error details. The defensive check on line 99 is acceptable given the component may remain mounted while the error state changes.


104-125: Good addition of last refresh timestamp.

The extra prop displaying the last refresh time provides valuable context about data freshness, especially when cached data is being shown after a refresh failure.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI Agents
In @src/pages/views/hooks/useViewData.ts:
- Around line 125-134: The callback that computes currentNamespace/currentName
and refsToInvalidate uses viewResult as a fallback but viewResult is missing
from the useCallback dependency array; update the dependency arrays for the
callback(s) that reference currentNamespace/currentName/refsToInvalidate (and
the similar callback around lines 155-163) to include viewResult so the closure
sees updated viewResult values, ensuring sectionsToRefresh, result, and
viewResult are all listed as dependencies alongside any other existing deps.
🧹 Nitpick comments (2)
src/pages/views/components/SingleView.tsx (2)

35-39: Dialog doesn't auto-close on successful refresh.

The useEffect only opens the dialog when an error occurs but doesn't close it when the refresh eventually succeeds (i.e., when refreshError becomes undefined). This is likely fine since users can dismiss manually, but for better UX you may want to auto-close.

🔎 Optional: Auto-close dialog on success
   useEffect(() => {
     if (refreshError && isCachedResponse) {
       setRefreshErrorOpen(true);
+    } else if (!refreshError) {
+      setRefreshErrorOpen(false);
     }
   }, [refreshError, isCachedResponse, viewResult?.requestFingerprint]);

62-65: Consider using a shared spinner component.

The inline spinner implementation works, but if the codebase has a shared Spinner or Loading component, using it would improve consistency.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5accfb5 and c6f846d.

📒 Files selected for processing (3)
  • src/pages/audit-report/types/index.ts
  • src/pages/views/components/SingleView.tsx
  • src/pages/views/hooks/useViewData.ts
🧰 Additional context used
🧬 Code graph analysis (2)
src/pages/views/hooks/useViewData.ts (1)
src/query-client.ts (1)
  • queryClient (6-26)
src/pages/views/components/SingleView.tsx (3)
src/components/ErrorViewer.tsx (1)
  • ErrorViewer (174-201)
src/components/ui/dialog.tsx (5)
  • Dialog (110-110)
  • DialogContent (115-115)
  • DialogHeader (116-116)
  • DialogTitle (118-118)
  • DialogDescription (119-119)
src/ui/Age/Age.tsx (1)
  • Age (24-105)
🔇 Additional comments (5)
src/pages/audit-report/types/index.ts (1)

436-439: LGTM! Well-structured refresh metadata fields.

The new optional fields cleanly extend ViewResult for refresh error handling. The separation between refreshStatus (operation outcome) and responseSource (data origin) allows the UI to distinguish between a failed refresh that returns cached data vs. a successful cache hit.

src/pages/views/hooks/useViewData.ts (2)

52-54: Clean refactor of query key computation.

Extracting viewQueryKey into a dedicated variable improves readability and makes the conditional logic easier to follow.


142-154: Selective invalidation logic looks correct.

The change to invalidate only section refs that don't match the current view is a good optimization—it avoids redundant invalidation of the query that was just refetched.

src/pages/views/components/SingleView.tsx (2)

41-84: Well-structured error and loading state handling.

The guard clauses properly handle the error, loading, and not-found states before rendering the main content. The order is correct: error state takes precedence, then loading, then not-found.


88-126: Refresh error dialog implementation looks good.

The dialog correctly displays the error message with context about cached data being shown. Using requestFingerprint in the effect dependency ensures the dialog responds to new requests.

@moshloop moshloop merged commit 2273720 into main Jan 7, 2026
14 of 16 checks passed
@moshloop moshloop deleted the fix/view-error branch January 7, 2026 07:57
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.

View refresh errors hidden when cache exists

3 participants