Skip to content

Conversation

@mguetta1
Copy link
Collaborator

@mguetta1 mguetta1 commented Oct 20, 2025

Related to #1318
Replacing #2109

Before:
Screenshot_20251020_095231

After:
Screenshot_20251020_095255

Summary by CodeRabbit

  • Refactor
    • Redesigned migration waves row actions into a compact action surface with a visible edit button plus streamlined manage/export/delete options; actions are conditionally displayed only for users with write permission and disable with explanatory messaging when unavailable.
  • Documentation
    • Added two user-facing messages for when no applications are available for assignment or export.

@coderabbitai
Copy link

coderabbitai bot commented Oct 20, 2025

Walkthrough

Replaced per-row Dropdown action menus with an RBAC-gated OverflowMenu containing a Pencil edit button and an ActionsColumn for manage/export/delete actions; removed local isRowDropdownOpen state and ConditionalTooltip usage; added two translation keys for no-applications messages.

Changes

Cohort / File(s) Change Summary
UI Action Menu Refactor
client/src/app/pages/migration-waves/migration-waves.tsx
Replaced per-row Dropdown and its isRowDropdownOpen state with an OverflowMenu that includes a Pencil edit button (with Tooltip) and an ActionsColumn for manage/export/delete actions; rendering gated by rbacWriteAccess; added imports (OverflowMenu, Tooltip, PencilAltIcon, ActionsColumn) and removed ConditionalTooltip plus old Dropdown-related code and local state.
Translations Added
client/public/locales/en/translation.json
Added keys noApplicationsForAssignment and noApplicationsForExport with messages for empty assignment/export states.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Row as MigrationWavesRow
  participant RBAC as RBAC
  participant Menu as OverflowMenu + ActionsColumn
  participant App as AppLogic

  Row->>RBAC: check rbacWriteAccess
  alt has write access
    Row->>Menu: render (Pencil button + ActionsColumn)
    Note right of Menu #E6F4EA: Actions: Edit, Manage, Export, Delete
    Menu->>Row: user clicks Edit
    Row->>App: open edit modal / navigate to edit
    Menu->>Row: user clicks Export/Manage/Delete
    Row->>App: perform action (with disabled/tooltip checks)
  else no write access
    Row-->>Row: no row actions rendered
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • ibolton336
  • rszwajko

Poem

🐰 I swapped the dropdown for a tiny pencil light,
RBAC nods first, then actions take flight.
Fewer states to track, no tooltip confusion,
Buttons hop cleanly into their new position. ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description Check ❓ Inconclusive The provided description template focuses primarily on PR title prefix conventions rather than defining a required structure or sections for the description body itself. The actual PR description includes relevant context such as a reference to the related issue, information about which PR it replaces, and before/after screenshots showing the visual changes. However, the description lacks detailed explanation of the technical changes being made or their rationale, which would be helpful for reviewers to understand the scope of work without examining the code. While the description provides helpful context through issue and PR references, consider adding a brief explanation of the key changes made (e.g., replacing the Dropdown menu with OverflowMenu and ActionsColumn, adding RBAC-driven access controls, and new translation entries). This would give reviewers a clearer understanding of the scope before diving into the code review.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title :sparkles: Update Migration waves table to use ActionsColumn directly reflects the main change described in the raw summary. The title uses the correct :sparkles: prefix per the repository template to indicate a non-breaking feature, is concise and specific about what's being updated (the Migration waves table) and the key technical change (using ActionsColumn), and avoids vague terminology or noise that would confuse readers reviewing the git history.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
client/src/app/pages/migration-waves/migration-waves.tsx (1)

473-537: Consider extracting action items configuration for readability.

The ActionsColumn configuration (lines 484-535) contains substantial inline logic. For improved maintainability, consider extracting this into a helper function or useMemo hook, especially since the logic includes complex conditional checks for disabled states and tooltips.

Example refactor:

const getRowActions = (migrationWave: WaveWithStatus) => [
  {
    title: t("composed.manage", {
      what: t("terms.applications").toLowerCase(),
    }),
    onClick: () => setWaveToManageModalState(migrationWave),
    isAriaDisabled: !applications || applications.length === 0,
    tooltipProps:
      !applications || applications.length === 0
        ? { content: t("message.noApplicationsForAssignment") }
        : undefined,
  },
  // ... other actions
];

// In render:
<ActionsColumn items={getRowActions(migrationWave)} />
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db2a0c0 and a10a91c.

📒 Files selected for processing (1)
  • client/src/app/pages/migration-waves/migration-waves.tsx (3 hunks)
🔇 Additional comments (2)
client/src/app/pages/migration-waves/migration-waves.tsx (2)

17-17: LGTM! New imports align with the refactoring.

The added PatternFly imports (OverflowMenu, Tooltip, PencilAltIcon, ActionsColumn) support the new action cell implementation.

Also applies to: 27-27, 31-31, 33-33


495-495: Incorrect review comment: The applications variable is always defined.

The useFetchApplications() hook (line 57 of client/src/app/queries/applications.ts) explicitly provides a default value: data: data || []. This guarantees that applications is always an array, never undefined. Accessing .length directly is safe and the defensive check is unnecessary.

Note: The optional chaining used elsewhere in the file (lines 511, 517) applies to migrationWave.applications (a property of the MigrationWave object), which is a different variable with different nullability semantics.

Likely an incorrect or invalid review comment.

@mguetta1 mguetta1 force-pushed the migration-waves-table branch from a10a91c to 791d7ea Compare October 20, 2025 07:13
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)
client/src/app/pages/migration-waves/migration-waves.tsx (1)

672-678: Optional chaining bug can throw at runtime (undefined.includes)

tickets?.map(...) may yield undefined; calling .includes on it throws. Normalize to an array first.

Apply:

-const hasExportableApplications = (tickets: Ticket[], applicationRefs: Ref[]) =>
-  applicationRefs.some(
-    (applicationRef) =>
-      !tickets
-        ?.map((ticket) => ticket?.application?.id)
-        .includes(applicationRef.id)
-  );
+const hasExportableApplications = (tickets: Ticket[] | undefined, applicationRefs: Ref[]) => {
+  const ticketAppIds = tickets?.map((t) => t?.application?.id) ?? [];
+  return applicationRefs.some((ref) => !ticketAppIds.includes(ref.id));
+};
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a10a91c and 791d7ea.

📒 Files selected for processing (2)
  • client/public/locales/en/translation.json (1 hunks)
  • client/src/app/pages/migration-waves/migration-waves.tsx (3 hunks)
🔇 Additional comments (3)
client/src/app/pages/migration-waves/migration-waves.tsx (2)

17-18: Imports updated to support new action surface — OK

Added OverflowMenu, Tooltip, PencilAltIcon, and ActionsColumn match usage below.

Also applies to: 27-28, 31-34


506-523: Disregard this review comment—the analysis is incorrect.

The fullApplications property exists and is legitimate: it's defined in the WaveWithStatus interface as fullApplications: Application[], and is populated via getApplications(wave.applications) in waves-selector.ts.

The code is correct as-is:

  • migrationWave.applications is a Ref[], while fullApplications is Application[]—the expanded application data needed for the export function.
  • The hasExportableApplications function expects Ref[] as its second parameter, so passing migrationWave?.applications is appropriate for the gating logic.

The suggested diff would actually break the export functionality by passing reference IDs instead of full application objects.

Likely an incorrect or invalid review comment.

client/public/locales/en/translation.json (1)

292-295: New i18n keys for tooltips — Verified

Keys align with usages in migration-waves.tsx. Verification confirms both message.noApplicationsForAssignment and message.noApplicationsForExport are present in the only locale file (en/translation.json) with correct values. No additional locale files exist in the repository.

Signed-off-by: Maayan Hadasi <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
client/src/app/pages/migration-waves/migration-waves.tsx (1)

515-515: Optional: Remove redundant optional chaining

Line 515 uses migrationWave?.applications, but migrationWave is guaranteed to be non-null within the .map() iteration. The optional chaining before applications is redundant.

                                      !hasExportableApplications(
                                        tickets,
-                                        migrationWave?.applications
+                                        migrationWave.applications
                                      )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 791d7ea and bebd275.

📒 Files selected for processing (1)
  • client/src/app/pages/migration-waves/migration-waves.tsx (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-20T07:18:26.598Z
Learnt from: mguetta1
PR: konveyor/tackle2-ui#2675
File: client/src/app/pages/migration-waves/migration-waves.tsx:508-510
Timestamp: 2025-10-20T07:18:26.598Z
Learning: In the tackle2-ui codebase, `WaveWithStatus` is an extended interface that includes `fullApplications: Application[]` property in addition to the base `MigrationWave` properties. The migration waves table component uses `WaveWithStatus` type, so `migrationWave.fullApplications` is a valid property reference.

Applied to files:

  • client/src/app/pages/migration-waves/migration-waves.tsx
🔇 Additional comments (1)
client/src/app/pages/migration-waves/migration-waves.tsx (1)

17-17: Excellent refactor to ActionsColumn pattern!

The migration from per-row Dropdown to OverflowMenu + ActionsColumn is well-executed. Key improvements include:

  • Resolved accessibility with aria-label on the edit button (line 477)
  • Proper i18n usage for tooltip messages (lines 500, 525)
  • Safe optional chaining for applications?.length (lines 496-497)
  • Clean RBAC gating for the entire action surface

Also applies to: 27-27, 31-31, 33-33, 473-539

Comment on lines +508 to +510
setApplicationsToExport(
migrationWave.fullApplications
),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify type consistency: fullApplications vs applications

Line 509 passes migrationWave.fullApplications (type Application[]) to setApplicationsToExport, but the state is typed as Ref[] | null (line 101-103). In contrast, the toolbar bulk export (line 345) uses item.applications (type Ref[]). This creates an inconsistency in what type ExportForm receives.

If ExportForm expects Ref[], passing Application[] may cause property access issues. If it expects Application[], the toolbar bulk export may be incorrect.

Run the following script to check the ExportForm component's prop type definitions:

If ExportForm expects Ref[], apply this fix:

                                    onClick: () =>
                                      setApplicationsToExport(
-                                        migrationWave.fullApplications
+                                        migrationWave.applications
                                      ),

If ExportForm expects Application[], update the state type and fix the toolbar usage:

-  const [applicationsToExport, setApplicationsToExport] = React.useState<
-    Ref[] | null
-  >(null);
+  const [applicationsToExport, setApplicationsToExport] = React.useState<
+    Application[] | null
+  >(null);

And on line 345:

                          onClick={() =>
                            setApplicationsToExport(
-                              selectedItems.flatMap((item) => item.applications)
+                              selectedItems.flatMap((item) => item.fullApplications)
                            )
                          }

🏁 Script executed:

#!/bin/bash
# Check ExportForm's applications prop type
echo "=== ExportForm prop type definition ==="
ast-grep --pattern 'interface $_ {
  $$$
  applications: $_
  $$$
}'  | rg -A2 -B2 "ExportForm"

echo -e "\n=== ExportForm component definition ==="
rg -n "ExportForm.*React.FC" -A 20 client/src/app/pages/migration-waves/components/export-form.tsx

echo -e "\n=== Type definitions for Application and Ref ==="
rg -n "^export interface (Application|Ref) " -A 10 client/src/app/api/models.ts

Length of output: 1706


The web search returned general information, not the codebase types. Let me search the codebase directly for the type definitions.


---

🏁 Script executed:

```shell
#!/bin/bash
# Find WaveWithStatus or MigrationWave type definition
echo "=== Looking for WaveWithStatus or MigrationWave type ==="
rg -n "export (interface|type) (WaveWithStatus|MigrationWave)" -A 15 client/src/app/api/models.ts

echo -e "\n=== Alternative search for Wave types ==="
rg -n "^export (interface|type) .*Wave" -A 10 client/src/app/api/models.ts

echo -e "\n=== Check migration-waves.tsx for type usage ==="
rg -n "migrationWave\.(fullApplications|applications)" -B 2 -A 2 client/src/app/pages/migration-waves/migration-waves.tsx

Length of output: 384



---

🏁 Script executed:

```shell
#!/bin/bash
# Find the correct paths for the files
echo "=== Locating models.ts ==="
fd -type f -name "models.ts"

echo -e "\n=== Locating migration-waves.tsx ==="
fd -type f -name "migration-waves.tsx"

echo -e "\n=== Locating export-form.tsx ==="
fd -type f -name "export-form.tsx"

Length of output: 611



---

🏁 Script executed:

```shell
#!/bin/bash
# Use correct fd syntax
echo "=== Locating models.ts ==="
fd -t f "models\.ts"

echo -e "\n=== Locating migration-waves.tsx ==="
fd -t f "migration-waves\.tsx"

Length of output: 150



---

🏁 Script executed:

```shell
#!/bin/bash
# Find WaveWithStatus or MigrationWave type definition
echo "=== Looking for WaveWithStatus or MigrationWave type ==="
rg -n "export (interface|type) (WaveWithStatus|MigrationWave)" -A 20 client/src/app/api/models.ts

echo -e "\n=== Check migrationWave property access in migration-waves.tsx ==="
rg -n "migrationWave\.(fullApplications|applications)" -B 3 -A 3 client/src/app/pages/migration-waves/migration-waves.tsx

Length of output: 3954


Use applications instead of fullApplications to match ExportForm's expected type

Line 509 passes migrationWave.fullApplications (type Application[]) to setApplicationsToExport, but the component expects Ref[] (see ExportForm's prop type at line 39).

The type hierarchy confirms the mismatch: WaveWithStatus has both applications: Ref[] (inherited from MigrationWave) and fullApplications: Application[]. Since line 345 correctly uses item.applications for the toolbar bulk export, line 509 should do the same:

                                      setApplicationsToExport(
-                                        migrationWave.fullApplications
+                                        migrationWave.applications
                                      ),
📝 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
setApplicationsToExport(
migrationWave.fullApplications
),
setApplicationsToExport(
migrationWave.applications
),
🤖 Prompt for AI Agents
In client/src/app/pages/migration-waves/migration-waves.tsx around lines 508 to
510, the call to setApplicationsToExport is passing
migrationWave.fullApplications (Application[]), but ExportForm expects Ref[] via
applications; replace migrationWave.fullApplications with
migrationWave.applications to pass the correct type and match the toolbar bulk
export usage elsewhere.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants