Skip to content

Conversation

@sjd78
Copy link
Member

@sjd78 sjd78 commented Nov 8, 2025

Resolves: https://issues.redhat.com/browse/MTA-6287
Resolves: #2708

All targets will new be displayed, even if they are not in the target order setting. The target query hook now will return the server ordering of the targets, and ordering by the "ui.target.order" setting. All targets are included in both lists. Any unordered targets is added to the end of the ordered list. By putting this logic in the target query hook, target order can be used the same way everywhere it is needed.

On the migration-targets page, the targets are now displayed in the order specified by the "ui.target.order" setting. Any targets not in the setting are added to the end of the list.

On the custom-target-form, updated the onSubmit handler to both create a new target and add it to the target order. This is done awaiting async mutations to help ensure the operations finish before the create modal is closed.

Summary by CodeRabbit

  • Refactor

    • Unified target ordering so lists, gallery, filters and drag-and-drop use a single ordered source; creation/edit flows now receive and propagate ordering so new items appear in the expected place.
    • Target fetch API now exposes an ordered list consumers use for rendering and interactions.
  • Bug Fixes

    • Loading and save flows simplified to reduce flicker and missed updates.
    • Settings cache invalidation narrowed to specific keys for more reliable refreshes.

@sjd78 sjd78 added this to the v0.8.1 milestone Nov 8, 2025
@sjd78 sjd78 added the cherry-pick/release-0.8 This PR should be cherry-picked to release-0.8 branch label Nov 8, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 8, 2025

Walkthrough

Replace local target ordering with a server-backed ordered list (targetsInOrder) from useFetchTargets; expose ordered targets and async mutation hooks; pass targetOrder into CustomTargetForm; scope settings cache invalidation to per-key queries.

Changes

Cohort / File(s) Summary
Queries: targets & settings
client/src/app/queries/targets.ts, client/src/app/queries/settings.ts
useFetchTargets now computes and returns targetsInOrder (memoized from ui.target.order) and exposes mutateAsync on create/file mutations; settings mutations now invalidate queries with [SettingQueryKey, key] for scoped cache invalidation.
Migration targets UI
client/src/app/pages/migration-targets/migration-targets.tsx
UI switched to use targetsInOrder everywhere (filters, table/drag items, provider mapping); onCustomTargetModalSaved became async; now passes targetOrder into CustomTargetForm; ordering display composes persisted order + unordered targets.
Custom target form
client/src/app/pages/migration-targets/components/custom-target-form.tsx
Added public prop targetOrder: number[]; introduced useTargetQueryHooks to centralize create/update/image and ordering mutateAsync flows; creation awaits createTargetAsync then appends new ID to order via targetOrderMutateAsync.
Analysis wizard update
client/src/app/pages/applications/analysis-wizard/set-targets.tsx
Removed local sorting and ui.target.order usage inside the component; now consumes targetsInOrder from useFetchTargets and simplifies loading state.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Form as CustomTargetForm
    participant UI as MigrationTargets
    participant API as Backend
    participant Settings as ui.target.order

    rect `#E8F8F5`
    Note over User,Form: Create target (new flow)
    User->>Form: Submit new target
    Form->>API: createTargetAsync
    API-->>Form: New Target (with id)
    Form->>Settings: targetOrderMutateAsync (append new id)
    Settings-->>Form: Order updated
    Form-->>UI: notify saved (awaited)
    UI->>API: useFetchTargets -> returns targets + targetsInOrder
    API-->>UI: targetsInOrder
    UI->>UI: render using targetsInOrder
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay extra attention to:
    • correctness of targetsInOrder computation and inclusion of unordered targets
    • proper usage of mutateAsync (avoiding unhandled races)
    • useTargetQueryHooks error/reset/notification flows and side-effects
    • settings invalidateQueries key scoping in queries/settings.ts

Possibly related PRs

Suggested reviewers

  • rszwajko
  • ibolton336

Poem

🐰
I hop with joy when targets align,
New IDs land and then entwine,
No vanished cards, no frantic race,
The order kept in its safe place,
Hooray — I thump my paws in time!

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title ':bug: Fix custom target order handling' directly addresses the main objective of fixing target order handling and aligns with the core changes in the changeset.
Description check ✅ Passed The PR description provides clear context about the problem, the solution, and implementation details across multiple affected components, aligning with the template requirements.
Linked Issues check ✅ Passed The PR implements the core requirement from #2708: ensuring newly created targets persist in the UI by centralizing ordering logic, including all targets in both ordered and unordered lists, and updating the custom-target-form to add new targets to the order setting.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing target order handling: removing local order computation in set-targets, centralizing ordering in the targets query hook, updating migration-targets page to use the new order, and updating custom-target-form to support the new flow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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: 1

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-targets/migration-targets.tsx (1)

218-236: Don't drop all visible targets when the order setting is unavailable.

filteredTargetsInOrder returns an empty list whenever the setting query is still loading or errors. That leaves the gallery blank (and permanently empty on an error) even though filteredTargets already contains the data from useFetchTargets, defeating the PR’s goal of always showing new targets.

Fall back to the filtered targets when the order setting isn’t ready, and only apply the ordered/append logic once we actually have the setting:

-    if (!targetOrderSetting.isSuccess) {
-      return [];
-    }
+    if (!targetOrderSetting.isSuccess || !Array.isArray(targetOrderSetting.data)) {
+      return filteredTargets;
+    }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2921ea and 2b6e57a.

📒 Files selected for processing (5)
  • client/src/app/pages/applications/analysis-wizard/set-targets.tsx (2 hunks)
  • client/src/app/pages/migration-targets/components/custom-target-form.tsx (5 hunks)
  • client/src/app/pages/migration-targets/migration-targets.tsx (7 hunks)
  • client/src/app/queries/settings.ts (1 hunks)
  • client/src/app/queries/targets.ts (4 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-07-18T23:21:22.818Z
Learnt from: sjd78
Repo: konveyor/tackle2-ui PR: 2472
File: client/src/app/pages/controls/job-functions/job-functions.tsx:56-58
Timestamp: 2025-07-18T23:21:22.818Z
Learning: In the tackle2-ui codebase, mutation hooks in the queries files already handle cache invalidation by calling queryClient.invalidateQueries() in their onSuccess callbacks. This ensures immediate UI updates after CRUD operations without needing additional manual invalidation in the UI components.

Applied to files:

  • client/src/app/queries/settings.ts
  • client/src/app/queries/targets.ts
📚 Learning: 2025-10-03T14:26:45.291Z
Learnt from: sjd78
Repo: konveyor/tackle2-ui PR: 2631
File: client/src/app/api/rest/applications.ts:14-15
Timestamp: 2025-10-03T14:26:45.291Z
Learning: In the tackle2-ui codebase, delete and update REST functions in files under `client/src/app/api/rest/` return `AxiosPromise<void>` (which resolves to `AxiosResponse<void>`) rather than unwrapped `Promise<void>`. This return type is expected and correctly handled by the React Query mutation hooks in `client/src/app/queries/`, which accept promise-compatible types including AxiosPromise.

Applied to files:

  • client/src/app/pages/migration-targets/components/custom-target-form.tsx
  • client/src/app/queries/targets.ts
📚 Learning: 2025-07-21T06:01:43.078Z
Learnt from: sjd78
Repo: konveyor/tackle2-ui PR: 2467
File: client/src/app/queries/generators.ts:20-20
Timestamp: 2025-07-21T06:01:43.078Z
Learning: The tackle2-ui codebase uses React Query v4 (tanstack/react-query v4.22.0), where the onError callback in query configurations is still valid and supported. The deprecation of onError callbacks only applies to React Query v5, so suggestions about removing them are premature until the codebase is upgraded.

Applied to files:

  • client/src/app/queries/targets.ts
📚 Learning: 2025-07-29T14:20:50.580Z
Learnt from: sjd78
Repo: konveyor/tackle2-ui PR: 2468
File: client/src/app/pages/source-platforms/usePlatformProviderList.ts:1-3
Timestamp: 2025-07-29T14:20:50.580Z
Learning: TargetCard component is focused on transformation targets, not source platform providers. It imports Target/TargetLabel models and operates independently from usePlatformProviderList. The codebase maintains clear separation between source platforms (managed by usePlatformProviderList) and transformation targets (managed by TargetCard).

Applied to files:

  • client/src/app/pages/migration-targets/migration-targets.tsx
  • client/src/app/pages/applications/analysis-wizard/set-targets.tsx
🧬 Code graph analysis (3)
client/src/app/pages/migration-targets/components/custom-target-form.tsx (5)
client/src/app/api/models.ts (1)
  • Target (557-567)
client/src/app/components/NotificationsContext.tsx (1)
  • NotificationsContext (31-33)
client/src/app/queries/targets.ts (3)
  • useCreateFileMutation (138-159)
  • useCreateTargetMutation (115-136)
  • useUpdateTargetMutation (69-89)
client/src/app/utils/utils.ts (1)
  • getAxiosErrorMessage (10-16)
client/src/app/queries/settings.ts (1)
  • useSettingMutation (20-32)
client/src/app/queries/targets.ts (4)
client/src/app/Constants.ts (1)
  • DEFAULT_REFETCH_INTERVAL (16-16)
client/src/app/api/models.ts (1)
  • Target (557-567)
client/src/app/api/rest.ts (1)
  • getTargets (314-315)
client/src/app/queries/settings.ts (1)
  • useSetting (9-19)
client/src/app/pages/migration-targets/migration-targets.tsx (3)
client/src/app/queries/targets.ts (1)
  • useFetchTargets (19-67)
client/src/app/api/models.ts (1)
  • Target (557-567)
client/src/app/hooks/table-controls/useLocalTableControls.ts (1)
  • useLocalTableControls (12-46)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: unit-test
  • GitHub Check: build-and-upload-for-global-ci

Resolves: https://issues.redhat.com/browse/MTA-6287
Resolves: konveyor#2708

All targets will new be displayed, even if they are not in the
target order setting.  The target query hook now will return the
server ordering of the targets, and ordering by the "ui.target.order"
setting.  All targets are included in both lists.  Any unordered
targets is added to the end of the ordered list.  By putting this
logic in the target query hook, target order can be used the same
way everywhere it is needed.

On the migration-targets page, the targets are now displayed in
the order specified by the "ui.target.order" setting.  Any targets
not in the setting are added to the end of the list.

On the custom-target-form, updated the onSubmit handler to
both create a new target and add it to the target order.  This
is done awaiting async mutations to help ensure the operations
finish before the create modal is closed.

Signed-off-by: Scott J Dickerson <[email protected]>
Signed-off-by: Scott J Dickerson <[email protected]>
@sjd78 sjd78 force-pushed the custom_target_ui.order branch from 2e29a90 to 0b79f1c Compare November 10, 2025 15:01
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
client/src/app/pages/migration-targets/components/custom-target-form.tsx (1)

397-412: Silent error handling hides mutation failures.

The empty catch blocks on lines 401-403 and 409-411 silently swallow all errors. While the mutation hooks have their own error handling (notifications), the caller has no way to detect if these operations failed, which could be important for debugging or recovery logic.

Note: The race condition where targetOrder could be empty if the setting hasn't loaded was already flagged in previous review comments. As discussed, this will be addressed via conditional rendering in a separate issue.

Consider at minimum logging errors for observability:

       try {
         const response = await createTargetAsync(payload);
         newTargetId = response.data.id;
       } catch {
-        /* ignore */
+        console.error("Failed to create target");
       }

       // Add the new target to the target order and wait for it to complete before continuing.
       if (newTargetId !== undefined) {
         try {
           await targetOrderMutateAsync([...targetOrder, newTargetId]);
         } catch {
-          /* ignore */
+          console.error("Failed to update target order");
         }
       }
🧹 Nitpick comments (2)
client/src/app/pages/migration-targets/components/custom-target-form.tsx (1)

82-126: Good consolidation of mutation hooks.

The useTargetQueryHooks hook centralizes mutation logic that was previously scattered throughout the component, improving maintainability.

One observation: onUpdateTargetFailure (line 110) is a no-op. If error notifications aren't needed for update failures, consider documenting why or removing the empty handler.

client/src/app/pages/migration-targets/migration-targets.tsx (1)

97-142: Remove unnecessary async keyword.

The function is marked async on line 97 but contains no await expressions. The async keyword is unnecessary and can be removed.

Apply this diff:

-  const onCustomTargetModalSaved = async (response: AxiosResponse<Target>) => {
+  const onCustomTargetModalSaved = (response: AxiosResponse<Target>) => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2e29a90 and 0b79f1c.

📒 Files selected for processing (5)
  • client/src/app/pages/applications/analysis-wizard/set-targets.tsx (2 hunks)
  • client/src/app/pages/migration-targets/components/custom-target-form.tsx (5 hunks)
  • client/src/app/pages/migration-targets/migration-targets.tsx (7 hunks)
  • client/src/app/queries/settings.ts (1 hunks)
  • client/src/app/queries/targets.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • client/src/app/queries/targets.ts
  • client/src/app/pages/applications/analysis-wizard/set-targets.tsx
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-18T23:21:22.818Z
Learnt from: sjd78
Repo: konveyor/tackle2-ui PR: 2472
File: client/src/app/pages/controls/job-functions/job-functions.tsx:56-58
Timestamp: 2025-07-18T23:21:22.818Z
Learning: In the tackle2-ui codebase, mutation hooks in the queries files already handle cache invalidation by calling queryClient.invalidateQueries() in their onSuccess callbacks. This ensures immediate UI updates after CRUD operations without needing additional manual invalidation in the UI components.

Applied to files:

  • client/src/app/queries/settings.ts
📚 Learning: 2025-07-29T14:20:50.580Z
Learnt from: sjd78
Repo: konveyor/tackle2-ui PR: 2468
File: client/src/app/pages/source-platforms/usePlatformProviderList.ts:1-3
Timestamp: 2025-07-29T14:20:50.580Z
Learning: TargetCard component is focused on transformation targets, not source platform providers. It imports Target/TargetLabel models and operates independently from usePlatformProviderList. The codebase maintains clear separation between source platforms (managed by usePlatformProviderList) and transformation targets (managed by TargetCard).

Applied to files:

  • client/src/app/pages/migration-targets/components/custom-target-form.tsx
  • client/src/app/pages/migration-targets/migration-targets.tsx
📚 Learning: 2025-10-03T14:26:45.291Z
Learnt from: sjd78
Repo: konveyor/tackle2-ui PR: 2631
File: client/src/app/api/rest/applications.ts:14-15
Timestamp: 2025-10-03T14:26:45.291Z
Learning: In the tackle2-ui codebase, delete and update REST functions in files under `client/src/app/api/rest/` return `AxiosPromise<void>` (which resolves to `AxiosResponse<void>`) rather than unwrapped `Promise<void>`. This return type is expected and correctly handled by the React Query mutation hooks in `client/src/app/queries/`, which accept promise-compatible types including AxiosPromise.

Applied to files:

  • client/src/app/pages/migration-targets/components/custom-target-form.tsx
🧬 Code graph analysis (2)
client/src/app/pages/migration-targets/components/custom-target-form.tsx (6)
client/src/app/api/models.ts (1)
  • Target (557-567)
client/src/app/components/NotificationsContext.tsx (1)
  • NotificationsContext (31-33)
client/src/app/queries/targets.ts (3)
  • useCreateFileMutation (138-159)
  • useCreateTargetMutation (115-136)
  • useUpdateTargetMutation (69-89)
client/src/app/utils/utils.ts (1)
  • getAxiosErrorMessage (10-16)
client/src/app/api/rest.ts (1)
  • updateTarget (304-305)
client/src/app/queries/settings.ts (1)
  • useSettingMutation (20-32)
client/src/app/pages/migration-targets/migration-targets.tsx (2)
client/src/app/queries/targets.ts (1)
  • useFetchTargets (19-67)
client/src/app/hooks/table-controls/useLocalTableControls.ts (1)
  • useLocalTableControls (12-46)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: unit-test
  • GitHub Check: build-and-upload-for-global-ci
🔇 Additional comments (6)
client/src/app/queries/settings.ts (1)

20-31: LGTM! Improved cache invalidation specificity.

The change from invalidating all setting queries to invalidating only the specific setting key is a good refinement. This prevents unnecessary refetches of unrelated settings and aligns with React Query best practices.

Based on learnings.

client/src/app/pages/migration-targets/components/custom-target-form.tsx (1)

49-54: LGTM! Props updated to support target ordering.

The addition of targetOrder enables the form to coordinate target ordering after creation, which aligns with the PR's objective to centralize ordering logic.

client/src/app/pages/migration-targets/migration-targets.tsx (4)

53-53: LGTM! Using centralized target ordering.

The switch to targetsInOrder aligns with the PR's objective to centralize ordering logic in the target query hook.


169-175: LGTM! Drag handling updated for ordered targets.

The active target resolution correctly uses targetsInOrder to match the rendered gallery items.


218-236: LGTM! Correct implementation of ordered + unordered target display.

The logic correctly:

  1. Orders targets according to ui.target.order setting
  2. Appends targets not in the setting to the end
  3. Maintains filtering behavior

This directly addresses the PR objective: "All targets will now be displayed even if they are not present in the target order setting."


316-322: LGTM! Target order passed to form for coordinated creation.

Passing targetOrder enables the CustomTargetForm to update the ordering after creating a new target, supporting the PR's goal to centralize ordering logic.

@sjd78 sjd78 merged commit e1b3b66 into konveyor:main Nov 10, 2025
12 checks passed
@sjd78 sjd78 deleted the custom_target_ui.order branch November 10, 2025 15:34
github-actions bot pushed a commit that referenced this pull request Nov 10, 2025
Resolves: https://issues.redhat.com/browse/MTA-6287
Resolves: #2708

All targets will new be displayed, even if they are not in the target
order setting. The target query hook now will return the server ordering
of the targets, and ordering by the "ui.target.order" setting. All
targets are included in both lists. Any unordered targets is added to
the end of the ordered list. By putting this logic in the target query
hook, target order can be used the same way everywhere it is needed.

On the migration-targets page, the targets are now displayed in the
order specified by the "ui.target.order" setting. Any targets not in the
setting are added to the end of the list.

On the custom-target-form, updated the onSubmit handler to both create a
new target and add it to the target order. This is done awaiting async
mutations to help ensure the operations finish before the create modal
is closed.

## Summary by CodeRabbit

* **Refactor**
  * Unified target ordering so lists, gallery, filters and drag-and-drop
    use a single ordered source; creation/edit flows now receive and
    propagate ordering so new items appear in the expected place.
  * Target fetch API now exposes an ordered list consumers use for
    rendering and interactions.

* **Bug Fixes**
  * Loading and save flows simplified to reduce flicker and missed
    updates.
  * Settings cache invalidation narrowed to specific keys for more
    reliable refreshes.

---------

Signed-off-by: Scott J Dickerson <[email protected]>
Signed-off-by: Cherry Picker <[email protected]>
sjd78 pushed a commit that referenced this pull request Nov 10, 2025
Resolves: https://issues.redhat.com/browse/MTA-6287
Resolves: #2708
Backport-Of: #2719

All targets will new be displayed, even if they are not in the target
order setting. The target query hook now will return the server ordering
of the targets, and ordering by the "ui.target.order" setting. All
targets are included in both lists. Any unordered targets is added to
the end of the ordered list. By putting this logic in the target query
hook, target order can be used the same way everywhere it is needed.

On the migration-targets page, the targets are now displayed in the
order specified by the "ui.target.order" setting. Any targets not in the
setting are added to the end of the list.

On the custom-target-form, updated the onSubmit handler to both create a
new target and add it to the target order. This is done awaiting async
mutations to help ensure the operations finish before the create modal
is closed.

## Summary by CodeRabbit

* **Refactor**
  * Unified target ordering so lists, gallery, filters and drag-and-drop
    use a single ordered source; creation/edit flows now receive and
    propagate ordering so new items appear in the expected place.
  * Target fetch API now exposes an ordered list consumers use for
    rendering and interactions.

* **Bug Fixes**
  * Loading and save flows simplified to reduce flicker and missed
    updates.
  * Settings cache invalidation narrowed to specific keys for more
    reliable refreshes.

---------

Signed-off-by: Scott J Dickerson <[email protected]>
Signed-off-by: Cherry Picker <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cherry-pick/release-0.8 This PR should be cherry-picked to release-0.8 branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Changing the layout right after creating a target makes it disappear

2 participants