Skip to content

Conversation

@vojtechszocs
Copy link
Contributor

@vojtechszocs vojtechszocs commented Nov 19, 2025

  • packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
  • public/components/persistent-volume-claim.tsx
  • public/components/persistent-volume.tsx
  • public/components/storage-class.tsx

@vojtechszocs vojtechszocs changed the title Migrate storage related tables to ConsoleDataView CONSOLE-4723: Migrate storage related tables to ConsoleDataView Nov 19, 2025
@openshift-ci openshift-ci bot requested review from TheRealJon and jhadvig November 19, 2025 21:28
@openshift-ci-robot
Copy link
Contributor

openshift-ci-robot commented Nov 19, 2025

@vojtechszocs: This pull request references CONSOLE-4723 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Walkthrough

Migrates multiple list/table components to ConsoleDataView (volume-snapshot, persistent-volume, persistent-volume-claim, storage-class, PVC/PV); converts several component signatures to React.FCC; removes legacy per-row/table props (notably unfilteredData); changes NodeFilters from an interface to a type alias; removes a few empty exported types; adds data-view helpers/columns and translation keys.

Changes

Cohort / File(s) Summary
Node type change
frontend/packages/console-app/src/components/nodes/NodesPage.tsx
NodeFilters changed from an interface extending ResourceFilters to a type alias intersection: type NodeFilters = ResourceFilters & { status: string[]; roles: string[]; architecture: string[] }.
VolumeSnapshot: class table
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
Replaced legacy table/row rendering with ConsoleDataView; added getDataViewRows, useVolumeSnapshotClassColumns, kind constant; removed unfilteredData prop; wrapped rendering in Suspense + LoadingBox; removed ListPageFilter.
VolumeSnapshot: content table
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
Migrated to ConsoleDataView: added getDataViewRows, useVolumeSnapshotContentColumns; removed unfilteredData; renders via ConsoleDataView inside Suspense + LoadingBox; replaced per-row rendering and filters with data-view flow.
VolumeSnapshot: snapshots & filters
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
Full data-view migration: added getDataViewRows, useVolumeSnapshotColumns, VolumeSnapshotRowData, VolumeSnapshotFilters; removed legacy unfilteredData/rowData and ListPageFilter; added DataViewCheckboxFilter, DASH/LoadingBox fallbacks; components now use React.FCC.
PersistentVolumeClaim (PVC)
frontend/public/components/persistent-volume-claim.tsx
Reworked PVC list/details to ConsoleDataView: added getDataViewRows, usePersistentVolumeClaimColumns, tableColumnInfo, status filters; renamed/added exports (PVCDetails, PersistentVolumeClaimList, PersistentVolumeClaimsPage) and props/types; removed legacy table behavior and unfilteredData.
PersistentVolume (PV)
frontend/public/components/persistent-volume.tsx
Replaced PV table with ConsoleDataView: added PersistentVolumeList, usePersistentVolumeColumns, getDataViewRows; renamed DetailsPVDetails and wired into details page; added LoadingBox and hid column management.
StorageClass
frontend/public/components/storage-class.tsx
Switched to ConsoleDataView: added StorageClassList export, getDataViewRows, useStorageClassColumns, tableColumnInfo; derive kind from StorageClassModel; updated page/list/detail components and exported props/types; removed old table-row exports.
Container security (minor)
frontend/packages/container-security/src/components/image-manifest-vuln.tsx
Removed an exported empty type alias: ImageManifestVulnListTableHeaderProps.
CustomResourceDefinition page props
frontend/public/components/custom-resource-definition.tsx
Removed exported empty CustomResourceDefinitionsPageProps type and loosened CustomResourceDefinitionsPage typing to React.FC.
Masthead toolbar
frontend/public/components/masthead/masthead-toolbar.tsx
Added module-level isTroubleshootingPanelPluginActive constant (reads window.SERVER_FLAGS.consolePlugins) and replaced per-call computation with this flag when adding troubleshooting launch actions.
Locales: translations
frontend/packages/console-app/locales/en/console-app.json, frontend/public/locales/en/public.json
Added translation keys (e.g., "Default", "Pending", "Error", "PersistentVolume", "Capacity", "StorageClass", "Bound", "Lost", "Claim") and removed duplicate/obsolete entries in public.json.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas needing extra attention:

  • getDataViewRows implementations across volume-snapshot, PVC, PV, and StorageClass — verify per-cell content, action menus, and DASH fallbacks.
  • use*Columns hooks and tableColumnInfo consistency (column IDs, sticky/nowrap flags, sort metadata).
  • Filtering wiring: DataViewCheckboxFilter, initialFilters, and matchesAdditionalFilters behavior and parity with previous filters.
  • Public API/signature changes: removed unfilteredData, new/renamed exported components/types, and React.FCC signature changes — confirm downstream consumers.
  • Deleted empty exported types (container-security, CRD props) — ensure no external reliance.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between e67fcad and 4acf7c1.

📒 Files selected for processing (12)
  • frontend/packages/console-app/locales/en/console-app.json (2 hunks)
  • frontend/packages/console-app/src/components/nodes/NodesPage.tsx (1 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (3 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (3 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (4 hunks)
  • frontend/packages/container-security/src/components/image-manifest-vuln.tsx (0 hunks)
  • frontend/public/components/custom-resource-definition.tsx (1 hunks)
  • frontend/public/components/masthead/masthead-toolbar.tsx (2 hunks)
  • frontend/public/components/persistent-volume-claim.tsx (12 hunks)
  • frontend/public/components/persistent-volume.tsx (3 hunks)
  • frontend/public/components/storage-class.tsx (4 hunks)
  • frontend/public/locales/en/public.json (2 hunks)
💤 Files with no reviewable changes (1)
  • frontend/packages/container-security/src/components/image-manifest-vuln.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
  • frontend/packages/console-app/locales/en/console-app.json
  • frontend/public/components/masthead/masthead-toolbar.tsx
  • frontend/packages/console-app/src/components/nodes/NodesPage.tsx
  • frontend/public/components/custom-resource-definition.tsx
  • frontend/public/locales/en/public.json
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
  • frontend/public/components/storage-class.tsx
  • frontend/public/components/persistent-volume.tsx
  • frontend/public/components/persistent-volume-claim.tsx
🧬 Code graph analysis (4)
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (4)
frontend/public/models/index.ts (3)
  • VolumeSnapshotContentModel (1279-1294)
  • VolumeSnapshotModel (1245-1260)
  • VolumeSnapshotClassModel (1262-1277)
frontend/packages/console-app/src/components/data-view/types.ts (1)
  • GetDataViewRows (26-29)
frontend/public/module/k8s/types.ts (1)
  • VolumeSnapshotContentKind (1098-1115)
frontend/packages/console-app/src/components/data-view/ConsoleDataView.tsx (4)
  • getNameCellProps (250-255)
  • actionsCellProps (257-261)
  • cellIsStickyProps (240-243)
  • ConsoleDataView (83-238)
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (7)
frontend/public/models/index.ts (1)
  • VolumeSnapshotClassModel (1262-1277)
frontend/packages/console-app/src/components/data-view/types.ts (1)
  • GetDataViewRows (26-29)
frontend/public/module/k8s/k8s.ts (1)
  • referenceFor (50-65)
frontend/public/components/utils/resource-link.tsx (1)
  • ResourceLink (71-127)
frontend/packages/console-app/src/components/data-view/ConsoleDataView.tsx (3)
  • getNameCellProps (250-255)
  • actionsCellProps (257-261)
  • ConsoleDataView (83-238)
frontend/packages/console-dynamic-plugin-sdk/src/api/dynamic-core-api.ts (1)
  • ListPageCreate (210-211)
frontend/public/components/utils/firehose.jsx (1)
  • loadError (127-127)
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (4)
frontend/packages/console-app/src/components/data-view/types.ts (2)
  • GetDataViewRows (26-29)
  • ResourceFilters (5-8)
frontend/public/components/utils/resource-link.tsx (1)
  • ResourceLink (71-127)
frontend/packages/console-app/src/components/data-view/ConsoleDataView.tsx (5)
  • getNameCellProps (250-255)
  • actionsCellProps (257-261)
  • cellIsStickyProps (240-243)
  • initialFiltersDefault (29-29)
  • ConsoleDataView (83-238)
frontend/public/components/factory/table.tsx (1)
  • TableColumn (668-675)
frontend/public/components/storage-class.tsx (5)
frontend/public/components/RBAC/role.jsx (8)
  • tableColumnInfo (47-47)
  • columns (250-250)
  • columns (448-448)
  • props (252-252)
  • props (295-297)
  • props (447-447)
  • getDataViewRows (49-85)
  • pages (376-376)
frontend/packages/console-app/src/components/data-view/types.ts (1)
  • GetDataViewRows (26-29)
frontend/public/module/k8s/types.ts (1)
  • StorageClassResourceKind (477-483)
frontend/packages/console-app/src/components/data-view/ConsoleDataView.tsx (4)
  • getNameCellProps (250-255)
  • actionsCellProps (257-261)
  • cellIsStickyProps (240-243)
  • ConsoleDataView (83-238)
frontend/public/components/factory/details.tsx (2)
  • DetailsPageProps (166-193)
  • DetailsPage (62-164)
🔇 Additional comments (13)
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (1)

158-178: LGTM - VolumeSnapshotContentTable correctly wired to ConsoleDataView.

The component correctly uses the data-view pattern with Suspense fallback, memoized columns, and proper prop forwarding.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (1)

42-62: Good pattern: passing translation function to row creator.

The getDataViewRowsCreator pattern correctly avoids calling hooks inside the row mapping function by accepting t as a parameter. This enables proper i18n for the "Default" label while respecting React's rules of hooks.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (2)

71-73: Correct size conversion pattern.

Unlike volume-snapshot-content.tsx, this file correctly converts the Kubernetes quantity to base bytes before humanizing. This is the expected pattern.


263-276: Status filter implementation is well-structured.

The matchesAdditionalFilters callback correctly handles status filtering with early return for efficiency, and the empty dependency array is appropriate since volumeSnapshotStatus is a stable import.

frontend/public/components/persistent-volume.tsx (1)

56-113: Rules of Hooks violation properly resolved.

The previous issue with calling useTranslation() inside getDataViewRows has been correctly fixed by refactoring to a creator pattern. The function now accepts the translation function t as a parameter (injected from the component at line 255), eliminating the hook violation while maintaining translation support.

frontend/public/components/persistent-volume-claim.tsx (8)

1-77: LGTM: Clean imports and column configuration.

The imports are well-organized and the tableColumnInfo constant provides a clear mapping for DataView columns.


79-103: LGTM: Extension-based status rendering.

The priority-based extension resolution with fallback to the standard Status component is implemented correctly.


105-174: LGTM: Well-structured row creator pattern.

The creator function pattern correctly addresses the hooks issue from previous reviews. The use of DASH for missing values and consistent optional chaining throughout the mapping logic is good.


176-233: LGTM: Properly memoized column definitions.

The hook correctly memoizes column definitions with appropriate dependencies and provides comprehensive column configuration.


235-416: LGTM: Comprehensive details rendering.

The details component correctly handles all PVC attributes with proper fallbacks using DASH for missing values.


418-467: LGTM: Proper memoization and filter setup.

The DataView setup with memoized columns, row creator, and filter options follows best practices.


483-499: LGTM: Clean DataView rendering.

The ConsoleDataView component is properly configured with all necessary props and appropriate Suspense boundary.


568-619: LGTM: Clean details page and type definitions.

The details page configuration and exported type definitions are well-structured and follow established patterns.


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

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Nov 19, 2025
@openshift-ci openshift-ci bot added the component/core Related to console core functionality label Nov 19, 2025
@vojtechszocs
Copy link
Contributor Author

/hold

@openshift-ci openshift-ci bot added component/helm Related to helm-plugin approved Indicates a PR has been approved by an approver from all required OWNERS files. component/monitoring Related to monitoring do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. labels Nov 19, 2025
@openshift-ci-robot
Copy link
Contributor

openshift-ci-robot commented Nov 19, 2025

@vojtechszocs: This pull request references CONSOLE-4723 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Depends on #15713

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot
Copy link
Contributor

openshift-ci-robot commented Nov 19, 2025

@vojtechszocs: This pull request references CONSOLE-4723 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Depends on #15713

  • packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
  • public/components/persistent-volume-claim.tsx
  • public/components/persistent-volume.jsx
  • public/components/storage-class.tsx
  • public/components/volumes-table.tsx

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

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

🧹 Nitpick comments (3)
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (1)

51-53: Consider normalizing restoreSize before humanizing for consistency

Here you call humanizeBinaryBytes(size).string directly on obj.status?.restoreSize. In volume-snapshot.tsx, size is first normalized with convertToBaseValue before humanization. Aligning both places (e.g., via a shared helper or the same pre-normalization step) would avoid subtle unit-handling differences and keep the UX consistent between snapshots and snapshot contents.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (2)

63-80: Make getDataViewRows resilient to missing rowData

Right now you destructure rowData: { hideSnapshotContentColumn } directly from each element. This assumes rowData is always present, which is true given the current customRowData usage, but it makes the helper fragile to future reuse. A small tweak to handle an optional rowData (e.g., const hideSnapshotContentColumn = rowData?.hideSnapshotContentColumn;) would make this safer without changing behavior today.


227-275: Confirm status filter values stay aligned with volumeSnapshotStatus

The status filter options (Ready, Pending, Error) are hard-coded, and matchesAdditionalFilters checks volumeSnapshotStatus(resource) against these strings. This is fine as long as volumeSnapshotStatus continues to return the same labels, but it’s a silent coupling. Worth double‑checking they match today and considering a shared source of truth if more statuses are added later.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between b34dc56 and 8f69bf3.

📒 Files selected for processing (4)
  • frontend/packages/console-app/src/components/nodes/NodesPage.tsx (3 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (4 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (3 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • frontend/packages/console-app/src/components/nodes/NodesPage.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
🔇 Additional comments (4)
frontend/packages/console-app/src/components/nodes/NodesPage.tsx (1)

548-551: LGTM! Good use of memoization for stable filter reference.

The memoized initialFilters prevents unnecessary object recreation on every render, which could cause filter resets in ConsoleDataView. The empty dependency array is appropriate since this filter configuration is truly static.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (1)

45-103: ConsoleDataView row mapping looks consistent and robust

The new getDataViewRows implementation builds row cells from VolumeSnapshotContentKind cleanly, uses DASH fallbacks, and wires actions/name/status/links in a data-driven way that should play nicely with ConsoleDataView and column management. No correctness issues stand out here.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (1)

41-139: Data-view migration for VolumeSnapshotClass looks solid

The combination of getDataViewRows, useVolumeSnapshotClassColumns, and the ConsoleDataView wrapper preserves existing behavior (default-class badge, driver/deletionPolicy display, actions) while standardizing on the new data-view patterns. Row construction, column IDs, and DASH fallbacks are consistent; I don’t see functional or maintainability concerns here.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (1)

63-146: Snapshot row construction and conditional snapshotContent column look correct

getDataViewRows correctly derives name/namespace/status/size/source/content/class/timestamp and wires actions/context. The hideSnapshotContentColumn flag is applied consistently in both the column definitions and the per-row disabled field, so the snapshot content column should cleanly disappear when CAN_LIST_VSC is false without leaving empty cells.

@vojtechszocs vojtechszocs force-pushed the data-view-storage-tables branch from 8f69bf3 to 96cafe4 Compare November 20, 2025 19:54
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
frontend/public/components/persistent-volume-claim.tsx (2)

481-545: Forward canCreate and showTitle props to ListPage component

The review comment is accurate. PersistentVolumeClaimsPageProps (lines 590-594) defines canCreate? and showTitle? as optional properties, but the component destructures only namespace and spreads remaining props without explicitly handling these two. The component then hardcodes canCreate={true} and never forwards showTitle, breaking the type contract and preventing callers from controlling these behaviors.

The suggested fix is correct: extract both props with appropriate defaults and forward them to ListPage instead of hardcoding canCreate={true} and omitting showTitle.


489-508: Dispatch in render phase confirmed—infinite render loop risk is real and critical

Verification confirms the review comment is accurate. The code has:

  1. dispatch(setPVCMetrics(pvcMetrics)) directly in component body (line 507), not wrapped in any effect
  2. No useEffect anywhere in the component that might mitigate this
  3. pvcMetrics is rebuilt each render via the ternary + reduce (no memoization)
  4. dispatch is a fresh function from useDispatch() each render

This creates a render loop: pvcMetrics object → dispatch → store update → re-render → new pvcMetrics object → repeat.

The suggested fix is correct—use useMemo for pvcMetrics and useEffect for the dispatch call with proper dependency arrays.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (1)

335-369: Ensure checkPVCSnapshot always returns an array to the table

checkPVCSnapshot currently uses optional chaining:

const checkPVCSnapshot = (
  volumeSnapshots: VolumeSnapshotKind[],
  pvc: K8sResourceKind,
): VolumeSnapshotKind[] =>
  volumeSnapshots?.filter(/* ... */);

If volumeSnapshots is ever null/undefined, this expression returns undefined, but VolumeSnapshotTable expects data: VolumeSnapshotKind[]. To avoid passing undefined into the table, return an empty array as a fallback:

 const checkPVCSnapshot = (
   volumeSnapshots: VolumeSnapshotKind[],
   pvc: K8sResourceKind,
 ): VolumeSnapshotKind[] =>
-  volumeSnapshots?.filter(
+  volumeSnapshots?.filter(
     (snapshot) =>
       snapshot?.spec?.source?.persistentVolumeClaimName === getName(pvc) &&
       getNamespace(snapshot) === getNamespace(pvc),
-  );
+  ) ?? [];

This keeps the runtime type consistent with the VolumeSnapshotTable contract.

🧹 Nitpick comments (4)
frontend/public/components/persistent-volume-claim.tsx (2)

103-174: Avoid using hooks directly inside getDataViewRows utility

getDataViewRows calls useTranslation and useSelector while explicitly disabling react-hooks/rules-of-hooks. This is brittle: if ConsoleDataView ever calls this callback conditionally or in a non-render context, hook ordering can break, and static analysis can’t protect you.

Consider moving the hook usage into a dedicated hook that returns a memoized row-mapping function, e.g. usePVCDataViewRows(): GetDataViewRows<PersistentVolumeClaimKind>, and then pass that from PersistentVolumeClaimList to ConsoleDataView. That keeps hooks at the top level of a React hook/component and lets you re‑enable the eslint rule.


584-588: Align PersistentVolumeClaimListProps['data'] type with what GetDataViewRows expects

PersistentVolumeClaimListProps currently types data as PersistentVolumeClaimKind[], but getDataViewRows treats each element as an object with an obj property. To avoid type drift and ensure callers pass the correct row shape, it’s safer to derive the element type from GetDataViewRows:

-type PersistentVolumeClaimListProps = {
-  data: PersistentVolumeClaimKind[];
+type PersistentVolumeClaimListProps = {
+  data: Parameters<GetDataViewRows<PersistentVolumeClaimKind>>[0];
   loaded: boolean;
   loadError: unknown;
 };

This keeps the list’s public props in sync with the DataView row contract even if the underlying row type changes.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (1)

45-53: Consider normalizing restoreSize before humanizing

In getDataViewRows, sizeMetrics calls humanizeBinaryBytes(size) directly, whereas the VolumeSnapshot table converts quantities via convertToBaseValue first. If status.restoreSize is a quantity string, mirroring that pattern here (humanizeBinaryBytes(convertToBaseValue(size))) would keep units handling consistent and more robust.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (1)

34-39: Use computed property name for the default-class annotation key

In isDefaultSnapshotClass, the default annotations object uses a literal key defaultSnapshotClassAnnotation:

getAnnotations(volumeSnapshotClass, { defaultSnapshotClassAnnotation: 'false' })[defaultSnapshotClassAnnotation]

Using a computed key keeps the constant and the actual annotation key in sync and makes the fallback clearer:

-  getAnnotations(volumeSnapshotClass, { defaultSnapshotClassAnnotation: 'false' })[
-    defaultSnapshotClassAnnotation
-  ] === 'true';
+  getAnnotations(volumeSnapshotClass, { [defaultSnapshotClassAnnotation]: 'false' })[
+    defaultSnapshotClassAnnotation
+  ] === 'true';

This avoids any future drift if the annotation name changes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 8f69bf3 and 96cafe4.

📒 Files selected for processing (5)
  • frontend/packages/console-app/src/components/nodes/NodesPage.tsx (3 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (4 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (3 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (4 hunks)
  • frontend/public/components/persistent-volume-claim.tsx (12 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/packages/console-app/src/components/nodes/NodesPage.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
  • frontend/public/components/persistent-volume-claim.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
🔇 Additional comments (7)
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (3)

54-103: Row mapping to ConsoleDataView looks consistent

rowCells keys are aligned with tableColumnInfo and the columns IDs, and the fallback to DASH plus optional props handling makes the mapping resilient to missing fields. No functional issues spotted in the row construction.


105-176: Columns hook and ConsoleDataView integration are wired correctly

useVolumeSnapshotContentColumns defines stable, memoized columns with appropriate sort keys and sticky/nowrap props, and VolumeSnapshotContentTable passes data, loaded, loadError, columns, and getDataViewRows into ConsoleDataView inside a Suspense with LoadingBox fallback. This aligns with the new data-view patterns and looks good.


180-206: Page-level watch and table composition look good

VolumeSnapshotContentPage watches the correct GVK, treats the resource as non‑namespaced, passes loadError through to the table, and uses ListPageCreate with the shared kind reference. The title/showTitle/canCreate wiring is straightforward and appears correct.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (2)

41-139: ConsoleDataView migration for VolumeSnapshotClass looks solid

getDataViewRows correctly builds cells for name/driver/deletionPolicy/actions, including the “Default” marker and action menu context, and useVolumeSnapshotClassColumns defines matching columns with sticky/nowrap props. VolumeSnapshotClassTable then passes these into ConsoleDataView with loaded, loadError, and a LoadingBox fallback. Overall the new data-view implementation is coherent and free of obvious issues.


143-174: Page wiring and creation flow remain intact

VolumeSnapshotClassPage still watches the correct model, threads namespace and selector, and now uses the shared kind reference for ListPageCreate while passing loadError to the table. The behavior should match the old page while benefiting from the new table implementation.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (2)

63-146: Row mapping and conditional SnapshotContent cell disabling look correct

getDataViewRows builds cells for all columns, uses VolumeSnapshotRowData.hideSnapshotContentColumn to mark the SnapshotContent cell as disabled, and correctly falls back to DASH for missing values. The filter over columns and the use of referenceForModel / referenceFor for links and action context all look consistent with the intended behavior.


148-295: DataView columns, status filters, and flag-based column visibility are well-structured

useVolumeSnapshotColumns cleanly encapsulates column definitions and hides the SnapshotContent column when hideSnapshotContentColumn is true, while VolumeSnapshotTable wires in customRowData, a status checkbox filter, and matchesAdditionalFilters to feed ConsoleDataView. The use of initialFiltersDefault and memoized filter options keeps configuration centralized and avoids unnecessary re-renders. No blocking issues here.

@openshift-ci-robot
Copy link
Contributor

openshift-ci-robot commented Nov 20, 2025

@vojtechszocs: This pull request references CONSOLE-4723 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Depends on #15713

  • packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
  • public/components/persistent-volume-claim.tsx
  • public/components/persistent-volume.jsx
  • public/components/storage-class.tsx
  • public/components/volumes-table.tsx

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot
Copy link
Contributor

openshift-ci-robot commented Nov 20, 2025

@vojtechszocs: This pull request references CONSOLE-4723 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Depends on #15713

  • packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
  • public/components/persistent-volume-claim.tsx
  • public/components/persistent-volume.tsx
  • public/components/storage-class.tsx
  • public/components/volumes-table.tsx

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@vojtechszocs vojtechszocs force-pushed the data-view-storage-tables branch from 96cafe4 to ab0aeb5 Compare November 20, 2025 20:46
@openshift-ci-robot
Copy link
Contributor

openshift-ci-robot commented Nov 20, 2025

@vojtechszocs: This pull request references CONSOLE-4723 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Depends on #15713

  • packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
  • public/components/persistent-volume-claim.tsx
  • public/components/persistent-volume.tsx
  • public/components/storage-class.tsx
  • public/components/volumes-table.tsx

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
frontend/public/components/persistent-volume-claim.tsx (2)

236-247: Fix useFlag usage so the PV link can actually be shown

useFlag(FLAGS.CAN_LIST_PV) is treated as if it returned a flags map:

const flags = useFlag(FLAGS.CAN_LIST_PV);
const canListPV = flags[FLAGS.CAN_LIST_PV];

If useFlag returns a single boolean (as elsewhere in Console), canListPV will always be undefined, and the volumeName && canListPV && ... block will never render.

Refactor to use the boolean directly:

-const PVCDetails: React.FCC<PVCDetailsProps> = ({ obj: pvc }) => {
-  const flags = useFlag(FLAGS.CAN_LIST_PV);
-  const { t } = useTranslation();
-  ...
-  const canListPV = flags[FLAGS.CAN_LIST_PV];
+const PVCDetails: React.FCC<PVCDetailsProps> = ({ obj: pvc }) => {
+  const canListPV = useFlag(FLAGS.CAN_LIST_PV);
+  const { t } = useTranslation();
+  ...
   {volumeName && canListPV && (
     <DescriptionListGroup>
       <DescriptionListTerm>{t('public~PersistentVolumes')}</DescriptionListTerm>
       <DescriptionListDescription data-test-id="persistent-volume">
         <ResourceLink kind="PersistentVolume" name={volumeName} />
       </DescriptionListDescription>
     </DescriptionListGroup>
   )}

Also applies to: 385-391


482-509: Avoid dispatching setPVCMetrics directly in render; memoize + useEffect

PersistentVolumeClaimsPage currently computes metrics and dispatches on every render:

const [response, loadError, loading] = usePrometheusPoll(...);

const pvcMetrics =
  _.isEmpty(loadError) && !loading
    ? response?.data?.result?.reduce(/* ... */)
    : {};

dispatch(setPVCMetrics(pvcMetrics));

Dispatching during render is brittle and can lead to unnecessary renders or even render loops if reducers touch state consumed here.

Consider:

-  const pvcMetrics =
-    _.isEmpty(loadError) && !loading
-      ? response?.data?.result?.reduce((acc, item) => {
-          _.set(
-            acc,
-            ['usedCapacity', item?.metric?.namespace, item?.metric?.persistentvolumeclaim],
-            Number(item?.value?.[1]),
-          );
-          return acc;
-        }, {})
-      : {};
-
-  dispatch(setPVCMetrics(pvcMetrics));
+  const pvcMetrics = React.useMemo(
+    () =>
+      _.isEmpty(loadError) && !loading
+        ? response?.data?.result?.reduce((acc, item) => {
+            _.set(
+              acc,
+              ['usedCapacity', item?.metric?.namespace, item?.metric?.persistentvolumeclaim],
+              Number(item?.value?.[1]),
+            );
+            return acc;
+          }, {})
+        : {},
+    [response, loadError, loading],
+  );
+
+  React.useEffect(() => {
+    dispatch(setPVCMetrics(pvcMetrics));
+  }, [dispatch, pvcMetrics]);

This keeps metrics computation tied to Prometheus updates and ensures Redux is updated outside the render phase.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (1)

180-213: Type mismatch: VolumeSnapshotContentPageProps is missing showTitle

VolumeSnapshotContentPage destructures showTitle with a default, but VolumeSnapshotContentPageProps only declares canCreate?: boolean (plus PageComponentProps). This will not type-check because showTitle is not part of the props type.

Add showTitle?: boolean to VolumeSnapshotContentPageProps (or drop the prop from the component) to keep the type definition aligned with usage.

 type VolumeSnapshotContentPageProps = {
-  canCreate?: boolean;
-} & PageComponentProps;
+  canCreate?: boolean;
+  showTitle?: boolean;
+} & PageComponentProps;
🧹 Nitpick comments (4)
frontend/public/components/persistent-volume-claim.tsx (1)

510-533: Confirm initPath behavior when namespace is undefined

initPath currently falls back to the default namespace:

const initPath = `/k8s/ns/${namespace || 'default'}/persistentvolumeclaims/`;

If PersistentVolumeClaimsPage is ever used without an explicit namespace, this will route create links into the default namespace rather than an all-namespaces/cluster-scoped path (if that was the previous behavior).

If the intended behavior is “all namespaces” when namespace is unset, consider something like:

const initPath = namespace
  ? `/k8s/ns/${namespace}/persistentvolumeclaims/`
  : '/k8s/all-namespaces/persistentvolumeclaims/';

Please double-check this against existing PVC pages to avoid changing navigation semantics unexpectedly.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (1)

35-43: Row/column mapping is sound; consider aligning size formatting with VolumeSnapshot

The data-view rows correctly map all tableColumnInfo ids to cells, with sensible fallbacks (DASH) and appropriate use of ResourceLink, Status, Timestamp, and LazyActionMenu. For consistency with VolumeSnapshot sizing, you may want to confirm that status.restoreSize is already in base bytes; if not, consider going through convertToBaseValue before humanizeBinaryBytes to avoid any subtle formatting differences.

If restoreSize is not guaranteed to be base bytes, please double‑check current usage of humanizeBinaryBytes with similar fields elsewhere in the codebase to decide whether a convertToBaseValue step is needed here.

Also applies to: 45-103, 105-156

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (2)

63-146: Guard against future column/rowCells drift in getDataViewRows

The current implementation assumes every columns entry has a corresponding rowCells[id], and uses rowCells[id].disabled in the filter predicate. That’s fine today because both are derived from the same tableColumnInfo, but it’s brittle to future changes (e.g., adding a column but forgetting to extend rowCells would cause a runtime error).

You can make this more robust with optional chaining and a default:

-    return columns
-      .filter(({ id }) => !rowCells[id].disabled)
-      .map(({ id }) => {
-        const cell = rowCells[id]?.cell || DASH;
-        const props = rowCells[id]?.props || undefined;
+    return columns
+      .filter(({ id }) => !rowCells[id]?.disabled)
+      .map(({ id }) => {
+        const cell = rowCells[id]?.cell || DASH;
+        const props = rowCells[id]?.props || undefined;
         return {
           id,
           props,
           cell,
         };
       });

335-369: PVC page behavior preserved; consider making ns optional in the type

VolumeSnapshotPVCPage preserves the existing behavior of preferring the ns prop and falling back to params.ns, and reuses VolumeSnapshotTable so the new data‑view behavior is applied consistently.

Given that the component already handles a missing ns by reading from route params, you may want to reflect that in the type by making ns optional for accuracy:

-type VolumeSnapshotPVCPage = {
-  obj: PersistentVolumeClaimKind;
-  ns: string;
-};
+type VolumeSnapshotPVCPage = {
+  obj: PersistentVolumeClaimKind;
+  ns?: string;
+};

This isn’t required for runtime correctness but better documents the actual call pattern.

Also applies to: 382-385

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 96cafe4 and ab0aeb5.

📒 Files selected for processing (6)
  • frontend/packages/console-app/src/components/nodes/NodesPage.tsx (3 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (4 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (3 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (4 hunks)
  • frontend/public/components/persistent-volume-claim.tsx (12 hunks)
  • frontend/public/components/persistent-volume.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/packages/console-app/src/components/nodes/NodesPage.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
  • frontend/public/components/persistent-volume-claim.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • frontend/public/components/persistent-volume.tsx
🔇 Additional comments (4)
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (2)

30-84: Data-view row mapping and column definitions look consistent and safe

tableColumnInfo, getDataViewRows, and useVolumeSnapshotClassColumns use the same column ids and provide sane fallbacks (DASH) plus sticky name/actions columns. The LazyActionMenu context and default-class badge logic are wired correctly; no issues from a correctness or maintainability standpoint.

Also applies to: 86-119


121-140: ConsoleDataView integration and page wiring are correct

Wrapping ConsoleDataView in Suspense with LoadingBox is appropriate, and loadError is passed through via ...props. The page’s useK8sWatchResource call feeds data, loaded, and loadError into VolumeSnapshotClassTable, and ListPageCreate correctly uses the shared kind constant.

Also applies to: 143-177, 186-190

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (2)

148-215: Column configuration and snapshot-content visibility logic look good

Using rowData.hideSnapshotContentColumn to both (a) mark the column definition as disabled and (b) filter it out via .filter((c) => !c.disabled) cleanly ties column visibility to the FLAGS.CAN_LIST_VSC flag. Sticky name/actions columns and the sort keys align with the row data, so the column setup is coherent and maintainable.


217-295: Status filter integration with ConsoleDataView is correctly wired

The status checkbox filter is correctly defined (filterId="status" and matching VolumeSnapshotFilters['status']), initialFilters extends initialFiltersDefault with status: [], and matchesAdditionalFilters cleanly short‑circuits when a status filter is active. This is a straightforward and maintainable use of the ResourceFilters + additionalFilterNodes pattern.

Also applies to: 371-373

@vojtechszocs vojtechszocs force-pushed the data-view-storage-tables branch from ab0aeb5 to f312ffb Compare November 21, 2025 18:40
@openshift-ci-robot
Copy link
Contributor

openshift-ci-robot commented Nov 21, 2025

@vojtechszocs: This pull request references CONSOLE-4723 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

Depends on #15713

  • packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
  • public/components/persistent-volume-claim.tsx
  • public/components/persistent-volume.tsx
  • public/components/storage-class.tsx
  • public/components/volumes-table.tsx

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (1)

151-161: VolumeSnapshotClass is cluster‑scoped but watched as namespaced

VolumeSnapshotClass is a cluster‑scoped resource; configuring useK8sWatchResource with namespaced: true and a namespace can result in watching the wrong URL (or an empty list), especially compared to VolumeSnapshotContentPage, which omits namespaced for another cluster‑scoped type.

Consider updating the watcher to treat it as cluster‑scoped, e.g.:

 const [resources, loaded, loadError] = useK8sWatchResource<VolumeSnapshotClassKind[]>({
   groupVersionKind: {
     group: VolumeSnapshotClassModel.apiGroup,
     kind: VolumeSnapshotClassModel.kind,
     version: VolumeSnapshotClassModel.apiVersion,
   },
   isList: true,
-  namespaced: true,
-  namespace,
+  namespaced: false,
   selector,
 });

and ignoring the namespace prop for this page if it is not actually used anywhere else.

♻️ Duplicate comments (2)
frontend/public/components/persistent-volume.tsx (1)

55-113: Rules of Hooks violation remains unresolved.

The getDataViewRows function still calls useTranslation() (line 57) despite not being a React component or custom hook. This was flagged in a previous review with suggested fixes. Please address this critical issue before merging.

frontend/public/components/persistent-volume-claim.tsx (1)

104-175: Rules of Hooks violation remains unresolved.

The getDataViewRows function calls both useTranslation() (line 106) and useSelector() (line 107) despite not being a React component or custom hook. This was flagged in a previous review with a detailed refactoring suggestion. Please address this critical issue before merging.

🧹 Nitpick comments (3)
frontend/public/components/storage-class.tsx (1)

252-260: Improve type safety in type definitions.

Two type-related improvements:

  1. Line 259: obj: any should use a more specific type like StorageClassResourceKind for better type safety.
  2. Line 255: loadError is declared in StorageClassListProps but not used in the component at line 160. Either use it (e.g., for error handling in ConsoleDataView) or remove it from the type definition.

Apply this diff to improve type safety:

 export type StorageClassDetailsProps = {
-  obj: any;
+  obj: StorageClassResourceKind;
 };
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (2)

63-66: Make row/column mapping resilient to future column changes

getDataViewRows filters with rowCells[id].disabled:

return columns
  .filter(({ id }) => !rowCells[id].disabled)
  .map(({ id }) => {
    const cell = rowCells[id]?.cell || DASH;
    const props = rowCells[id]?.props || undefined;
    ...
  });

This assumes every columns entry has a corresponding rowCells[id]. If a new column is ever added and rowCells isn’t updated, this will throw at runtime before the optional chaining is reached.

A small defensive tweak avoids that brittleness:

-  .filter(({ id }) => !rowCells[id].disabled)
+  .filter(({ id }) => !rowCells[id]?.disabled)

You may also not need the disabled flag on rowCells at all, since useVolumeSnapshotColumns already filters disabled columns at the header level.

Also applies to: 82-96, 105-132, 134-146


148-215: Status filter wiring looks good; consider centralizing status values

The status checkbox options and matchesAdditionalFilters logic are consistent and should work as intended, assuming volumeSnapshotStatus() returns "Ready" | "Pending" | "Error" for the cases you care about.

To reduce the chance of divergence if statuses evolve, consider sharing constants (or a small enum/union) between volumeSnapshotStatus and volumeSnapshotStatusFilterOptions rather than hardcoding the strings in two places.

Also applies to: 221-226, 227-276, 279-293

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between ab0aeb5 and f312ffb.

📒 Files selected for processing (7)
  • frontend/packages/console-app/src/components/nodes/NodesPage.tsx (3 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (4 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (3 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (4 hunks)
  • frontend/public/components/persistent-volume-claim.tsx (12 hunks)
  • frontend/public/components/persistent-volume.tsx (3 hunks)
  • frontend/public/components/storage-class.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/packages/console-app/src/components/nodes/NodesPage.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • frontend/public/components/storage-class.tsx
  • frontend/public/components/persistent-volume-claim.tsx
  • frontend/public/components/persistent-volume.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
🔇 Additional comments (4)
frontend/public/components/storage-class.tsx (1)

211-230: Verify intention to omit filter toolbar.

Line 225 sets omitFilterToolbar={true}, which removes filtering capabilities from the storage class list. If this is part of the migration strategy, please confirm this is intentional, as it may affect user experience.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (1)

41-84: Data-view migration for VolumeSnapshotClass table looks consistent

Row construction, column IDs, and use of DASH fallback are coherent with the shared data‑view patterns. Sticky name/actions columns and memoized column definitions should keep the table behavior and UX consistent with other data‑view based lists.

Also applies to: 86-119, 121-139

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (1)

54-103: ConsoleDataView integration for VolumeSnapshotContent looks solid

The row mapping, column definitions, Suspense/LoadingBox wrapper, and use of DASH fallback and actions cell props are consistent with the new data‑view patterns and should preserve behavior while simplifying the table/rendering code.

Also applies to: 105-156, 158-177, 180-205

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (1)

335-338: PVC‑scoped reuse of VolumeSnapshotTable looks correct

checkPVCSnapshot correctly filters snapshots by PVC name and namespace, and VolumeSnapshotPVCPage reuses VolumeSnapshotTable with the filtered data while preserving loaded/loadError wiring. This keeps the PVC view aligned with the main snapshot list behavior.

Also applies to: 345-346, 362-366

Comment on lines +45 to 53
const getDataViewRows: GetDataViewRows<VolumeSnapshotContentKind> = (data, columns) => {
return data.map(({ obj }) => {
const name = obj.metadata?.name || '';
const creationTimestamp = obj.metadata?.creationTimestamp || '';
const snapshotName = obj.spec?.volumeSnapshotRef?.name || '';
const snapshotNamespace = obj.spec?.volumeSnapshotRef?.namespace || '';
const size = obj.status?.restoreSize;
const sizeMetrics = size ? humanizeBinaryBytes(size).string : DASH;

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix VolumeSnapshotContent size humanization to use base bytes

obj.status?.restoreSize is a quantity (e.g., 10Gi), but it’s passed directly into humanizeBinaryBytes. In volume-snapshot.tsx you correctly call convertToBaseValue first; without that, this can produce incorrect or NaN values.

Align this code with the snapshot list:

-import { humanizeBinaryBytes } from '@console/internal/components/utils/units';
+import { convertToBaseValue, humanizeBinaryBytes } from '@console/internal/components/utils/units';
...
-    const size = obj.status?.restoreSize;
-    const sizeMetrics = size ? humanizeBinaryBytes(size).string : DASH;
+    const size = obj.status?.restoreSize;
+    const sizeBase = convertToBaseValue(size);
+    const sizeMetrics = size ? humanizeBinaryBytes(sizeBase).string : DASH;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const getDataViewRows: GetDataViewRows<VolumeSnapshotContentKind> = (data, columns) => {
return data.map(({ obj }) => {
const name = obj.metadata?.name || '';
const creationTimestamp = obj.metadata?.creationTimestamp || '';
const snapshotName = obj.spec?.volumeSnapshotRef?.name || '';
const snapshotNamespace = obj.spec?.volumeSnapshotRef?.namespace || '';
const size = obj.status?.restoreSize;
const sizeMetrics = size ? humanizeBinaryBytes(size).string : DASH;
const getDataViewRows: GetDataViewRows<VolumeSnapshotContentKind> = (data, columns) => {
return data.map(({ obj }) => {
const name = obj.metadata?.name || '';
const creationTimestamp = obj.metadata?.creationTimestamp || '';
const snapshotName = obj.spec?.volumeSnapshotRef?.name || '';
const snapshotNamespace = obj.spec?.volumeSnapshotRef?.namespace || '';
const size = obj.status?.restoreSize;
const sizeBase = convertToBaseValue(size);
const sizeMetrics = size ? humanizeBinaryBytes(sizeBase).string : DASH;
🤖 Prompt for AI Agents
In
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
around lines 45 to 53, the code passes obj.status?.restoreSize (a k8s Quantity
like "10Gi") directly to humanizeBinaryBytes which yields incorrect/NaN results;
change this to first convert the Quantity to base bytes using
convertToBaseValue(obj.status?.restoreSize) and then pass that numeric base
value to humanizeBinaryBytes, and add the necessary import for
convertToBaseValue if not already present.

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Nov 22, 2025
@openshift-ci-robot
Copy link
Contributor

openshift-ci-robot commented Nov 25, 2025

@vojtechszocs: This pull request references CONSOLE-4723 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.21.0" version, but no target version was set.

In response to this:

  • packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
  • packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
  • public/components/persistent-volume-claim.tsx
  • public/components/persistent-volume.tsx
  • public/components/storage-class.tsx

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@vojtechszocs vojtechszocs force-pushed the data-view-storage-tables branch from f312ffb to d9d1b09 Compare November 25, 2025 17:50
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Nov 25, 2025
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: 4

♻️ Duplicate comments (3)
frontend/public/components/storage-class.tsx (1)

68-123: Hooks violation in getDataViewRows remains unaddressed.

The useTranslation() hook is called inside getDataViewRows, which violates React's Rules of Hooks. This was flagged in a previous review. The eslint-disable comment suppresses the linter but doesn't fix the underlying issue—hooks must be called at the component level.

Additionally, the type mismatch persists: StorageClassListProps.data is typed as StorageClassResourceKind[] (line 253), but getDataViewRows destructures { obj } from each item, expecting RowProps<StorageClassResourceKind>[].

frontend/public/components/persistent-volume-claim.tsx (1)

105-109: Hooks violation in getDataViewRows remains unaddressed.

Calling useTranslation() and useSelector() inside getDataViewRows violates React's Rules of Hooks. This was flagged in a previous review. Lift these hooks to PersistentVolumeClaimList and pass the values to a memoized callback.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (1)

51-52: Fix: humanizeBinaryBytes receives a k8s Quantity string instead of base bytes.

obj.status?.restoreSize is a Kubernetes quantity string (e.g., "10Gi"), but humanizeBinaryBytes expects a numeric base value. This will produce incorrect or NaN results. In volume-snapshot.tsx, you correctly use convertToBaseValue first.

+import { convertToBaseValue, humanizeBinaryBytes } from '@console/internal/components/utils/units';
-import { humanizeBinaryBytes } from '@console/internal/components/utils/units';
 ...
     const size = obj.status?.restoreSize;
-    const sizeMetrics = size ? humanizeBinaryBytes(size).string : DASH;
+    const sizeBase = convertToBaseValue(size);
+    const sizeMetrics = size ? humanizeBinaryBytes(sizeBase).string : DASH;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between f312ffb and d9d1b09.

📒 Files selected for processing (7)
  • frontend/packages/console-app/src/components/nodes/NodesPage.tsx (1 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (4 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (3 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (4 hunks)
  • frontend/public/components/persistent-volume-claim.tsx (12 hunks)
  • frontend/public/components/persistent-volume.tsx (3 hunks)
  • frontend/public/components/storage-class.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/packages/console-app/src/components/nodes/NodesPage.tsx
  • frontend/public/components/persistent-volume.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • frontend/public/components/storage-class.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • frontend/public/components/persistent-volume-claim.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
🧬 Code graph analysis (1)
frontend/public/components/persistent-volume-claim.tsx (9)
frontend/public/models/index.ts (1)
  • PersistentVolumeClaimModel (664-677)
frontend/public/redux.ts (1)
  • RootState (19-27)
frontend/public/components/utils/link.tsx (1)
  • getNamespace (38-57)
frontend/public/components/events.jsx (3)
  • obj (126-126)
  • props (125-125)
  • loading (387-387)
frontend/public/module/k8s/k8s.ts (1)
  • referenceFor (50-65)
frontend/packages/console-app/src/components/data-view/ConsoleDataView.tsx (5)
  • getNameCellProps (250-255)
  • actionsCellProps (257-261)
  • cellIsStickyProps (240-243)
  • initialFiltersDefault (29-29)
  • ConsoleDataView (83-238)
frontend/__mocks__/i18next.ts (1)
  • t (8-14)
frontend/public/components/factory/table.tsx (1)
  • TableColumn (668-675)
frontend/public/components/graphs/helpers.ts (1)
  • PrometheusEndpoint (9-9)
🔇 Additional comments (8)
frontend/public/components/storage-class.tsx (1)

160-176: LGTM with caveat on getDataViewRows.

The StorageClassList component correctly uses useStorageClassColumns hook at the component level. However, once the hooks violation in getDataViewRows is fixed, you'll need to pass t from this component to the row mapper function.

frontend/public/components/persistent-volume-claim.tsx (1)

420-495: LGTM - List component structure is correct.

The PersistentVolumeClaimList component properly uses hooks at the component level and sets up filtering correctly. The Suspense boundary with LoadingBox fallback is appropriate.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-content.tsx (2)

45-103: Good: No hooks violations in this getDataViewRows.

Unlike the other files, this getDataViewRows implementation does not call any React hooks, which is the correct pattern. This can serve as a reference for fixing the hooks violations in storage-class.tsx and persistent-volume-claim.tsx.


158-178: LGTM - Component structure follows the correct pattern.

The VolumeSnapshotContentTable component properly uses hooks at the component level, wraps content in Suspense with LoadingBox fallback, and passes props correctly to ConsoleDataView.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (2)

41-84: Good: No hooks violations in getDataViewRows.

This implementation correctly avoids calling hooks inside getDataViewRows, following best practices. The row mapping logic is clean and consistent with the data-view pattern.


121-141: LGTM - VolumeSnapshotClassTable follows the correct pattern.

Proper use of hooks at component level, Suspense boundary with fallback, and correct ConsoleDataView prop passing.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx (2)

63-146: Good: No hooks violations and proper size conversion.

This getDataViewRows implementation correctly:

  1. Avoids calling React hooks inside the function
  2. Uses convertToBaseValue(size) before passing to humanizeBinaryBytes

This serves as a good reference for other files in this PR.


217-295: LGTM - VolumeSnapshotTable is well-structured.

The component properly:

  • Uses hooks at the component level
  • Implements status filtering with memoized filter options
  • Uses customRowData pattern for conditional column visibility
  • Wraps content in Suspense with LoadingBox fallback

Comment on lines +134 to +144
return columns
.filter(({ id }) => !rowCells[id].disabled)
.map(({ id }) => {
const cell = rowCells[id]?.cell || DASH;
const props = rowCells[id]?.props || undefined;
return {
id,
props,
cell,
};
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential undefined access in filter logic.

Line 135 accesses rowCells[id].disabled directly without optional chaining, but line 137 uses rowCells[id]?.cell. If rowCells[id] is undefined for a given column id, line 135 will throw.

     return columns
-      .filter(({ id }) => !rowCells[id].disabled)
+      .filter(({ id }) => !rowCells[id]?.disabled)
       .map(({ id }) => {
         const cell = rowCells[id]?.cell || DASH;
         const props = rowCells[id]?.props || undefined;
🤖 Prompt for AI Agents
In
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot.tsx
around lines 134 to 144, the filter currently accesses rowCells[id].disabled
directly which can throw if rowCells[id] is undefined; change the filter to
safely check existence (e.g. use optional chaining: filter(({ id }) =>
!rowCells[id]?.disabled) or explicitly guard: filter(({ id }) => !!rowCells[id]
&& !rowCells[id].disabled)) and keep the subsequent mapping logic that uses
rowCells[id]?.cell / props so undefined cells are handled consistently.

Comment on lines +464 to +481
const matchesAdditionalFilters = React.useCallback(
(resource: PersistentVolumeClaimKind, filters: PersistentVolumeClaimFilters) => {
// Status filter
if (filters.status.length > 0) {
const status = resource.status.phase;
if (!filters.status.includes(status)) {
return false;
}
}

return true;
},
[],
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard against undefined status to prevent runtime error.

If resource.status is undefined, accessing resource.status.phase at line 468 will throw a TypeError.

   const matchesAdditionalFilters = React.useCallback(
     (resource: PersistentVolumeClaimKind, filters: PersistentVolumeClaimFilters) => {
       // Status filter
       if (filters.status.length > 0) {
-        const status = resource.status.phase;
+        const status = resource.status?.phase;
         if (!filters.status.includes(status)) {
           return false;
         }
       }

       return true;
     },
     [],
   );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const matchesAdditionalFilters = React.useCallback(
(resource: PersistentVolumeClaimKind, filters: PersistentVolumeClaimFilters) => {
// Status filter
if (filters.status.length > 0) {
const status = resource.status.phase;
if (!filters.status.includes(status)) {
return false;
}
}
return true;
},
[],
);
const matchesAdditionalFilters = React.useCallback(
(resource: PersistentVolumeClaimKind, filters: PersistentVolumeClaimFilters) => {
// Status filter
if (filters.status.length > 0) {
const status = resource.status?.phase;
if (!filters.status.includes(status)) {
return false;
}
}
return true;
},
[],
);
🤖 Prompt for AI Agents
In frontend/public/components/persistent-volume-claim.tsx around lines 464 to
477, the code directly reads resource.status.phase which can throw if
resource.status is undefined; update the status check to safely handle missing
status (e.g., const status = resource.status?.phase; or if (!resource.status ||
resource.status.phase === undefined) return false when filters.status is
non-empty) so that undefined status does not cause a TypeError and the filter
behaves correctly.

Comment on lines 521 to 527
: {};

dispatch(setPVCMetrics(pvcMetrics));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Unconditional dispatch on every render may cause performance issues.

dispatch(setPVCMetrics(pvcMetrics)) is called on every render cycle. This can trigger unnecessary re-renders and Redux state updates. Consider wrapping in useEffect with appropriate dependencies.

+  React.useEffect(() => {
+    dispatch(setPVCMetrics(pvcMetrics));
+  }, [dispatch, pvcMetrics]);

-  dispatch(setPVCMetrics(pvcMetrics));

Note: You may need to stabilize pvcMetrics with useMemo to prevent the effect from running excessively due to object reference changes.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
: {};
dispatch(setPVCMetrics(pvcMetrics));
: {};
React.useEffect(() => {
dispatch(setPVCMetrics(pvcMetrics));
}, [dispatch, pvcMetrics]);
🤖 Prompt for AI Agents
In frontend/public/components/persistent-volume-claim.tsx around lines 521 to
523, the code unconditionally dispatches setPVCMetrics(pvcMetrics) on every
render which can cause unnecessary Redux updates; wrap the dispatch call in a
useEffect that runs only when pvcMetrics actually changes (add appropriate
dependencies), and if pvcMetrics is an object/array stabilize it with useMemo
(or derive a stable primitive key) before putting it in the effect dependency
array so the effect only runs when meaningful metric values change.

Copy link
Member

@logonoff logonoff left a comment

Choose a reason for hiding this comment

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

/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Nov 28, 2025
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 (3)
frontend/public/components/persistent-volume-claim.tsx (2)

468-481: Guard against undefined status to prevent runtime error.

If resource.status is undefined, accessing resource.status.phase at line 472 will throw a TypeError. This issue was previously flagged but remains unaddressed.

Apply this diff to safely handle missing status:

   const matchesAdditionalFilters = React.useCallback(
     (resource: PersistentVolumeClaimKind, filters: PersistentVolumeClaimFilters) => {
       // Status filter
       if (filters.status.length > 0) {
-        const status = resource.status.phase;
+        const status = resource.status?.phase;
         if (!filters.status.includes(status)) {
           return false;
         }
       }

       return true;
     },
     [],
   );

527-527: Wrap dispatch in useEffect to prevent unnecessary re-renders.

dispatch(setPVCMetrics(pvcMetrics)) is called unconditionally on every render, which can trigger unnecessary Redux updates and re-renders throughout the application. This issue was previously flagged but remains unaddressed.

Apply this diff to dispatch only when metrics change:

+  React.useEffect(() => {
+    dispatch(setPVCMetrics(pvcMetrics));
+  }, [dispatch, pvcMetrics]);
+
-  dispatch(setPVCMetrics(pvcMetrics));

Note: Since pvcMetrics is a newly computed object on each render, you should stabilize it with useMemo to prevent the effect from running excessively:

   const pvcMetrics =
-    _.isEmpty(loadError) && !loading
-      ? response?.data?.result?.reduce((acc, item) => {
-          _.set(
-            acc,
-            ['usedCapacity', item?.metric?.namespace, item?.metric?.persistentvolumeclaim],
-            Number(item?.value?.[1]),
-          );
-          return acc;
-        }, {})
-      : {};
+    React.useMemo(
+      () =>
+        _.isEmpty(loadError) && !loading
+          ? response?.data?.result?.reduce((acc, item) => {
+              _.set(
+                acc,
+                ['usedCapacity', item?.metric?.namespace, item?.metric?.persistentvolumeclaim],
+                Number(item?.value?.[1]),
+              );
+              return acc;
+            }, {})
+          : {},
+      [response, loadError, loading],
+    );
frontend/public/components/storage-class.tsx (1)

114-116: Prefer ?? over || for cell/props fallbacks

Using || will treat valid falsy values (e.g., 0, empty string) as missing and replace them with DASH/undefined. ?? keeps legitimate falsy values while still defaulting for null/undefined.

-      const cell = rowCells[id]?.cell || DASH;
-      const props = rowCells[id]?.props || undefined;
+      const cell = rowCells[id]?.cell ?? DASH;
+      const props = rowCells[id]?.props ?? undefined;
🧹 Nitpick comments (2)
frontend/public/components/persistent-volume.tsx (1)

248-252: Consider deriving PersistentVolumeListProps from shared list/DataView props

Right now PersistentVolumeListProps is a bespoke { data; loaded; loadError } type while PersistentVolumeList forwards ...props into ConsoleDataView. This works, but it can drift from whatever prop shape ConsoleDataView/ListPage actually expect (e.g., if more props are added later).

To keep things aligned and future-proof, consider defining PersistentVolumeListProps as something like:

  • A reuse of the shared list component props type from ListPage, or
  • React.ComponentProps<typeof ConsoleDataView<PersistentVolumeKind>> (possibly Pick/Omit-ed as needed),

so that any additional props are correctly typed and forwarded without manual duplication.

Also applies to: 295-299

frontend/public/components/storage-class.tsx (1)

255-263: Consider whether these prop types should be exported or inlined

StorageClassListProps and StorageClassDetailsProps are only used to type components in this file. If there are no external consumers, you could inline these shapes into the React.FCC<...> declarations to reduce local type noise; if they are part of a public API, consider export type so downstream code can import them explicitly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 67768e2 and 3f438a0.

📒 Files selected for processing (9)
  • frontend/packages/console-app/locales/en/console-app.json (1 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (4 hunks)
  • frontend/packages/container-security/src/components/image-manifest-vuln.tsx (0 hunks)
  • frontend/public/components/custom-resource-definition.tsx (1 hunks)
  • frontend/public/components/masthead/masthead-toolbar.tsx (2 hunks)
  • frontend/public/components/persistent-volume-claim.tsx (12 hunks)
  • frontend/public/components/persistent-volume.tsx (3 hunks)
  • frontend/public/components/storage-class.tsx (4 hunks)
  • frontend/public/locales/en/public.json (2 hunks)
💤 Files with no reviewable changes (1)
  • frontend/packages/container-security/src/components/image-manifest-vuln.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/public/components/custom-resource-definition.tsx
  • frontend/packages/console-app/locales/en/console-app.json
  • frontend/public/locales/en/public.json
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • frontend/public/components/masthead/masthead-toolbar.tsx
  • frontend/public/components/storage-class.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • frontend/public/components/persistent-volume-claim.tsx
  • frontend/public/components/persistent-volume.tsx
🧬 Code graph analysis (2)
frontend/public/components/masthead/masthead-toolbar.tsx (1)
frontend/public/module/auth.js (1)
  • window (5-12)
frontend/public/components/storage-class.tsx (4)
frontend/public/module/k8s/types.ts (1)
  • StorageClassResourceKind (477-483)
frontend/public/components/utils/resource-link.tsx (1)
  • ResourceLink (71-127)
frontend/packages/console-app/src/components/data-view/ConsoleDataView.tsx (3)
  • getNameCellProps (250-255)
  • actionsCellProps (257-261)
  • ConsoleDataView (83-238)
frontend/public/components/factory/details.tsx (2)
  • DetailsPageProps (166-193)
  • DetailsPage (62-164)
🔇 Additional comments (5)
frontend/public/components/masthead/masthead-toolbar.tsx (1)

142-145: LGTM—good optimization.

Moving the plugin detection to module scope eliminates repeated array lookups on every getLaunchActions call. Since plugins are loaded at startup and the TODO indicates this is temporary code, the static check is appropriate.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (1)

1-196: LGTM! Clean migration to ConsoleDataView.

The migration is well-structured and follows best practices:

  • Proper memoization of columns (line 93) and row creator (line 132) for performance
  • Translation correctly implemented for all user-facing strings, including the "Default" label (line 57) that was flagged in previous reviews
  • Clean separation between column definitions, row creation logic, and rendering
  • Type safety maintained with updated props (data, loaded, loadError replacing unfilteredData)

The data-view pattern is consistently applied across the component.

frontend/public/components/persistent-volume.tsx (2)

42-113: ConsoleDataView integration and hook refactor look solid

getDataViewRowsCreator is now a pure factory taking t: TFunction, and useTranslation is only used inside PersistentVolumeList/usePersistentVolumeColumns, so the previous Rules-of-Hooks concern is resolved. Row construction lines up with tableColumnInfo IDs, and the memoized getDataViewRows plus ConsoleDataView usage (including hideColumnManagement and LoadingBox fallback) look correct and maintainable.

Also applies to: 115-166, 248-270


168-246: Details and page wiring are coherent and consistent

PVDetails cleanly presents PV metadata using existing shared components, and both the list and details pages correctly wire in PersistentVolumeList / PVDetails via ListPage and DetailsPage with the expected kind/pages configuration. No major functional or maintainability issues stand out here.

Also applies to: 272-285, 287-293

frontend/public/components/storage-class.tsx (1)

161-179: Data-view + i18n wiring in StorageClassList looks correct

Deriving getDataViewRows via getDataViewRowsCreator(t) at component scope (with useMemo) cleanly avoids hook-rule violations and keeps the row mapper stable, only changing when the translation function changes. No further issues here.

@vojtechszocs
Copy link
Contributor Author

/hold cancel

@openshift-ci openshift-ci bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Nov 28, 2025
@vojtechszocs vojtechszocs force-pushed the data-view-storage-tables branch from 3f438a0 to e67fcad Compare November 28, 2025 19:49
@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Nov 28, 2025
@logonoff
Copy link
Member

/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Nov 28, 2025
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

♻️ Duplicate comments (2)
frontend/public/components/persistent-volume-claim.tsx (2)

468-481: Guard against undefined status to prevent runtime error.

If resource.status is undefined, accessing resource.status.phase at line 472 will throw a TypeError.

   const matchesAdditionalFilters = React.useCallback(
     (resource: PersistentVolumeClaimKind, filters: PersistentVolumeClaimFilters) => {
       // Status filter
       if (filters.status.length > 0) {
-        const status = resource.status.phase;
+        const status = resource.status?.phase;
         if (!filters.status.includes(status)) {
           return false;
         }
       }

       return true;
     },
     [],
   );

527-527: Unconditional dispatch on every render causes performance issues.

dispatch(setPVCMetrics(pvcMetrics)) is called on every render cycle. This triggers unnecessary re-renders and Redux state updates.

+  React.useEffect(() => {
+    dispatch(setPVCMetrics(pvcMetrics));
+  }, [dispatch, pvcMetrics]);
+
-  dispatch(setPVCMetrics(pvcMetrics));

Note: You may need to stabilize pvcMetrics with useMemo to prevent the effect from running excessively due to object reference changes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 3f438a0 and e67fcad.

📒 Files selected for processing (9)
  • frontend/packages/console-app/locales/en/console-app.json (2 hunks)
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (4 hunks)
  • frontend/packages/container-security/src/components/image-manifest-vuln.tsx (0 hunks)
  • frontend/public/components/custom-resource-definition.tsx (1 hunks)
  • frontend/public/components/masthead/masthead-toolbar.tsx (2 hunks)
  • frontend/public/components/persistent-volume-claim.tsx (12 hunks)
  • frontend/public/components/persistent-volume.tsx (3 hunks)
  • frontend/public/components/storage-class.tsx (4 hunks)
  • frontend/public/locales/en/public.json (2 hunks)
💤 Files with no reviewable changes (1)
  • frontend/packages/container-security/src/components/image-manifest-vuln.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/packages/console-app/locales/en/console-app.json
  • frontend/public/components/masthead/masthead-toolbar.tsx
  • frontend/public/components/custom-resource-definition.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • frontend/public/components/persistent-volume.tsx
  • frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
  • frontend/public/components/persistent-volume-claim.tsx
  • frontend/public/locales/en/public.json
  • frontend/public/components/storage-class.tsx
🧬 Code graph analysis (1)
frontend/public/components/persistent-volume-claim.tsx (2)
frontend/packages/console-app/src/components/data-view/types.ts (2)
  • GetDataViewRows (26-29)
  • ResourceFilters (5-8)
frontend/packages/console-app/src/components/data-view/ConsoleDataView.tsx (5)
  • getNameCellProps (250-255)
  • actionsCellProps (257-261)
  • cellIsStickyProps (240-243)
  • initialFiltersDefault (29-29)
  • ConsoleDataView (83-238)
🔇 Additional comments (13)
frontend/public/locales/en/public.json (2)

1109-1110: Storage and PersistentVolume translation keys correctly added.

The new translation keys for storage-related UI components (PersistentVolume, Capacity, StorageClass, Bound, Lost, Claim) are correctly placed in the Recommendations/Notifications section and follow the existing naming and formatting conventions. All keys use straightforward one-to-one English translations appropriate for the base locale file.

Also applies to: 1112-1112, 1124-1125, 1128-1128


1357-1357: Manual verification required due to infrastructure limitations.

The automated verification cannot be completed due to persistent repository access issues. The concerns raised in the review comment require direct inspection of:

  1. References to "Default for VirtualMachines" in migrated storage-class components and volume-snapshot modules
  2. Migration context to confirm this key complements rather than incorrectly replaces existing "Default" entries
  3. Storage provisioner integration to ensure proper usage in ConsoleDataView migration

These verification steps must be performed locally by examining the component files directly.

frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx (3)

42-88: Data-view row construction is side‑effect free and i18n‑safe.

getDataViewRowsCreator cleanly maps VolumeSnapshotClassKind objects to row cells, uses t passed from the component (no hooks in the helper), provides a consistent actions context, and falls back to DASH for missing values. No issues spotted in the row mapping logic.


90-123: Column definitions align with ConsoleDataView usage.

useVolumeSnapshotClassColumns correctly uses useTranslation, stable ids from tableColumnInfo, appropriate sort fields, and sticky/nowrap cell props. This should integrate cleanly with ConsoleDataView’s column handling.


125-145: Table/page wiring to ConsoleDataView looks consistent.

VolumeSnapshotClassTable and VolumeSnapshotClassPage correctly:

  • Obtain t via useTranslation in components (respecting hook rules).
  • Memoize getDataViewRows via getDataViewRowsCreator(t).
  • Wrap ConsoleDataView in Suspense with LoadingBox fallback.
  • Pass data, loaded, loadError, and static label, plus kind into ListPageCreate.

This matches the data‑view migration patterns used elsewhere; no structural issues seen.

Also applies to: 149-180

frontend/public/components/persistent-volume.tsx (5)

39-50: Top‑level PV wiring and status helper look good.

Using PersistentVolumeModel.kind/referenceForModel for kind and action context, plus PVStatus delegating to <Status>, is consistent with existing patterns and keeps status logic centralized.

Also applies to: 52-54


56-113: getDataViewRowsCreator correctly replaces the old hook‑using helper.

The new getDataViewRowsCreator(t):

  • Avoids calling useTranslation inside a non‑hook helper.
  • Covers all defined columns (name, status, claim, capacity, labels, created, actions).
  • Uses DASH fallbacks and stable LabelList/Timestamp/LazyActionMenu usages.
  • Builds claim cell with a translated “No claim” message.

This resolves the earlier Rules of Hooks issue without introducing new behavior problems.


115-166: Column hook is idiomatic and matches data‑view expectations.

usePersistentVolumeColumns uses useTranslation inside a hook, memoizes the column array, and wires sort keys/ids and sticky/nowrap props appropriately. The action column uses an empty title with a dedicated id and sticky props, which matches other console tables.


168-246: PVDetails reuses existing patterns and handles optional fields cleanly.

The details view:

  • Uses PaneBody, SectionHeading, ResourceSummary, and PatternFly DescriptionList components consistently.
  • Safely handles optional fields (capacity, access modes, PVC, NFS export) and provides sensible fallbacks (e.g., Filesystem / None translations).
  • Reuses PVStatus and ResourceLink for related resources.

No functional or structural issues identified.


248-299: List/page/details integration with ConsoleDataView looks solid.

  • PersistentVolumeList obtains t via useTranslation, memoizes getDataViewRowsCreator(t), and passes data, loaded, columns, and getDataViewRows into ConsoleDataView wrapped in Suspense with LoadingBox.
  • PersistentVolumesPage uses ListPage with kind={kind}, ListComponent={PersistentVolumeList}, canCreate, and omitFilterToolbar, matching other list implementations.
  • PersistentVolumesDetailsPage uses DetailsPage with the reference kind and navFactory.details(PVDetails).

The new PersistentVolumeListProps surface is minimal and appropriate for this wiring.

frontend/public/components/persistent-volume-claim.tsx (1)

105-174: LGTM! Hooks issue properly resolved.

The factory pattern (getDataViewRowsCreator) correctly addresses the previous review comment about calling hooks inside getDataViewRows. By accepting t and pvcMetrics as parameters and returning the row-building function, this allows the parent component to call hooks and pass the results in, maintaining React's rules of hooks.

frontend/public/components/storage-class.tsx (2)

3-43: Centralizing kind from StorageClassModel improves maintainability

Deriving kind via const { kind } = StorageClassModel; and reusing it across the module removes magic strings and reduces risk of resource-kind drift between list, links, and details. Import set looks coherent with the data‑view migration and existing console patterns; no issues here.


49-73: Row mapping factory cleanly integrates i18n and actions into ConsoleDataView

Using tableColumnInfo plus getDataViewRowsCreator(t) is a solid pattern: you avoid calling hooks inside the row‑mapper, keep the translator function injectable, and build a per‑row rowCells map keyed by column id before projecting over columns. The kubevirt plugin gate and TODO around isKubevirtPluginActive are also a pragmatic way to keep existing annotations‑based hints without hard‑wiring plugin logic into the table forever. I don’t see functional issues in this mapping logic; the LazyActionMenu context and defaulting to DASH for missing cells are consistent with other resources.

Please just re‑confirm that GetDataViewRows<StorageClassResourceKind> in the shared data‑view types still expects data entries with an obj field, so this { obj } destructuring and the referenceFor(obj) call remain aligned with the shared contract.

Also applies to: 74-124

Comment on lines +35 to 40
const defaultSnapshotClassAnnotation = 'snapshot.storage.kubernetes.io/is-default-class';

const defaultSnapshotClassAnnotation: string = 'snapshot.storage.kubernetes.io/is-default-class';
export const isDefaultSnapshotClass = (volumeSnapshotClass: VolumeSnapshotClassKind) =>
getAnnotations(volumeSnapshotClass, { defaultSnapshotClassAnnotation: 'false' })[
defaultSnapshotClassAnnotation
] === 'true';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix annotation key usage in isDefaultSnapshotClass.

defaultSnapshotClassAnnotation is a string constant, but the fallback passed to getAnnotations uses a literal property name:

getAnnotations(volumeSnapshotClass, { defaultSnapshotClassAnnotation: 'false' })[
  defaultSnapshotClassAnnotation
]

This creates a key "defaultSnapshotClassAnnotation", not the annotation key value, so the helper will almost always return false and the “Default” label will never show.

Use a computed property so the key matches the constant’s value:

-export const isDefaultSnapshotClass = (volumeSnapshotClass: VolumeSnapshotClassKind) =>
-  getAnnotations(volumeSnapshotClass, { defaultSnapshotClassAnnotation: 'false' })[
-    defaultSnapshotClassAnnotation
-  ] === 'true';
+export const isDefaultSnapshotClass = (volumeSnapshotClass: VolumeSnapshotClassKind) =>
+  getAnnotations(volumeSnapshotClass, { [defaultSnapshotClassAnnotation]: 'false' })[
+    defaultSnapshotClassAnnotation
+  ] === 'true';
🤖 Prompt for AI Agents
In
frontend/packages/console-app/src/components/volume-snapshot/volume-snapshot-class.tsx
around lines 35 to 40, the fallback object passed to getAnnotations uses the
literal property name "defaultSnapshotClassAnnotation" instead of the value of
the constant defaultSnapshotClassAnnotation, causing the annotation lookup to
always miss; change the fallback to use a computed property keyed by the
constant (e.g. {[defaultSnapshotClassAnnotation]: 'false'}) so getAnnotations
returns the correct annotation value and the function can correctly detect and
return true when the annotation equals 'true'.

@vojtechszocs
Copy link
Contributor Author

/retest

@vojtechszocs
Copy link
Contributor Author

We will need to test basic functionality of the impacted tables

  • StorageClass
  • PersistentVolume
  • PersistentVolumeClaim
  • VolumeSnapshot
  • VolumeSnapshotClass
  • VolumeSnapshotContent

/assign @yapei

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 1, 2025
@yapei
Copy link
Contributor

yapei commented Dec 2, 2025

@yanpzhan please help verify,thanks!

@vojtechszocs vojtechszocs force-pushed the data-view-storage-tables branch from e67fcad to 4acf7c1 Compare December 2, 2025 10:17
@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Dec 2, 2025
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 2, 2025
@vojtechszocs
Copy link
Contributor Author

vojtechszocs commented Dec 2, 2025

@yanpzhan I've rebased the PR, it builds and works on local dev env. without any issues.

Can you please do some basic testing of the impacted resource list pages? (No dynamic plugins needed.)

@yanpzhan
Copy link
Contributor

yanpzhan commented Dec 2, 2025

Regression test on cluster launched against the pr passed.
Covered pages including: StorageClass/PersistentVolume/PersistentVolumeClaim/VolumeSnapshot/VolumeSnapshotClass/VolumeSnapshotContent
/verified by yanpzhan

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Dec 2, 2025
@openshift-ci-robot
Copy link
Contributor

@yanpzhan: This PR has been marked as verified by yanpzhan.

In response to this:

Regression test on cluster launched against the pr passed.
Covered pages including: StorageClass/PersistentVolume/PersistentVolumeClaim/VolumeSnapshot/VolumeSnapshotClass/VolumeSnapshotContent
/verified by yanpzhan

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@logonoff
Copy link
Member

logonoff commented Dec 2, 2025

/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Dec 2, 2025
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Dec 2, 2025

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: logonoff, vojtechszocs

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci-robot
Copy link
Contributor

/retest-required

Remaining retests: 0 against base HEAD 598afdb and 2 for PR HEAD 4acf7c1 in total

@logonoff
Copy link
Member

logonoff commented Dec 2, 2025

/retest

@openshift-ci-robot
Copy link
Contributor

/retest-required

Remaining retests: 0 against base HEAD 7d838b5 and 1 for PR HEAD 4acf7c1 in total

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Dec 3, 2025

@vojtechszocs: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-gcp-console 4acf7c1 link true /test e2e-gcp-console

Full PR test history. Your PR dashboard.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. component/core Related to console core functionality component/helm Related to helm-plugin component/monitoring Related to monitoring docs-approved Signifies that Docs has signed off on this PR jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. kind/i18n Indicates issue or PR relates to internationalization or has content that needs to be translated lgtm Indicates that a PR is ready to be merged. px-approved Signifies that Product Support has signed off on this PR verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants