Skip to content

feat: add multi-destination pathfinding with drag-and-drop reordering#2954

Open
julian1j wants to merge 5 commits into
SpecterOps:mainfrom
julian1j:feat/multi-destination-pathfinding
Open

feat: add multi-destination pathfinding with drag-and-drop reordering#2954
julian1j wants to merge 5 commits into
SpecterOps:mainfrom
julian1j:feat/multi-destination-pathfinding

Conversation

@julian1j

@julian1j julian1j commented Jul 2, 2026

Copy link
Copy Markdown

Enables chaining up to 4 nodes (1 source + 3 destinations) in pathfinding queries. Each consecutive pair fires a parallel shortestpath API call and results are merged client-side. Includes drag-and-drop reordering, node removal, and URL persistence via tertiarySearch/quaternarySearch params.

Description

Enables chaining up to 4 nodes (1 source + 3 destinations) in pathfinding queries, similar to Google Maps multi-stop routing

  • Each consecutive node pair fires a parallel shortestpath API call; results are merged client-side
  • Drag-and-drop reordering, inline node removal, and "Add Destination" button
  • URL persistence via new tertiarySearch/quaternarySearch params
  • Swap button retained for 2-node pathfinding; hidden when 3+ nodes are active

Motivation and Context

Resolves BED-8075

Why is this change required? What problem does it solve?

How Has This Been Tested?

Tested locally on CE with standard example dataset.

Screenshots (optional):

two_nodes three_nodes four_nodes

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist:

Summary by CodeRabbit

  • New Features
    • Multi-stop pathfinding in Explore now supports up to four ordered waypoints.
    • The pathfinding UI is dynamic, letting users add, remove, and reorder waypoint nodes (drag-and-drop and keyboard).
  • Bug Fixes
    • Waypoint selections stay in sync with URL parameters, including higher-order waypoints.
    • Multi-leg path results are merged correctly across consecutive waypoint pairs.
    • Clearing higher-order waypoints now clears their related query fields.
  • Chores
    • Updated ignore rules to exclude the local .claude/ directory.

Enables chaining up to 4 nodes (1 source + 3 destinations) in pathfinding
queries. Each consecutive pair fires a parallel shortest-path API call and
results are merged client-side. Includes drag-and-drop reordering, node
removal, and URL persistence via tertiarySearch/quaternarySearch params.
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: de4ecbff-0b26-45c7-b3ca-2e51a26515bc

📥 Commits

Reviewing files that changed from the base of the PR and between 09cf304 and a5c8697.

📒 Files selected for processing (1)
  • packages/javascript/bh-shared-ui/src/hooks/useExploreGraph/usePathfindingSearch.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/javascript/bh-shared-ui/src/hooks/useExploreGraph/usePathfindingSearch.ts

📝 Walkthrough

Walkthrough

This PR extends pathfinding search from two fixed endpoints to up to four ordered waypoints, adding URL parameter support, multi-leg graph querying, dynamic hook state, and draggable UI updates. It also adds a .claude/ ignore entry.

Changes

Multi-node pathfinding

Layer / File(s) Summary
Query param contract for extra waypoints
packages/javascript/bh-shared-ui/src/hooks/useExploreParams/useExploreParams.tsx
Adds tertiarySearch and quaternarySearch to ExploreQueryParams, reads and returns them from URL params, and whitelists them in the settable param keys.
Multi-leg shortest path query merging
packages/javascript/bh-shared-ui/src/hooks/useExploreGraph/queries/pathfindingSearch.ts
Adds GraphResponse typing and mergeGraphResponses, then extends pathfindingSearchGraphQuery to issue parallel getShortestPathV2 requests per waypoint pair and merge the results with an updated query key.
usePathfindingSearch node array refactor
packages/javascript/bh-shared-ui/src/hooks/useExploreGraph/usePathfindingSearch.ts
Replaces fixed source/destination state with a dynamic nodes array and extraNodeCount, syncs from URL params, and generalizes select/edit/swap/reorder/add/remove handlers with an updated return shape.
Reorderable pathfinding node UI
packages/javascript/bh-shared-ui/src/views/Explore/ExploreSearch/PathfindingSearch.tsx, cmd/ui/src/views/Explore/ExploreSearch/ExploreSearch.tsx, cmd/ui/src/views/Explore/ExploreSearch/ExploreSearch.test.tsx
Reworks PathfindingSearchState and PathfindingSearch to render draggable node rows with add/remove controls, conditional swap behavior, an updated SourceToBullseyeIcon, teardown cleanup for tertiary/quaternary params, and updated test queries for the pathfinding controls.

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

Suggested labels: enhancement, user interface

Suggested reviewers: catsiller

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main feature: multi-destination pathfinding with drag-and-drop reordering.
Description check ✅ Passed The description follows the required template with description, motivation, testing, issue reference, screenshots, and change type.
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
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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
`@packages/javascript/bh-shared-ui/src/hooks/useExploreGraph/queries/pathfindingSearch.ts`:
- Around line 48-49: The waypoint list in pathfindingSearch is compacting sparse
inputs with filter(Boolean), which can change the intended slot order for
persisted URL destinations. Update the waypoints construction in
useExploreGraph/pathfindingSearch to preserve positional gaps or explicitly
reject/normalize sparse chains before calling the path query, so primarySearch,
secondarySearch, tertiarySearch, and quaternarySearch are interpreted in their
original order.

In
`@packages/javascript/bh-shared-ui/src/hooks/useExploreGraph/usePathfindingSearch.ts`:
- Around line 59-71: The `usePathfindingSearch` effects only increase
`extraNodeCount`, so clearing `tertiarySearch` or `quaternarySearch` leaves
`totalNodeCount` stale and keeps empty waypoint rows rendered. Update the
`useEffect` blocks around `syncNodeFromParam` to also recalculate or reset
`extraNodeCount` based on the current URL params instead of only using
`Math.max`, so removed waypoints reduce the count when appropriate. Make sure
the logic handles both the tertiary and quaternary cases consistently and keeps
`setExtraNodeCount` in sync with `tertiarySearch`, `quaternarySearch`, `data2`,
and `data3`.

In
`@packages/javascript/bh-shared-ui/src/views/Explore/ExploreSearch/PathfindingSearch.tsx`:
- Around line 138-151: Add a keyboard-accessible way to reorder destinations in
PathfindingSearch: the current draggable-only flow in the item wrapper and grip
icon is not reachable by keyboard users. Update the reorder UI around the
draggable row and grip control to expose focusable move controls or keyboard
event handling (for example in the same render path that uses handleDragStart,
handleDragEnter, handleDrop, and the faGripVertical grip) so users can move
items up/down without a mouse.
🪄 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: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 73ecc1f1-2444-4b27-a40a-cee68850e4bf

📥 Commits

Reviewing files that changed from the base of the PR and between aa6e331 and 9c54864.

📒 Files selected for processing (6)
  • .gitignore
  • cmd/ui/src/views/Explore/ExploreSearch/ExploreSearch.tsx
  • packages/javascript/bh-shared-ui/src/hooks/useExploreGraph/queries/pathfindingSearch.ts
  • packages/javascript/bh-shared-ui/src/hooks/useExploreGraph/usePathfindingSearch.ts
  • packages/javascript/bh-shared-ui/src/hooks/useExploreParams/useExploreParams.tsx
  • packages/javascript/bh-shared-ui/src/views/Explore/ExploreSearch/PathfindingSearch.tsx

Comment on lines +48 to +49
// Build ordered list of waypoints
const waypoints = [primarySearch, secondarySearch, tertiarySearch, quaternarySearch].filter(Boolean) as string[];

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Don’t compact sparse waypoint params.

filter(Boolean) turns [primary, secondary, null, quaternary] into [primary, secondary, quaternary], so a sparse URL can query a different ordered path than the persisted node slots indicate. Since this PR adds URL persistence for extra destinations, disable or normalize sparse chains before querying.

Proposed guard
-    const waypoints = [primarySearch, secondarySearch, tertiarySearch, quaternarySearch].filter(Boolean) as string[];
+    if (!tertiarySearch && quaternarySearch) {
+        return { enabled: false };
+    }
+
+    const waypoints = [primarySearch, secondarySearch, tertiarySearch, quaternarySearch].filter(
+        (waypoint): waypoint is string => !!waypoint
+    );
🤖 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
`@packages/javascript/bh-shared-ui/src/hooks/useExploreGraph/queries/pathfindingSearch.ts`
around lines 48 - 49, The waypoint list in pathfindingSearch is compacting
sparse inputs with filter(Boolean), which can change the intended slot order for
persisted URL destinations. Update the waypoints construction in
useExploreGraph/pathfindingSearch to preserve positional gaps or explicitly
reject/normalize sparse chains before calling the path query, so primarySearch,
secondarySearch, tertiarySearch, and quaternarySearch are interpreted in their
original order.

julian1j added 3 commits July 2, 2026 15:41
- Sync extraNodeCount bidirectionally with URL params so removing
  waypoints properly reduces the visible node count
- Add keyboard accessibility to drag-and-drop reorder (arrow keys
  on the grip handle)
Wrap updateNode and syncNodeFromParam in useCallback to satisfy
react-hooks/exhaustive-deps lint rule.
Use getByRole('textbox') to target inputs specifically, avoiding
ambiguity with the reorder grip handle aria-labels.
@coderabbitai coderabbitai Bot added enhancement New feature or request user interface A pull request containing changes affecting the UI code. labels Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request user interface A pull request containing changes affecting the UI code.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant