Skip to content

Commit f43302c

Browse files
committed
refactor: extract applyWaypointUpdate helper to deduplicate routing waypoint methods
1 parent 75d6c35 commit f43302c

1 file changed

Lines changed: 62 additions & 141 deletions

File tree

src/lib/stores/routing.ts

Lines changed: 62 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,54 @@ const state = writable<RoutingState>({
8585
/** Generation counter — incremented on each recalculateAllRoutes call to cancel stale async work */
8686
let routingGeneration = 0;
8787

88+
function findConnection(connectionId: string): Connection | undefined {
89+
return get(graphStore.connections).find((c) => c.id === connectionId);
90+
}
91+
92+
/**
93+
* Persist new waypoints for a connection, then either recompute the route
94+
* synchronously (when port positions are available) or invalidate the cached
95+
* route so a fresh calculation runs on the next read.
96+
*
97+
* Shared by addUserWaypoint, addUserWaypointAtIndex, removeUserWaypoint, and
98+
* moveWaypoint — they all do the same thing after they've decided what the
99+
* new waypoint list should look like.
100+
*/
101+
function applyWaypointUpdate(
102+
connection: Connection,
103+
updatedWaypoints: Waypoint[],
104+
getPortInfo: ((nodeId: string, portIndex: number, isOutput: boolean) => PortInfo | null) | undefined
105+
): void {
106+
graphStore.updateConnectionWaypoints(connection.id, updatedWaypoints);
107+
108+
if (getPortInfo) {
109+
const $state = get(state);
110+
const sourceInfo = getPortInfo(connection.sourceNodeId, connection.sourcePortIndex, true);
111+
const targetInfo = getPortInfo(connection.targetNodeId, connection.targetPortIndex, false);
112+
113+
if (sourceInfo && targetInfo) {
114+
const userWaypoints = getUserWaypoints(updatedWaypoints);
115+
const result = computeRoute(
116+
sourceInfo.position,
117+
targetInfo.position,
118+
sourceInfo.direction,
119+
targetInfo.direction,
120+
$state.grid,
121+
userWaypoints
122+
);
123+
124+
state.update((s) => {
125+
const routes = new Map(s.routes);
126+
routes.set(connection.id, result);
127+
return { ...s, routes };
128+
});
129+
return;
130+
}
131+
}
132+
133+
routingStore.invalidateRoute(connection.id);
134+
}
135+
88136
/**
89137
* Routing store - manages route calculations and caching
90138
*/
@@ -501,50 +549,17 @@ export const routingStore = {
501549
): string | null {
502550
let waypointId: string | null = null;
503551
historyStore.mutate(() => {
504-
const connections = get(graphStore.connections);
505-
const connection = connections.find((c) => c.id === connectionId);
552+
const connection = findConnection(connectionId);
506553
if (!connection) return;
507554

508555
waypointId = generateId();
509-
const newWaypoint: Waypoint = {
510-
id: waypointId,
511-
position,
512-
isUserWaypoint: true
513-
};
556+
const newWaypoint: Waypoint = { id: waypointId, position, isUserWaypoint: true };
514557

515-
// Get existing user waypoints (filter out auto waypoints)
558+
// Drop auto waypoints — they'll be regenerated from the new user-waypoint set.
516559
const existingUserWaypoints = getUserWaypoints(connection.waypoints);
517560
const updatedWaypoints = [...existingUserWaypoints, newWaypoint];
518561

519-
graphStore.updateConnectionWaypoints(connectionId, updatedWaypoints);
520-
521-
// Immediately recalculate route if we have port info (prevents full recalc)
522-
if (getPortInfo) {
523-
const $state = get(state);
524-
const sourceInfo = getPortInfo(connection.sourceNodeId, connection.sourcePortIndex, true);
525-
const targetInfo = getPortInfo(connection.targetNodeId, connection.targetPortIndex, false);
526-
527-
if (sourceInfo && targetInfo) {
528-
const result = computeRoute(
529-
sourceInfo.position,
530-
targetInfo.position,
531-
sourceInfo.direction,
532-
targetInfo.direction,
533-
$state.grid,
534-
updatedWaypoints
535-
);
536-
537-
state.update((s) => {
538-
const routes = new Map(s.routes);
539-
routes.set(connectionId, result);
540-
return { ...s, routes };
541-
});
542-
return;
543-
}
544-
}
545-
546-
// Fallback: just invalidate
547-
routingStore.invalidateRoute(connectionId);
562+
applyWaypointUpdate(connection, updatedWaypoints, getPortInfo);
548563
});
549564
return waypointId;
550565
},
@@ -562,56 +577,20 @@ export const routingStore = {
562577
): string | null {
563578
let waypointId: string | null = null;
564579
historyStore.mutate(() => {
565-
const connections = get(graphStore.connections);
566-
const connection = connections.find((c) => c.id === connectionId);
580+
const connection = findConnection(connectionId);
567581
if (!connection) return;
568582

569583
waypointId = generateId();
570-
const newWaypoint: Waypoint = {
571-
id: waypointId,
572-
position,
573-
isUserWaypoint: true
574-
};
584+
const newWaypoint: Waypoint = { id: waypointId, position, isUserWaypoint: true };
575585

576-
// Get existing user waypoints
577586
const existingUserWaypoints = getUserWaypoints(connection.waypoints);
578-
579-
// Insert at the specified index
580587
const updatedWaypoints = [
581588
...existingUserWaypoints.slice(0, insertIndex),
582589
newWaypoint,
583590
...existingUserWaypoints.slice(insertIndex)
584591
];
585592

586-
graphStore.updateConnectionWaypoints(connectionId, updatedWaypoints);
587-
588-
// Immediately recalculate route if we have port info (prevents full recalc)
589-
if (getPortInfo) {
590-
const $state = get(state);
591-
const sourceInfo = getPortInfo(connection.sourceNodeId, connection.sourcePortIndex, true);
592-
const targetInfo = getPortInfo(connection.targetNodeId, connection.targetPortIndex, false);
593-
594-
if (sourceInfo && targetInfo) {
595-
const result = computeRoute(
596-
sourceInfo.position,
597-
targetInfo.position,
598-
sourceInfo.direction,
599-
targetInfo.direction,
600-
$state.grid,
601-
updatedWaypoints
602-
);
603-
604-
state.update((s) => {
605-
const routes = new Map(s.routes);
606-
routes.set(connectionId, result);
607-
return { ...s, routes };
608-
});
609-
return;
610-
}
611-
}
612-
613-
// Fallback: just invalidate
614-
routingStore.invalidateRoute(connectionId);
593+
applyWaypointUpdate(connection, updatedWaypoints, getPortInfo);
615594
});
616595
return waypointId;
617596
},
@@ -626,49 +605,21 @@ export const routingStore = {
626605
getPortInfo?: (nodeId: string, portIndex: number, isOutput: boolean) => PortInfo | null
627606
): void {
628607
historyStore.mutate(() => {
629-
const connections = get(graphStore.connections);
630-
const connection = connections.find((c) => c.id === connectionId);
608+
const connection = findConnection(connectionId);
631609
if (!connection?.waypoints) return;
632610

633611
const updatedWaypoints = connection.waypoints.filter(
634612
(w) => w.id !== waypointId || !w.isUserWaypoint
635613
);
636614

637-
graphStore.updateConnectionWaypoints(connectionId, updatedWaypoints);
638-
639-
// Immediately recalculate route if we have port info (prevents flicker)
640-
if (getPortInfo) {
641-
const $state = get(state);
642-
const sourceInfo = getPortInfo(connection.sourceNodeId, connection.sourcePortIndex, true);
643-
const targetInfo = getPortInfo(connection.targetNodeId, connection.targetPortIndex, false);
644-
645-
if (sourceInfo && targetInfo) {
646-
const userWaypoints = getUserWaypoints(updatedWaypoints);
647-
const result = computeRoute(
648-
sourceInfo.position,
649-
targetInfo.position,
650-
sourceInfo.direction,
651-
targetInfo.direction,
652-
$state.grid,
653-
userWaypoints
654-
);
655-
656-
state.update((s) => {
657-
const routes = new Map(s.routes);
658-
routes.set(connectionId, result);
659-
return { ...s, routes };
660-
});
661-
return;
662-
}
663-
}
664-
665-
// Fallback: just invalidate
666-
routingStore.invalidateRoute(connectionId);
615+
applyWaypointUpdate(connection, updatedWaypoints, getPortInfo);
667616
});
668617
},
669618

670619
/**
671-
* Move a waypoint to a new position and recalculate route
620+
* Move a waypoint to a new position and recalculate route.
621+
* Not wrapped in historyStore.mutate — the caller owns the drag transaction
622+
* so a single drag becomes one undo entry rather than one per move event.
672623
* @param getPortInfo - Optional callback to get port info for route recalculation
673624
*/
674625
moveWaypoint(
@@ -677,44 +628,14 @@ export const routingStore = {
677628
newPosition: Position,
678629
getPortInfo?: (nodeId: string, portIndex: number, isOutput: boolean) => PortInfo | null
679630
): void {
680-
const connections = get(graphStore.connections);
681-
const connection = connections.find((c) => c.id === connectionId);
631+
const connection = findConnection(connectionId);
682632
if (!connection?.waypoints) return;
683633

684634
const updatedWaypoints = connection.waypoints.map((w) =>
685635
w.id === waypointId ? { ...w, position: newPosition } : w
686636
);
687637

688-
graphStore.updateConnectionWaypoints(connectionId, updatedWaypoints);
689-
690-
// If getPortInfo is provided, recalculate route immediately
691-
if (getPortInfo) {
692-
const $state = get(state);
693-
const sourceInfo = getPortInfo(connection.sourceNodeId, connection.sourcePortIndex, true);
694-
const targetInfo = getPortInfo(connection.targetNodeId, connection.targetPortIndex, false);
695-
696-
if (sourceInfo && targetInfo) {
697-
const userWaypoints = getUserWaypoints(updatedWaypoints);
698-
const result = computeRoute(
699-
sourceInfo.position,
700-
targetInfo.position,
701-
sourceInfo.direction,
702-
targetInfo.direction,
703-
$state.grid,
704-
userWaypoints
705-
);
706-
707-
state.update((s) => {
708-
const routes = new Map(s.routes);
709-
routes.set(connectionId, result);
710-
return { ...s, routes };
711-
});
712-
return;
713-
}
714-
}
715-
716-
// Fallback: just invalidate
717-
routingStore.invalidateRoute(connectionId);
638+
applyWaypointUpdate(connection, updatedWaypoints, getPortInfo);
718639
},
719640

720641
/**

0 commit comments

Comments
 (0)