Skip to content

Conversation

@adityathebe
Copy link
Member

@adityathebe adityathebe commented Dec 8, 2025

Summary by CodeRabbit

  • New Features

    • Unified view data layer with aggregated/current variables and a consolidated section-aware view component.
    • Manual refresh control exposed as a single "force refresh" action; optional hiding of variable UI.
  • Refactor

    • Centralized loading and error handling with a dedicated error viewer and simplified view layout.
  • Bug Fixes

    • Better handling for sections lacking a namespace to prevent missing data.

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

@vercel
Copy link

vercel bot commented Dec 8, 2025

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

Project Deployment Preview Updated (UTC)
aws-preview Ready Ready Preview Dec 9, 2025 4:06pm
flanksource-ui Ready Ready Preview Dec 9, 2025 4:06pm

@coderabbitai
Copy link

coderabbitai bot commented Dec 8, 2025

Walkthrough

Centralizes view data fetching into a new useViewData hook, adds ViewWithSections for sectioned rendering, updates SingleView and ConfigDetailsViewPage to use the hook and ErrorViewer, adjusts namespace handling for section fetches, and makes ViewRef.namespace optional.

Changes

Cohort / File(s) Summary
New hook-based data layer
src/pages/views/hooks/useViewData.ts
Adds useViewData hook that fetches view/display-plugin data via React Query, aggregates variables, exposes viewResult, isLoading, isFetching, error, aggregatedVariables, currentVariables, and handleForceRefresh, and manages related query invalidation.
New view rendering component
src/pages/views/components/ViewWithSections.tsx
New ViewWithSections component that renders global variable filters, primary view section, and additional sections; detects aggregator views and conditionally hides variables or the primary section.
Pages/components updated to use hook
src/pages/views/components/SingleView.tsx, src/pages/config/details/ConfigDetailsViewPage.tsx
Replaces per-file useQuery and manual refetch/cache logic with useViewData; delegates rendering to ViewWithSections; swaps toast-based errors for ErrorViewer; exposes handleForceRefresh for refresh control.
Variable aggregation helper adjusted
src/pages/views/hooks/useAggregatedViewVariables.ts
Calls getViewDataByNamespace with `namespace
View section fetch enablement tweak
src/pages/views/components/ViewSection.tsx
Passes `namespace
Type change
src/pages/audit-report/types/index.ts
Makes ViewRef.namespace optional (namespace?: string), allowing references without a namespace.

Sequence Diagram(s)

sequenceDiagram
    participant UI as SingleView / ConfigDetailsViewPage
    participant Hook as useViewData
    participant Q as React-Query
    participant API as Backend API
    participant View as ViewWithSections

    UI->>Hook: init(viewId[, configId])
    Hook->>Q: start queries (viewResult, display-plugin vars?)
    Q->>API: fetch view data / plugin vars
    API-->>Q: return data
    Q-->>Hook: query results (data/error/loading)
    Hook->>Hook: aggregate variables (useAggregatedViewVariables)
    Hook-->>UI: return viewResult, isLoading, isFetching, error, aggregatedVariables, currentVariables, handleForceRefresh
    UI->>View: render with viewResult + variables
    Note over UI,Hook: on user refresh
    UI->>Hook: call handleForceRefresh()
    Hook->>Q: refetch & invalidate dependent keys
    Q->>API: refetch
    API-->>Q: fresh data
    Q-->>Hook: updated results -> UI re-renders
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 sections in config details page' directly describes the main focus of the changes, which involves refactoring view section rendering in the ConfigDetailsViewPage component using a new ViewWithSections 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-sections-on-config-page

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

🧹 Nitpick comments (3)
src/pages/config/details/ConfigDetailsViewPage.tsx (2)

21-24: Non-null assertion on viewId could mask routing issues.

If the route is misconfigured or the user navigates directly without a viewId, this will pass undefined! which becomes "undefined" string when coerced, potentially causing confusing API errors instead of a clear "missing parameter" state.

Consider adding a guard or returning early if viewId is missing:

+ if (!viewId) {
+   return <div>View ID is required</div>;
+ }
+
  const {
    viewResult,
    isLoading,
    error,
    aggregatedVariables,
    currentVariables,
    handleForceRefresh
  } = useViewData({
-   viewId: viewId!,
+   viewId,
    configId
  });

35-35: Remove empty className attribute.

The empty string serves no purpose and adds noise.

-     <div className="">
+     <div>
src/pages/views/hooks/useViewData.ts (1)

95-139: The query invalidation after refetch() may be redundant.

On lines 121-125, you invalidate the same query key that was just refetched. Since refetch() already updates the cache, this invalidation triggers an additional refetch. If this is intentional (e.g., to force dependent components to re-render), consider adding a comment explaining the rationale.

Also, the error handling on lines 100-109 is thorough, but the type cast to any could be replaced with a more specific error type if available.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57bd6e6 and eddd315.

📒 Files selected for processing (4)
  • src/pages/config/details/ConfigDetailsViewPage.tsx (1 hunks)
  • src/pages/views/components/SingleView.tsx (3 hunks)
  • src/pages/views/components/ViewWithSections.tsx (1 hunks)
  • src/pages/views/hooks/useViewData.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/pages/views/hooks/useViewData.ts (3)
src/pages/audit-report/types/index.ts (3)
  • ViewResult (420-435)
  • ViewVariable (382-389)
  • ViewRef (409-412)
src/api/services/views.ts (2)
  • getViewDisplayPluginVariables (140-148)
  • getViewDataById (112-122)
src/components/Toast/toast.ts (1)
  • toastError (15-25)
src/pages/views/components/ViewWithSections.tsx (3)
src/pages/audit-report/types/index.ts (3)
  • ViewResult (420-435)
  • ViewVariable (382-389)
  • ViewSection (414-418)
src/pages/audit-report/components/View/GlobalFiltersForm.tsx (1)
  • GlobalFiltersForm (65-90)
src/pages/views/constants.ts (1)
  • VIEW_VAR_PREFIX (2-2)
src/pages/config/details/ConfigDetailsViewPage.tsx (3)
src/pages/views/hooks/useViewData.ts (1)
  • useViewData (30-159)
src/ui/Loading/index.tsx (1)
  • Loading (11-37)
src/components/ErrorViewer.tsx (1)
  • ErrorViewer (68-115)
src/pages/views/components/SingleView.tsx (1)
src/pages/views/hooks/useViewData.ts (1)
  • useViewData (30-159)
🔇 Additional comments (10)
src/pages/config/details/ConfigDetailsViewPage.tsx (1)

36-58: LGTM!

The conditional rendering logic properly handles all states (loading, error, data, and fallback), and the delegation to ViewWithSections with hideVariables is appropriate for the config details context.

src/pages/views/components/ViewWithSections.tsx (3)

1-14: LGTM!

Clean imports and well-defined props interface. The optional props (aggregatedVariables, currentVariables, hideVariables) provide good flexibility for different usage contexts.


25-37: LGTM!

The isAggregatorView determination correctly identifies views that only contain sections without their own content. The primaryViewSection construction properly handles the optional namespace field.


42-79: LGTM!

The rendering logic correctly handles all cases:

  • Global filters are shown only when appropriate
  • Primary view section is skipped for aggregator views (which only contain sections)
  • Section keys use the unique namespace:name pattern
  • hideVariables is properly propagated to child ViewSection components to prevent duplicate filter UI
src/pages/views/hooks/useViewData.ts (3)

39-43: Consider handling the loading/error state for displayPluginVariables.

The query for displayPluginVariables doesn't expose its loading or error state. If this query fails or is slow, the main view query will remain disabled (since enabled: isDisplayPluginMode ? !!variables : !!viewId), potentially leaving the user in a perpetual loading state without feedback.

Consider whether you need to surface loading/error states from this query:

- const { data: displayPluginVariables } = useQuery({
+ const { data: displayPluginVariables, isLoading: isLoadingVariables, error: variablesError } = useQuery({
    queryKey: ["viewDisplayPluginVariables", viewId, configId],
    queryFn: () => getViewDisplayPluginVariables(viewId, configId!),
    enabled: isDisplayPluginMode
  });

47-66: LGTM!

The query configuration is well-structured:

  • Distinct query keys for each mode prevent cache collisions
  • The enabled condition properly gates fetching until dependencies are ready
  • staleTime of 5 minutes is reasonable for view data
  • keepPreviousData is appropriate for v4 of React Query

150-158: LGTM!

The return values correctly differentiate between display plugin mode (empty aggregatedVariables, plugin-derived currentVariables) and standard mode (aggregated variables from all sections).

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

1-6: LGTM!

Clean imports. The migration to the new useViewData hook and ViewWithSections component simplifies the component significantly while maintaining proper separation of concerns.


23-66: LGTM!

The state handling is well-structured:

  • Loading spinner only appears on initial load (not during background refetches)
  • Error and not-found states provide appropriate feedback
  • All states include the refresh action for recovery

68-93: LGTM!

The main render correctly passes all necessary props to ViewWithSections. Notably, hideVariables is not passed here (unlike in ConfigDetailsViewPage), so global filters will be displayed—which is the expected behavior for the standalone view page.

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: 3

🧹 Nitpick comments (3)
src/pages/config/details/ConfigDetailsViewPage.tsx (1)

21-24: Consider guarding against undefined viewId.

The non-null assertion viewId! could cause issues if the route is accessed without a viewId param. While useViewData has internal enabled checks, consider adding an early return or explicit guard for better clarity and to prevent potential edge-case issues.

+  if (!viewId) {
+    return (
+      <ConfigDetailsTabs pageTitlePrefix="Config View" activeTabName="">
+        <div className="flex flex-1 flex-col items-center justify-center">
+          <div className="text-center text-gray-500">View ID is required</div>
+        </div>
+      </ConfigDetailsTabs>
+    );
+  }
+
   const {
     viewResult,
     isLoading,
     error,
     aggregatedVariables,
     currentVariables,
     handleForceRefresh
   } = useViewData({
-    viewId: viewId!,
+    viewId,
     configId
   });
src/pages/views/components/ViewWithSections.tsx (1)

66-77: Inconsistent key fallback for undefined namespace.

Line 59 uses namespace || "default" for the primary section key, but line 70 uses section.viewRef.namespace directly without a fallback. If namespace is undefined, the key becomes "undefined:name". Consider using a consistent fallback pattern.

           {viewResult.sections.map((section) => (
             <div
-              key={`${section.viewRef.namespace}:${section.viewRef.name}`}
+              key={`${section.viewRef.namespace || "default"}:${section.viewRef.name}`}
               className="mt-4"
             >
src/pages/views/hooks/useViewData.ts (1)

86-94: Avoid unnecessary aggregated variable fetching in display‑plugin mode

When configId is provided, the hook:

  • Still calls useAggregatedViewVariables(allSectionRefs), which will likely spin up per‑section queries.
  • Then discards aggregatedVariables and ignores aggregatedCurrentVariables via:
const currentVariables = isDisplayPluginMode
  ? (variables ?? {})
  : aggregatedCurrentVariables;

return {
  ...
  aggregatedVariables: isDisplayPluginMode ? [] : aggregatedVariables,
  currentVariables,
};

So in display‑plugin mode you pay the cost of the extra queries and aggregation but don’t use their results.

You can short‑circuit the aggregation when isDisplayPluginMode is true:

-  const {
-    variables: aggregatedVariables,
-    currentVariables: aggregatedCurrentVariables
-  } = useAggregatedViewVariables(allSectionRefs);
+  const {
+    variables: aggregatedVariables,
+    currentVariables: aggregatedCurrentVariables
+  } = useAggregatedViewVariables(
+    isDisplayPluginMode ? [] : allSectionRefs
+  );
@@
-  const currentVariables = isDisplayPluginMode
-    ? (variables ?? {})
-    : aggregatedCurrentVariables;
+  const currentVariables = isDisplayPluginMode
+    ? (variables ?? {})
+    : aggregatedCurrentVariables;
@@
-    aggregatedVariables: isDisplayPluginMode ? [] : aggregatedVariables,
+    aggregatedVariables,

If there’s a future need to mix plugin variables with aggregated ones, this can be revisited, but for now this keeps network and compute overhead down in config/plugin mode.

Also applies to: 150-158

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eddd315 and c5708d4.

📒 Files selected for processing (7)
  • src/pages/audit-report/types/index.ts (1 hunks)
  • src/pages/config/details/ConfigDetailsViewPage.tsx (1 hunks)
  • src/pages/views/components/SingleView.tsx (3 hunks)
  • src/pages/views/components/ViewSection.tsx (1 hunks)
  • src/pages/views/components/ViewWithSections.tsx (1 hunks)
  • src/pages/views/hooks/useAggregatedViewVariables.ts (1 hunks)
  • src/pages/views/hooks/useViewData.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
src/pages/config/details/ConfigDetailsViewPage.tsx (4)
src/pages/views/hooks/useViewData.ts (1)
  • useViewData (30-159)
src/components/Configs/ConfigDetailsTabs.tsx (1)
  • ConfigDetailsTabs (31-91)
src/ui/Loading/index.tsx (1)
  • Loading (11-37)
src/components/ErrorViewer.tsx (1)
  • ErrorViewer (68-115)
src/pages/views/components/ViewWithSections.tsx (3)
src/pages/audit-report/types/index.ts (3)
  • ViewResult (430-446)
  • ViewVariable (387-394)
  • ViewSection (424-428)
src/pages/audit-report/components/View/GlobalFiltersForm.tsx (1)
  • GlobalFiltersForm (65-90)
src/pages/views/constants.ts (1)
  • VIEW_VAR_PREFIX (2-2)
src/pages/views/hooks/useViewData.ts (4)
src/pages/audit-report/types/index.ts (3)
  • ViewResult (430-446)
  • ViewVariable (387-394)
  • ViewRef (419-422)
src/api/services/views.ts (2)
  • getViewDisplayPluginVariables (140-148)
  • getViewDataById (112-122)
src/pages/views/hooks/useAggregatedViewVariables.ts (1)
  • useAggregatedViewVariables (9-53)
src/components/Toast/toast.ts (1)
  • toastError (15-25)
src/pages/views/components/SingleView.tsx (1)
src/pages/views/hooks/useViewData.ts (1)
  • useViewData (30-159)
src/pages/views/components/ViewSection.tsx (1)
src/api/services/views.ts (1)
  • getViewDataByNamespace (124-135)
🔇 Additional comments (6)
src/pages/views/components/ViewSection.tsx (1)

36-41: LGTM! Type-safe namespace handling.

The fallback to empty string on line 38 ensures getViewDataByNamespace always receives a string as expected by its signature, while the enabled condition on line 39 still correctly prevents the query from running when namespace is falsy.

src/pages/views/hooks/useAggregatedViewVariables.ts (1)

32-41: LGTM! Consistent namespace handling.

The change mirrors the pattern in ViewSection.tsx, ensuring type-safe string values for getViewDataByNamespace while the enabled condition correctly prevents queries when namespace is falsy.

src/pages/config/details/ConfigDetailsViewPage.tsx (1)

35-59: Clean refactoring of the view rendering logic.

The conditional rendering structure is clear and handles all states appropriately. The integration with ViewWithSections and ErrorViewer components follows good component composition patterns.

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

25-29: Verify intended behavior for empty panels/columns arrays.

The isAggregatorView check uses !panels && !columns, which treats empty arrays as truthy (not aggregator). If the intent is to also consider empty arrays as "no content," the check should be:

const isAggregatorView =
  viewResult.sections?.length > 0 &&
  (!panels || panels.length === 0) &&
  (!columns || columns.length === 0);

16-41: Well-structured component with clear responsibilities.

The component cleanly separates concerns: aggregated variable display at the top level, primary section rendering, and additional sections. The hideVariables prop correctly controls filter visibility, and the logic flow is easy to follow.

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

12-22: SingleView’s integration with useViewData and ViewWithSections looks correct

The component cleanly delegates data fetching to useViewData({ viewId: id }), handles loading/error/not‑found states before destructuring viewResult, and then passes viewResult, aggregatedVariables, currentVariables, and handleForceRefresh through to ViewWithSections. This keeps SingleView lean and consistent with the new shared data layer used on the config details page.

Also applies to: 68-90

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: 0

♻️ Duplicate comments (1)
src/pages/views/hooks/useViewData.ts (1)

30-167: Hook correctly unifies view + display‑plugin queries and fixes prior error/namespace issues

This hook looks solid:

  • Display‑plugin mode now exposes its own loading/fetching/error states and correctly gates the main view query on variables, so plugin failures surface via error instead of silently blocking viewResult.
  • allSectionRefs and sectionsToRefresh normalize namespaces with ?? "", which aligns with other view hooks and ensures cache invalidation works even when namespace is absent.
  • handleForceRefresh uses a cache‑busting header, invalidates both plugin and main view queries (with mode‑aware keys), and refreshes per‑section "view-result", "view-table", and "view-variables" queries via prefix keys.

I don’t see functional issues in the current design; this neatly centralizes view data/refresh behavior.

🧹 Nitpick comments (2)
src/pages/views/hooks/useAggregatedViewVariables.ts (1)

25-41: Recheck enabled condition now that namespace is normalized to an empty string

queryFn always normalizes the namespace with section.namespace || "", but enabled still requires a truthy namespace (!!section.namespace && !!section.name). For refs coming from useViewData, namespace is "" when absent, so these queries will never run even though the backend accepts "" as the namespace.

If you want aggregated variables for namespace-less views/sections, consider relaxing this to only require a name:

-      enabled: !!section.namespace && !!section.name,
+      enabled: !!section.name,

Otherwise, it may be worth documenting that aggregation is intentionally disabled for namespace-less refs.

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

12-91: SingleView’s new data flow is clean; consider whether errors should hide stale data

The refactor to useViewData plus ViewWithSections is straightforward: loading/error/not‑found states are clearly separated, handleForceRefresh is threaded through consistently, and isFetching is used to drive the layout’s loading state while data is present.

One UX nuance to think about: when a background refetch fails, error will be truthy while viewResult still holds previous data (because of keepPreviousData: true), but the current logic shows only the error screen. If you’d rather keep showing the last successful result with an inline error banner, you could gate on !viewResult in the error path and otherwise render ViewWithSections plus an error indication.

As written, though, behavior is consistent and correct.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c5708d4 and 6f8976c.

📒 Files selected for processing (7)
  • src/pages/audit-report/types/index.ts (1 hunks)
  • src/pages/config/details/ConfigDetailsViewPage.tsx (1 hunks)
  • src/pages/views/components/SingleView.tsx (3 hunks)
  • src/pages/views/components/ViewSection.tsx (1 hunks)
  • src/pages/views/components/ViewWithSections.tsx (1 hunks)
  • src/pages/views/hooks/useAggregatedViewVariables.ts (1 hunks)
  • src/pages/views/hooks/useViewData.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/pages/audit-report/types/index.ts
  • src/pages/views/components/ViewSection.tsx
  • src/pages/views/components/ViewWithSections.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
src/pages/config/details/ConfigDetailsViewPage.tsx (4)
src/pages/views/hooks/useViewData.ts (1)
  • useViewData (30-168)
src/components/Configs/ConfigDetailsTabs.tsx (1)
  • ConfigDetailsTabs (31-91)
src/ui/Loading/index.tsx (1)
  • Loading (11-37)
src/components/ErrorViewer.tsx (1)
  • ErrorViewer (160-187)
src/pages/views/components/SingleView.tsx (1)
src/pages/views/hooks/useViewData.ts (1)
  • useViewData (30-168)
🔇 Additional comments (1)
src/pages/config/details/ConfigDetailsViewPage.tsx (1)

4-60: New useViewData/ViewWithSections wiring for config views looks consistent

The refactor to use useViewData plus ViewWithSections is coherent: loading/error/empty states are handled cleanly, and passing handleForceRefresh into ConfigDetailsTabs keeps the refresh behavior wired through without changing its contract (it happily accepts an async function). No functional issues stand out here.

@adityathebe adityathebe merged commit 5d4c661 into main Dec 11, 2025
14 of 16 checks passed
@adityathebe adityathebe deleted the fix/view-sections-on-config-page branch December 11, 2025 11:28
@netlify
Copy link

netlify bot commented Dec 19, 2025

Deploy Preview for clerk-saas-ui failed. Why did it fail? →

Name Link
🔨 Latest commit 6f8976c
🔍 Latest deploy log https://app.netlify.com/projects/clerk-saas-ui/deploys/6938477ea26f77000874e081

@netlify
Copy link

netlify bot commented Dec 19, 2025

Deploy Preview for flanksource-demo-stable failed. Why did it fail? →

Name Link
🔨 Latest commit 6f8976c
🔍 Latest deploy log https://app.netlify.com/projects/flanksource-demo-stable/deploys/6938477e1a10b00008201508

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.

2 participants