Skip to content

feat(openchoreo): add row-level delete to catalog and namespace listings#675

Open
isuruRuhu wants to merge 3 commits into
openchoreo:mainfrom
isuruRuhu:feat/component-delete-listing
Open

feat(openchoreo): add row-level delete to catalog and namespace listings#675
isuruRuhu wants to merge 3 commits into
openchoreo:mainfrom
isuruRuhu:feat/component-delete-listing

Conversation

@isuruRuhu

@isuruRuhu isuruRuhu commented Jul 8, 2026

Copy link
Copy Markdown

Purpose

To let users delete entities directly from the console listing pages, without opening each entity page first. A delete action is added to the rows of the catalog "All ..." pages, the namespace page's projects/resources cards, and the project's Project Contents table (components and resources).

Goals

Describe the solutions that this feature/fix will introduce to resolve the problems described above

Approach

A shared useDeleteEntityDialog hook dispatches the delete per entity kind, reusing the same kind mapping and confirmation dialog as the entity-page context menu. A reusable RowDeleteButton renders the row action only for kinds the API can delete and hides it for rows already marked for deletion. Deleted rows are overlaid with the "marked for deletion" badge until the catalog sync catches up.

User stories

Summary of user stories addressed by this change>

Release note

Brief description of the new feature or bug fix as it will appear in the release notes

Documentation

Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter “N/A” plus brief explanation of why there’s no doc impact

Training

Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable

Certification

Type “Sent” when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type “N/A” and explain why.

Marketing

Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable

Automation tests

  • Unit tests

    Code coverage information

Summary by CodeRabbit

  • New Features

    • Added delete actions throughout listing and project views, including row-level delete buttons and a shared confirmation dialog.
    • Deleted rows now stay visible with a pending-deletion indicator until the list refreshes.
    • Expanded delete support to more entity types, including resource rows where applicable.
  • Bug Fixes

    • Parent systems now refresh after a component is deleted, reducing stale related-entity messages.
  • Style

    • Updated table spacing and column widths to fit the new actions layout.

isuruRuhu added 3 commits July 8, 2026 16:46
Signed-off-by: isuruRuhu <isuru.ruhu@gmail.com>
Signed-off-by: isuruRuhu <isuru.ruhu@gmail.com>
Signed-off-by: isuruRuhu <isuru.ruhu@gmail.com>
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR generalizes listing-row delete behavior across the Backstage plugin: a new useDeleteEntityDialog hook, RowDeleteButton, DeleteEntityDialog, and usePendingDeletionOverlay replace component-specific deletion logic and are wired into catalog, namespace, and project content listings. Separately, the catalog backend module refreshes the parent System entity when a Component is deleted.

Changes

Frontend row-delete generalization

Layer / File(s) Summary
Delete dispatch and display helpers
plugins/openchoreo/src/components/DeleteEntity/hooks/deleteEntityDispatch.tsx
Adds getEntityDisplayType, isDeletableEntityKind, performEntityDelete, and getEntityDeleteCascadeNote to centralize per-kind deletion dispatch and labeling.
Delete dialog and row button components
.../components/DeleteEntityDialog.tsx, .../components/RowDeleteButton.tsx(.test.tsx)
Adds a reusable confirmation dialog and a gated per-row delete icon button, with tests for visibility and click behavior.
Dialog hook and pending-deletion overlay
.../hooks/useDeleteEntityDialog.tsx(.test.tsx), .../hooks/usePendingDeletionOverlay.ts, .../utils/deletionUtils.ts
Adds a shared dialog-management hook (state, alerts, error handling) and an overlay hook plus utilities to optimistically mark rows as deleted.
Menu items refactor and exports wiring
.../hooks/useDeleteEntityMenuItems.tsx, .../components/index.ts, .../hooks/index.ts, .../DeleteEntity/index.ts, plugins/openchoreo/src/index.ts
Refactors the entity context-menu delete flow to reuse shared helpers and dialog, and re-exports new APIs through barrel files.
Catalog, namespace, and project listing wiring
packages/app/src/components/catalog/*, .../Namespaces/*Card/*, .../Projects/ProjectContentsCard/*
Integrates RowDeleteButton, dialog, and overlay into CatalogCardList, namespace project/resource cards, and Project Contents table rows/columns, including style adjustments and new RowActionsCell.
Changesets
.changeset/component-delete-from-project-listing.md, .changeset/listing-row-delete-everywhere.md
Document the minor version bump and behavior for the generalized row delete feature.

System refresh on component delete

Layer / File(s) Summary
Parent System resolution and refresh
plugins/catalog-backend-module-openchoreo/src/provider/EventDeltaApplier.ts
Adds findParentSystemRef and refreshEntityRef helpers and updates the component-deletion path to refresh the resolved parent System after removal.
Tests and changeset
EventDeltaApplier.test.ts, .changeset/refresh-system-on-component-delete.md
Adds tests for partOf-based resolution, spec.system fallback, and unresolved-owner cases, plus a patch changeset.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Row as RowDeleteButton
  participant Dialog as useDeleteEntityDialog
  participant Client as OpenChoreoClientApi
  participant Overlay as usePendingDeletionOverlay
  Row->>Dialog: requestDelete(entity)
  Dialog->>Client: performEntityDelete(entity)
  Client-->>Dialog: success
  Dialog->>Overlay: markDeleted(entity)
  Overlay-->>Row: overlay(entities) shows deletion badge
Loading
sequenceDiagram
  participant Event as EventDeltaApplier
  participant Catalog as CatalogService
  Event->>Catalog: getEntityByRef(component)
  Catalog-->>Event: parent System ref (partOf or spec.system)
  Event->>Catalog: remove Component entity
  Event->>Catalog: refreshEntity(System ref)
Loading

Suggested reviewers: sameerajayasoma, stefinie123, kaviththiranga, Mirage20

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning Only Purpose and Approach are filled; most required template sections are missing or left as placeholders. Add content for Goals, User stories, Release note, Documentation, Automation tests, and the remaining required sections in the template.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main change: adding row-level delete actions to listing pages.
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.
✨ 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.

@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 (2)
plugins/openchoreo/src/components/Projects/ProjectContentsCard/ProjectContentsCard.tsx (1)

89-95: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider consolidating pending-deletion tracking with usePendingDeletionOverlay.

ProjectContentsCard manually manages a pendingDeletions Set and applies optimistic marks via withOptimisticDeletion, which overlaps with what usePendingDeletionOverlay provides (markDeleted + overlay). The duplication is currently justified because the overlay here operates on ProjectContentItem[] (not Entity[]) and the card also needs a refreshToken bump that the hook doesn't support. If this pattern appears in more listing components, consider extracting a lower-level usePendingDeletionSet hook (exposing markDeleted, isPending, and the raw Set) that both usePendingDeletionOverlay and this card could share.

Also applies to: 216-225

🤖 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
`@plugins/openchoreo/src/components/Projects/ProjectContentsCard/ProjectContentsCard.tsx`
around lines 89 - 95, `ProjectContentsCard` is duplicating pending-deletion
state management that overlaps with `usePendingDeletionOverlay`; refactor the
shared logic so the card can reuse a lower-level pending-deletion primitive
instead of owning its own `pendingDeletions` Set and `withOptimisticDeletion`
flow. Keep the card-specific `refreshToken` behavior, but move the shared
delete-tracking pieces into a reusable hook (for example a
`usePendingDeletionSet`-style helper) that exposes `markDeleted`, `isPending`,
and the raw Set, then have both `ProjectContentsCard` and
`usePendingDeletionOverlay` consume it.
plugins/openchoreo/src/components/DeleteEntity/hooks/useDeleteEntityDialog.test.tsx (1)

84-263: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a test for the in-flight "deleting" state.

The suite covers open/close, success, and error paths but doesn't verify the UI guards that prevent closing the dialog while a delete is in progress (disabled buttons, handleClose early-return, spinner). A never-resolving promise can hold the hook in the deleting state to assert these guards.

✅ Suggested test
   it('closes on cancel without calling the API', async () => {
     // ... existing test ...
   });
+
+  it('disables actions and keeps the dialog open while deletion is in flight', async () => {
+    const user = userEvent.setup();
+    // Never-resolving promise keeps the hook in the deleting state
+    mockClient.deleteComponent.mockReturnValue(new Promise(() => {}));
+
+    renderHarness([makeComponent('my-service')]);
+
+    await user.click(screen.getByTestId('open-my-service'));
+    await user.click(screen.getByRole('button', { name: /^delete$/i }));
+
+    await waitFor(() => {
+      expect(screen.getByRole('button', { name: /cancel/i })).toBeDisabled();
+      expect(screen.getByRole('button', { name: /deleting/i })).toBeDisabled();
+    });
+
+    // Dialog remains open
+    expect(
+      screen.getByRole('heading', { name: /delete component/i }),
+    ).toBeInTheDocument();
+  });
🤖 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
`@plugins/openchoreo/src/components/DeleteEntity/hooks/useDeleteEntityDialog.test.tsx`
around lines 84 - 263, Add a test in useDeleteEntityDialog.test.tsx for the
in-flight deleting state: trigger delete through the existing
renderHarness/useDeleteEntityDialog flow with a never-resolving
mockClient.deleteComponent promise, then assert the dialog enters the deleting
state and UI guards are active (cancel/delete disabled, spinner shown, and close
attempts are ignored by handleClose). Use the existing makeComponent,
renderHarness, and delete button flow to locate the right hook behavior without
changing the success/error tests.
🤖 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 @.changeset/component-delete-from-project-listing.md:
- Around line 5-10: The changeset summary is inconsistent with the implemented
behavior: RowActionsCell and RowDeleteButton support deletion for both component
and resource rows, and the related listing-row-delete-everywhere.md changeset
confirms that scope. Update the wording in the changeset to remove the “hidden
for resources” claim and describe the delete action as applying to both
components and resources, so the changelog matches the final behavior.

In
`@plugins/openchoreo/src/components/DeleteEntity/hooks/deleteEntityDispatch.tsx`:
- Around line 110-128: The cascade note in getEntityDeleteCascadeNote is using
Typography variant="h5", which makes the warning read like a heading inside the
delete confirmation dialog. Update the returned Typography for both the system
and domain branches to use a body-level variant such as body2 or caption, and
keep the note visually distinct with the existing warning styling instead of
relying on heading semantics.

---

Nitpick comments:
In
`@plugins/openchoreo/src/components/DeleteEntity/hooks/useDeleteEntityDialog.test.tsx`:
- Around line 84-263: Add a test in useDeleteEntityDialog.test.tsx for the
in-flight deleting state: trigger delete through the existing
renderHarness/useDeleteEntityDialog flow with a never-resolving
mockClient.deleteComponent promise, then assert the dialog enters the deleting
state and UI guards are active (cancel/delete disabled, spinner shown, and close
attempts are ignored by handleClose). Use the existing makeComponent,
renderHarness, and delete button flow to locate the right hook behavior without
changing the success/error tests.

In
`@plugins/openchoreo/src/components/Projects/ProjectContentsCard/ProjectContentsCard.tsx`:
- Around line 89-95: `ProjectContentsCard` is duplicating pending-deletion state
management that overlaps with `usePendingDeletionOverlay`; refactor the shared
logic so the card can reuse a lower-level pending-deletion primitive instead of
owning its own `pendingDeletions` Set and `withOptimisticDeletion` flow. Keep
the card-specific `refreshToken` behavior, but move the shared delete-tracking
pieces into a reusable hook (for example a `usePendingDeletionSet`-style helper)
that exposes `markDeleted`, `isPending`, and the raw Set, then have both
`ProjectContentsCard` and `usePendingDeletionOverlay` consume it.
🪄 Autofix (Beta)

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

Review profile: CHILL

Plan: Pro

Run ID: e7e3e82b-e732-45b7-820f-d25520ec739a

📥 Commits

Reviewing files that changed from the base of the PR and between f1163a9 and 373f493.

📒 Files selected for processing (29)
  • .changeset/component-delete-from-project-listing.md
  • .changeset/listing-row-delete-everywhere.md
  • .changeset/refresh-system-on-component-delete.md
  • packages/app/src/components/catalog/CatalogCardList.tsx
  • packages/app/src/components/catalog/styles.ts
  • plugins/catalog-backend-module-openchoreo/src/provider/EventDeltaApplier.test.ts
  • plugins/catalog-backend-module-openchoreo/src/provider/EventDeltaApplier.ts
  • plugins/openchoreo/src/components/DeleteEntity/components/DeleteEntityDialog.tsx
  • plugins/openchoreo/src/components/DeleteEntity/components/RowDeleteButton.test.tsx
  • plugins/openchoreo/src/components/DeleteEntity/components/RowDeleteButton.tsx
  • plugins/openchoreo/src/components/DeleteEntity/components/index.ts
  • plugins/openchoreo/src/components/DeleteEntity/hooks/deleteEntityDispatch.tsx
  • plugins/openchoreo/src/components/DeleteEntity/hooks/index.ts
  • plugins/openchoreo/src/components/DeleteEntity/hooks/useDeleteEntityDialog.test.tsx
  • plugins/openchoreo/src/components/DeleteEntity/hooks/useDeleteEntityDialog.tsx
  • plugins/openchoreo/src/components/DeleteEntity/hooks/useDeleteEntityMenuItems.tsx
  • plugins/openchoreo/src/components/DeleteEntity/hooks/usePendingDeletionOverlay.ts
  • plugins/openchoreo/src/components/DeleteEntity/index.ts
  • plugins/openchoreo/src/components/DeleteEntity/utils/deletionUtils.ts
  • plugins/openchoreo/src/components/DeleteEntity/utils/index.ts
  • plugins/openchoreo/src/components/Namespaces/NamespaceProjectsCard/NamespaceProjectsCard.tsx
  • plugins/openchoreo/src/components/Namespaces/NamespaceResourcesCard/NamespaceResourcesCard.tsx
  • plugins/openchoreo/src/components/Projects/ProjectContentsCard/ProjectContentsCard.test.tsx
  • plugins/openchoreo/src/components/Projects/ProjectContentsCard/ProjectContentsCard.tsx
  • plugins/openchoreo/src/components/Projects/ProjectContentsCard/RowActionsCell.test.tsx
  • plugins/openchoreo/src/components/Projects/ProjectContentsCard/RowActionsCell.tsx
  • plugins/openchoreo/src/components/Projects/ProjectContentsCard/columns.tsx
  • plugins/openchoreo/src/components/Projects/hooks/useProjectContentsPage.ts
  • plugins/openchoreo/src/index.ts

Comment on lines +5 to +10
Add a per-row "Delete" action to the Project Contents table so a component
can be deleted directly from the project listing without opening the
component page first. The action surfaces in a row "more actions" kebab for
component rows (hidden for resources and for rows already marked for
deletion), reuses the shared delete-confirmation dialog, and refreshes the
listing once the component is marked for deletion.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Changeset says "hidden for resources" but code supports resource deletion.

RowActionsCell renders RowDeleteButton for both component and resource items, and RowActionsCell.test.tsx confirms the delete button appears for resource rows. The companion changeset listing-row-delete-everywhere.md also states it "extends the Project Contents row action to resource rows." Since both changesets ship together, the "hidden for resources" clause is inaccurate for the final state and will confuse changelog readers.

📝 Suggested changeset revision
 Add a per-row "Delete" action to the Project Contents table so a component
 can be deleted directly from the project listing without opening the
-component page first. The action surfaces in a row "more actions" kebab for
-component rows (hidden for resources and for rows already marked for
-deletion), reuses the shared delete-confirmation dialog, and refreshes
-the listing once the component is marked for deletion.
+component page first. The action surfaces as a per-row delete button for
+both component and resource rows (hidden for rows already marked for
+deletion), reuses the shared delete-confirmation dialog, and optimistically
+marks the row for deletion until the next catalog sync drops it.
📝 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
Add a per-row "Delete" action to the Project Contents table so a component
can be deleted directly from the project listing without opening the
component page first. The action surfaces in a row "more actions" kebab for
component rows (hidden for resources and for rows already marked for
deletion), reuses the shared delete-confirmation dialog, and refreshes the
listing once the component is marked for deletion.
Add a per-row "Delete" action to the Project Contents table so a component
can be deleted directly from the project listing without opening the
component page first. The action surfaces as a per-row delete button for
both component and resource rows (hidden for rows already marked for
deletion), reuses the shared delete-confirmation dialog, and optimistically
marks the row for deletion until the next catalog sync drops it.
🤖 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 @.changeset/component-delete-from-project-listing.md around lines 5 - 10, The
changeset summary is inconsistent with the implemented behavior: RowActionsCell
and RowDeleteButton support deletion for both component and resource rows, and
the related listing-row-delete-everywhere.md changeset confirms that scope.
Update the wording in the changeset to remove the “hidden for resources” claim
and describe the delete action as applying to both components and resources, so
the changelog matches the final behavior.

Comment on lines +110 to +128
export function getEntityDeleteCascadeNote(kind: string): ReactNode {
const kindLower = kind.toLowerCase();
if (kindLower === 'system') {
return (
<Typography variant="h5">
Note: All components within this project will also be deleted.
</Typography>
);
}
if (kindLower === 'domain') {
return (
<Typography variant="h5">
Note: All projects and components within this namespace will also be
deleted.
</Typography>
);
}
return undefined;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use body2 or caption variant for cascade note text instead of h5.

Typography variant="h5" renders as a heading, which is semantically incorrect for a warning note inside a confirmation dialog. Screen readers will announce it as a heading, and visually it will be disproportionately large relative to the dialog's other text. Use variant="body2" (or caption) with a warning color instead.

🎨 Proposed fix
 export function getEntityDeleteCascadeNote(kind: string): ReactNode {
   const kindLower = kind.toLowerCase();
   if (kindLower === 'system') {
     return (
-      <Typography variant="h5">
+      <Typography variant="body2" color="error">
         Note: All components within this project will also be deleted.
       </Typography>
     );
   }
   if (kindLower === 'domain') {
     return (
-      <Typography variant="h5">
+      <Typography variant="body2" color="error">
         Note: All projects and components within this namespace will also be
         deleted.
       </Typography>
     );
   }
   return undefined;
 }
📝 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
export function getEntityDeleteCascadeNote(kind: string): ReactNode {
const kindLower = kind.toLowerCase();
if (kindLower === 'system') {
return (
<Typography variant="h5">
Note: All components within this project will also be deleted.
</Typography>
);
}
if (kindLower === 'domain') {
return (
<Typography variant="h5">
Note: All projects and components within this namespace will also be
deleted.
</Typography>
);
}
return undefined;
}
export function getEntityDeleteCascadeNote(kind: string): ReactNode {
const kindLower = kind.toLowerCase();
if (kindLower === 'system') {
return (
<Typography variant="body2" color="error">
Note: All components within this project will also be deleted.
</Typography>
);
}
if (kindLower === 'domain') {
return (
<Typography variant="body2" color="error">
Note: All projects and components within this namespace will also be
deleted.
</Typography>
);
}
return undefined;
}
🤖 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
`@plugins/openchoreo/src/components/DeleteEntity/hooks/deleteEntityDispatch.tsx`
around lines 110 - 128, The cascade note in getEntityDeleteCascadeNote is using
Typography variant="h5", which makes the warning read like a heading inside the
delete confirmation dialog. Update the returned Typography for both the system
and domain branches to use a body-level variant such as body2 or caption, and
keep the note visually distinct with the existing warning styling instead of
relying on heading semantics.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant