Skip to content

OSAC-3599: [UI] Storage Backends list page - #130

Merged
openshift-merge-bot[bot] merged 12 commits into
osac-project:mainfrom
ElayAharoni:OSAC-3599-storage-backends-list-page
Aug 11, 2026
Merged

OSAC-3599: [UI] Storage Backends list page#130
openshift-merge-bot[bot] merged 12 commits into
osac-project:mainfrom
ElayAharoni:OSAC-3599-storage-backends-list-page

Conversation

@ElayAharoni

@ElayAharoni ElayAharoni commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

OSAC-3599: [UI] Storage Backends list page

Jira: https://redhat.atlassian.net/browse/OSAC-3599
Story type: [UI]

Summary

Adds the Backends list page under Storage admin management: a table of registered storage backends (name, provider, endpoint, state), a "Create backend" action, and a per-row Edit/Delete kebab. Replaces the placeholder previously left in StorageManagementPage's Backends tab.

Changes

  • StorageBackendStateLabel: maps StorageBackendState (READY/UNSPECIFIED) to the shared ResourceStatusLabel
  • StorageBackendsTable: plain PatternFly table with NAME/PROVIDER/ENDPOINT/STATE columns and a row-actions cell
  • StorageBackendActionsMenu: row kebab — Edit navigates to the existing (placeholder) edit route, Delete opens a confirm modal
  • StorageBackendDeleteConfirmModal: surfaces the server's delete error (e.g. FAILED_PRECONDITION when a backend is still referenced by an active StorageTier) verbatim, inline, without removing the row; hides the "Create backend" action when the list fails to load
  • StorageBackendsListPage: wires usePrivateStorageBackends() to the table via ListPageBody for loading/error/empty states
  • Wired into StorageManagementPage's Backends tab, replacing the StoragePlaceholder
  • Fixed createMockConnectTransport's StorageBackends.delete test stub, which was previously a stateless no-op — it now removes the deleted item from a defensively-cloned copy of the fixtures array, so tests can verify real query-invalidation-driven row removal without corrupting shared fixtures across test runs

Testing

  • Unit tests: StorageBackendStateLabel (3 tests: READY/UNSPECIFIED/undefined mappings), StorageBackendDeleteConfirmModal (3 tests: success, FAILED_PRECONDITION verbatim + no removal, cancel)
  • Integration tests: StorageBackendsListPage (8 tests: columns, rows, state labels, empty state, create/edit navigation, delete-dialog open, delete-success row removal via real invalidation). StorageBackendActionsMenu/StorageBackendsTable have no isolated tests, matching this codebase's existing convention (ClustersTable, IdentityProviderActionsMenu have none) — covered transitively through the list page's tests.
  • Coverage: No coverage tool is configured in this repo; qualitatively, every behavioral path named in the story's Testing Approach is exercised through public-interface tests. Full suite: 499/500 passing (the one failure is a pre-existing, unrelated ClusterCreatePage.test.tsx parallel-worker timeout flake, untouched by this branch).

Acceptance Criteria

  • The Backends tab renders a table with columns NAME, PROVIDER, ENDPOINT, STATE, sourced from usePrivateStorageBackends().
  • STATE renders via a StorageBackendStateLabel component wrapping the shared ResourceStatusLabel, mapping READY to green "Ready" and UNSPECIFIED to grey "Unspecified."
  • A "Create backend" action routes to /admin/storage/backends/create.
  • Each row has a row-actions kebab with Edit (routes to /admin/storage/backends/:id/edit) and Delete.
  • Deleting a backend that is referenced by an active StorageTier shows the server's FAILED_PRECONDITION error verbatim, and the row remains in the table (no optimistic removal).
  • Loading and empty states are handled via the existing ListPage/ListPageBody shell components, matching the convention every other list page in this codebase follows.
image

Summary by CodeRabbit

  • New Features

    • Added a Backends management view with loading, error, and empty states.
    • Display storage backend names, statuses, providers, and endpoints in a table.
    • Added options to create, edit, and delete storage backends.
    • Added deletion confirmation, progress feedback, and inline error messages.
    • Added clear status labels and translated backend-related text.
  • Tests

    • Expanded coverage for backend listing, navigation, status labels, deletion flows, and empty states.

@openshift-ci-robot

openshift-ci-robot commented Aug 9, 2026

Copy link
Copy Markdown

@ElayAharoni: This pull request references OSAC-3599 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 "5.0.0" version, but no target version was set.

Details

In response to this:

OSAC-3599: [UI] Storage Backends list page

Jira: https://redhat.atlassian.net/browse/OSAC-3599
Story type: [UI]

Summary

Adds the Backends list page under Storage admin management: a table of registered storage backends (name, provider, endpoint, state), a "Create backend" action, and a per-row Edit/Delete kebab. Replaces the placeholder previously left in StorageManagementPage's Backends tab.

Changes

  • StorageBackendStateLabel: maps StorageBackendState (READY/UNSPECIFIED) to the shared ResourceStatusLabel
  • StorageBackendsTable: plain PatternFly table with NAME/PROVIDER/ENDPOINT/STATE columns and a row-actions cell
  • StorageBackendActionsMenu: row kebab — Edit navigates to the existing (placeholder) edit route, Delete opens a confirm modal
  • StorageBackendDeleteConfirmModal: surfaces the server's delete error (e.g. FAILED_PRECONDITION when a backend is still referenced by an active StorageTier) verbatim, inline, without removing the row; hides the "Create backend" action when the list fails to load
  • StorageBackendsListPage: wires usePrivateStorageBackends() to the table via ListPageBody for loading/error/empty states
  • Wired into StorageManagementPage's Backends tab, replacing the StoragePlaceholder
  • Fixed createMockConnectTransport's StorageBackends.delete test stub, which was previously a stateless no-op — it now removes the deleted item from a defensively-cloned copy of the fixtures array, so tests can verify real query-invalidation-driven row removal without corrupting shared fixtures across test runs

Testing

  • Unit tests: StorageBackendStateLabel (3 tests: READY/UNSPECIFIED/undefined mappings), StorageBackendDeleteConfirmModal (3 tests: success, FAILED_PRECONDITION verbatim + no removal, cancel)
  • Integration tests: StorageBackendsListPage (8 tests: columns, rows, state labels, empty state, create/edit navigation, delete-dialog open, delete-success row removal via real invalidation). StorageBackendActionsMenu/StorageBackendsTable have no isolated tests, matching this codebase's existing convention (ClustersTable, IdentityProviderActionsMenu have none) — covered transitively through the list page's tests.
  • Coverage: No coverage tool is configured in this repo; qualitatively, every behavioral path named in the story's Testing Approach is exercised through public-interface tests. Full suite: 499/500 passing (the one failure is a pre-existing, unrelated ClusterCreatePage.test.tsx parallel-worker timeout flake, untouched by this branch).

Acceptance Criteria

  • The Backends tab renders a table with columns NAME, PROVIDER, ENDPOINT, STATE, sourced from usePrivateStorageBackends().
  • STATE renders via a StorageBackendStateLabel component wrapping the shared ResourceStatusLabel, mapping READY to green "Ready" and UNSPECIFIED to grey "Unspecified."
  • A "Create backend" action routes to /admin/storage/backends/create.
  • Each row has a row-actions kebab with Edit (routes to /admin/storage/backends/:id/edit) and Delete.
  • Deleting a backend that is referenced by an active StorageTier shows the server's FAILED_PRECONDITION error verbatim, and the row remains in the table (no optimistic removal).
  • Loading and empty states are handled via the existing ListPage/ListPageBody shell components, matching the convention every other list page in this codebase follows.

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

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The PR replaces the Backends placeholder with a functional storage-backend list. It adds status display, create and edit navigation, delete confirmation, translations, tests, and mutable mock transport fixtures.

Changes

Storage backend management

Layer / File(s) Summary
Backend table and actions
libs/ui-components/src/components/Storage/*, libs/i18n/locales/en/translation.json
Adds the backend table, status labels, edit and delete actions, delete confirmation modal, translations, and component tests.
Backend list page and deletion state
libs/ui-components/src/pages/admin/StorageBackendsListPage.*, libs/ui-components/src/test-utils/createMockConnectTransport.ts
Adds backend loading, empty and error states, create navigation, deletion handling, page tests, and mutable mock deletion fixtures.
Backends tab integration and route tests
libs/ui-components/src/pages/admin/StorageManagementPage.*, apps/app-frontend/src/shell/StorageRoutes.test.tsx
Replaces the Backends placeholder and updates asynchronous content and redirect assertions.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Admin
  participant StorageManagementPage
  participant StorageBackendsListPage
  participant StorageBackendsTable
  participant StorageBackendDeleteConfirmModal
  Admin->>StorageManagementPage: open Backends tab
  StorageManagementPage->>StorageBackendsListPage: render backend list
  StorageBackendsListPage->>StorageBackendsTable: render loaded backends
  Admin->>StorageBackendsTable: select delete action
  StorageBackendsTable->>StorageBackendDeleteConfirmModal: open confirmation
  StorageBackendDeleteConfirmModal-->>StorageBackendsListPage: report successful deletion
  StorageBackendsListPage-->>Admin: display remaining backends
Loading

Suggested labels: lgtm

Suggested reviewers: batzionb, rawagner

🚥 Pre-merge checks | ✅ 11
✅ Passed checks (11 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding the Storage Backends list page to the UI.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No-Hardcoded-Secrets ✅ Passed PR diff scans found no added secret assignments, private-key or vendor-token markers, or credential-bearing URLs; the only password fixture predates the PR.
No-Weak-Crypto ✅ Passed The complete OSAC-3599 diff adds no MD5, SHA1, DES, RC4, Blowfish, ECB, crypto APIs, custom crypto, or secret/token comparisons.
No-Injection-Vectors ✅ Passed The aggregate PR diff scanned 559 added lines and found no SQL concatenation, dynamic execution, unsafe YAML/pickle, shell execution, or dangerouslySetInnerHTML; backend data is rendered as escaped...
Container-Privileges ✅ Passed The PR changes no container or Kubernetes manifests and adds no privilege settings; the existing production image runs as USER 1001.
No-Sensitive-Data-In-Logs ✅ Passed No added console, logger, print, telemetry, or tracing calls were found in the PR files or added diff lines.
Ai-Attribution ✅ Passed AI use is explicit in 12 OSAC-3599 commits; each includes an Assisted-by: Claude Code trailer, and no AI Co-Authored-By trailer was found.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

@ElayAharoni
ElayAharoni marked this pull request as ready for review August 9, 2026 14:29
@openshift-ci
openshift-ci Bot requested review from jhernand and larsks August 9, 2026 14:29
@ElayAharoni
ElayAharoni requested review from batzionb and rawagner and removed request for jhernand and larsks August 9, 2026 14:30
@batzionb

Copy link
Copy Markdown
Contributor

rename state to status and move the column to be second after name

@batzionb batzionb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

fix routes after #129 is merged

@ElayAharoni
ElayAharoni force-pushed the OSAC-3599-storage-backends-list-page branch from 4a9fe01 to 9ae8da9 Compare August 10, 2026 14:52
@batzionb

Copy link
Copy Markdown
Contributor

screenshot is of tenanats page...

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
libs/ui-components/src/components/Storage/StorageBackendStatusLabel.tsx (1)

12-29: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a switch for the state mapping.

Map StorageBackendState with a switch. This makes the default behavior explicit and avoids rebuilding a lookup object on each render.

Proposed refactor
-const storageBackendStatusMap = (t: TFunction): Record<StorageBackendState, StatusLabelProps> => ({
-  [StorageBackendState.READY]: {
-    status: 'ready',
-    text: t('Ready'),
-  },
-  [StorageBackendState.UNSPECIFIED]: {
-    status: 'unspecified',
-    text: t('Unspecified'),
-  },
-});
+const getStorageBackendStatus = (
+  state: StorageBackendState | undefined,
+  t: TFunction,
+): StatusLabelProps => {
+  switch (state) {
+    case StorageBackendState.READY:
+      return { status: 'ready', text: t('Ready') };
+    case StorageBackendState.UNSPECIFIED:
+    default:
+      return { status: 'unspecified', text: t('Unspecified') };
+  }
+};
 
-  const statusMap = storageBackendStatusMap(t);
-
-  const status =
-    state !== undefined ? statusMap[state] : statusMap[StorageBackendState.UNSPECIFIED];
+  const status = getStorageBackendStatus(state, t);

Based on learnings, prefer a switch statement when mapping a discriminant to component props.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/ui-components/src/components/Storage/StorageBackendStatusLabel.tsx`
around lines 12 - 29, Replace the storageBackendStatusMap lookup and status
selection in StorageBackendStatusLabel with a switch on state that returns the
corresponding StatusLabelProps for READY and UNSPECIFIED, using UNSPECIFIED as
the default. Keep translation through the existing useTranslation hook and
preserve the rendered status behavior.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libs/ui-components/src/components/Storage/StorageBackendActionsMenu.tsx`:
- Around line 35-43: Update the MenuToggle in StorageBackendActionsMenu to
receive the controlled dropdown state via isExpanded={open}, using the same open
state managed by setOpen and passed to Control’s isOpen/onOpenChange, so its
aria-expanded value stays synchronized with the menu.

In
`@libs/ui-components/src/components/Storage/StorageBackendDeleteConfirmModal.test.tsx`:
- Around line 64-89: Update the test around StorageBackendDeleteConfirmModal so
the mocked deletion failure is triggered by the Delete action rather than being
present during render: make mutate set or return the FAILED_PRECONDITION error,
assert the exact server error is absent before clicking, then assert it appears
afterward and onSuccess remains uncalled.

---

Nitpick comments:
In `@libs/ui-components/src/components/Storage/StorageBackendStatusLabel.tsx`:
- Around line 12-29: Replace the storageBackendStatusMap lookup and status
selection in StorageBackendStatusLabel with a switch on state that returns the
corresponding StatusLabelProps for READY and UNSPECIFIED, using UNSPECIFIED as
the default. Keep translation through the existing useTranslation hook and
preserve the rendered status behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f7cbb20d-25c7-4311-b919-295f5d362f07

📥 Commits

Reviewing files that changed from the base of the PR and between 407c96f and 9ae8da9.

📒 Files selected for processing (13)
  • apps/app-frontend/src/shell/StorageRoutes.test.tsx
  • libs/i18n/locales/en/translation.json
  • libs/ui-components/src/components/Storage/StorageBackendActionsMenu.tsx
  • libs/ui-components/src/components/Storage/StorageBackendDeleteConfirmModal.test.tsx
  • libs/ui-components/src/components/Storage/StorageBackendDeleteConfirmModal.tsx
  • libs/ui-components/src/components/Storage/StorageBackendStatusLabel.test.tsx
  • libs/ui-components/src/components/Storage/StorageBackendStatusLabel.tsx
  • libs/ui-components/src/components/Storage/StorageBackendsTable.tsx
  • libs/ui-components/src/pages/admin/StorageBackendsListPage.test.tsx
  • libs/ui-components/src/pages/admin/StorageBackendsListPage.tsx
  • libs/ui-components/src/pages/admin/StorageManagementPage.test.tsx
  • libs/ui-components/src/pages/admin/StorageManagementPage.tsx
  • libs/ui-components/src/test-utils/createMockConnectTransport.ts

@ElayAharoni
ElayAharoni requested a review from batzionb August 10, 2026 14:58
Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Elay Aharoni <elayaha@gmail.com>
Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Elay Aharoni <elayaha@gmail.com>
Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Elay Aharoni <elayaha@gmail.com>
Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Elay Aharoni <elayaha@gmail.com>
Adds the delete-removal test path, which required fixing
createMockConnectTransport's StorageBackends delete handler to
actually remove the item from the fixtures array instead of no-op'ing,
so a post-delete refetch reflects the deletion.

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Elay Aharoni <elayaha@gmail.com>
Also updates StorageRoutes.test.tsx, which independently asserted on
the now-removed Backends placeholder text.

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Elay Aharoni <elayaha@gmail.com>
- Defensively clone the storageBackends fixtures array in
  createMockConnectTransport so the delete handler's mutation cannot
  corrupt a shared fixture array reused across tests regardless of
  execution order.
- Hide the "Create backend" button on a list-load error, matching the
  TenantListPage/IdentityProviderListPage convention.

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Elay Aharoni <elayaha@gmail.com>
…column

- Renamed StorageBackendStateLabel to StorageBackendStatusLabel to match
  the StatusLabel naming convention used by every other resource
  (Tenant, Cluster, IdentityProvider, Subnet, SecurityGroup,
  VirtualNetwork).
- Renamed the table's "State" column header to "Status" and moved it
  to the second position, right after Name.

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Elay Aharoni <elayaha@gmail.com>
main moved Storage under the new Infrastructure nav section
(OSAC-3780), remounting StorageRoutes at
/admin/infrastructure/storage/* instead of /admin/storage/*. Updates
the remaining hardcoded absolute navigate() targets and test
assertions in files this branch owns exclusively (Create-backend and
Edit-backend navigation) to match; StorageManagementPage.tsx and its
route registration were already updated by the rebase merge itself,
since OSAC-3780 touched those pre-existing files directly.

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Elay Aharoni <elayaha@gmail.com>
isExpanded was missing on StorageBackendActionsMenu's MenuToggle, so
aria-expanded never reflected the controlled Dropdown's open/closed
state.

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Elay Aharoni <elayaha@gmail.com>
Rebasing onto main (which merged OSAC-3604's real StorageTiersListPage
alongside our real StorageBackendsListPage in the same
StorageManagementPage.tsx) left two issues no textual merge conflict
caught:

- An unused StoragePlaceholder import (both tabs now render real
  components, StoragePlaceholder is only needed by StorageRoutes.tsx's
  create/edit routes).
- Two StorageManagementPage.test.tsx assertions written against the
  Backends tab's old placeholder text ("Storage backends"), which no
  longer renders now that the real list page is wired in. Updated to
  check for the "Create backend" button instead, mirroring how the
  same file already identifies the Tiers tab via "Create tier".

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Elay Aharoni <elayaha@gmail.com>
@ElayAharoni
ElayAharoni force-pushed the OSAC-3599-storage-backends-list-page branch from 71c3343 to b6dabb6 Compare August 11, 2026 08:55
Comment thread libs/ui-components/src/pages/admin/StorageBackendsListPage.tsx Outdated
Stop hiding the Create backend action when the backend list fails to
load; per reviewer feedback, blocking it on a data-loading error isn't
needed.

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Elay Aharoni <elayaha@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
libs/ui-components/src/pages/admin/StorageBackendsListPage.tsx (1)

18-27: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the new error-state behavior with a regression test.

The button is now intentionally outside ListPageBody, so it remains available when usePrivateStorageBackends() returns an error. Add an error-state case in libs/ui-components/src/pages/admin/StorageBackendsListPage.test.tsx that asserts Create backend remains rendered.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/ui-components/src/pages/admin/StorageBackendsListPage.tsx` around lines
18 - 27, Add an error-state regression test in StorageBackendsListPage.test.tsx
that mocks usePrivateStorageBackends() to return an error and asserts the
“Create backend” button remains rendered outside the failed list content. Reuse
the existing test setup and rendering patterns in the StorageBackendsListPage
test suite.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@libs/ui-components/src/pages/admin/StorageBackendsListPage.tsx`:
- Around line 18-27: Add an error-state regression test in
StorageBackendsListPage.test.tsx that mocks usePrivateStorageBackends() to
return an error and asserts the “Create backend” button remains rendered outside
the failed list content. Reuse the existing test setup and rendering patterns in
the StorageBackendsListPage test suite.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5fb14510-6a39-4de3-abeb-616fa3583780

📥 Commits

Reviewing files that changed from the base of the PR and between b6dabb6 and c0f1304.

📒 Files selected for processing (1)
  • libs/ui-components/src/pages/admin/StorageBackendsListPage.tsx

@openshift-ci

openshift-ci Bot commented Aug 11, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: ElayAharoni, rawagner

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

The pull request process is described here

Details Needs approval from an approver in each of these files:
  • OWNERS [ElayAharoni,rawagner]

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

@openshift-merge-bot
openshift-merge-bot Bot merged commit 86b7cff into osac-project:main Aug 11, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants