feat(edges): aggregate cross-group edges into exit/bridge/entry paths - #320
Conversation
jeff-phillips-18
left a comment
There was a problem hiding this comment.
Thanks @jpinsonneau. Looking real good. A few suggestions.
|
Thanks for the feedback @jeff-phillips-18 🥳 Split demo into
Replaced DemoDefaultGroup + “Collapse Group 2 & Subgroup 3” checkbox with collapsible DefaultGroup; collapse rebuilds aggregates from leaf edges via context |
|
@jpinsonneau I'm seeing a couple of issues: For the first, it looks like an existing issue in The second issue looks to be due to handling the collapsed state in the view. I don't think that is needed as it is held by by the However, after making those changes, I am seeing an odd edge arrow after collapsing:
|
|
Thanks @jeff-phillips-18 — addressed in the latest commit:
|
4879125 to
e4dd81a
Compare
Good catch @jeff-phillips-18 I have fixed that case in 4da96ea
|
|
These new edges created with roles will rely on the application creating an edge component very much like the I'm still not exactly sure what the |
Sure, added the
Aggregate edges pin endpoints with
|
jeff-phillips-18
left a comment
There was a problem hiding this comment.
Thanks @jpinsonneau. LGTM!
Thanks for your quick feedback ! I appreciate 👍 |
| action(() => { | ||
| state[SELECTION_STATE] = selectedIds; | ||
| })(); |
There was a problem hiding this comment.
Why is this necessary? We shouldn't modify the controller's state directly and the following fireEvent will update the state correctly.
There was a problem hiding this comment.
Sure, let me fix that
| }, | ||
| forceSnap ? 0 : AGGREGATE_HULL_SETTLE_MS | ||
| ); | ||
|
|
There was a problem hiding this comment.
@jpinsonneau Could you explain these two timer functions? Why do we need both? It looks like the timeout function is supposed to happen after the requestAnimationFrame function but on forceSnap it will occur before. Is that purposeful?
There was a problem hiding this comment.
While geometry is moving we use two phases: requestAnimationFrame for a cheap approx snap (keeps stubs attached during Cola ticks), then a settle timeout (~100ms) for a precise hull snap. On forceSnap (layout end / collapse) that delay-0 race was real.
I'll skip approx and run one precise snap on requestAnimationFrame only.
| if (!edge.hasController()) { | ||
| return; | ||
| } | ||
| const plan = computeSnapPlan(edge, role, false); | ||
| if (plan) { | ||
| applySnapPlan(edge, plan, moveThreshold, true); | ||
| } |
There was a problem hiding this comment.
This is largely repeated below with the only change being the threshold passed to applySnapPlan. We could have one utility function that does this and just takes the edge, role, and threshold. I don't see applySnapPlan ever being called with the clearUnset parameter set to false.
There was a problem hiding this comment.
Sure let me create a function and drop cleanUnser
| start?: XY; | ||
| end?: XY; |
There was a problem hiding this comment.
| start?: XY; | |
| end?: XY; | |
| start: XY | null; | |
| end: XY | null; |
| const startFixed = plan.start != null; | ||
| const endFixed = plan.end != null; |
There was a problem hiding this comment.
| const startFixed = plan.start != null; | |
| const endFixed = plan.end != null; | |
| const startFixed = plan.start !== null; | |
| const endFixed = plan.end !== null; |
| return; | ||
| } | ||
| const startMoved = startFixed | ||
| ? significantlyMoved(edge.getStartPoint(), plan.start!.x, plan.start!.y, threshold) |
There was a problem hiding this comment.
| ? significantlyMoved(edge.getStartPoint(), plan.start!.x, plan.start!.y, threshold) | |
| ? significantlyMoved(edge.getStartPoint(), plan.start.x, plan.start.y, threshold) |
Remove all non-null assertions.
| if (!peer) { | ||
| return undefined; | ||
| } | ||
| const plan: SnapPlan = {}; |
There was a problem hiding this comment.
| const plan: SnapPlan = {}; | |
| const plan: SnapPlan = { | |
| start: null, | |
| end: null | |
| }; |
| if (!edges?.length) { | ||
| return []; | ||
| } | ||
| if (!nodes?.length) { | ||
| return edges; | ||
| } |
There was a problem hiding this comment.
| if (!edges?.length) { | |
| return []; | |
| } | |
| if (!nodes?.length) { | |
| return edges; | |
| } | |
| if (!edges?.length || !nodes?.length) { | |
| return []; | |
| } |
If there are no nodes, we should have no edges.
| }); | ||
| vis.fromModel( | ||
| getModel({ | ||
| groupEdges: true, |
There was a problem hiding this comment.
| groupEdges: true, | |
| groupEdges: false, |
Should match the initial demo context value
|
@jpinsonneau Sorry, went through it again and found some issues I missed before. Also, could you squash all the previous commits? |
321ab9f to
517e755
Compare
Addressed the changes and squash into a single commit |
| } else { | ||
| const aggregate = createSegmentEdge(aggregateEdgeType, segment, edge.id, true, edge.label, true); | ||
| aggregate.children = [edge.id]; | ||
| pendingAggregates.push(aggregate); |
There was a problem hiding this comment.
I don't see this being used anywhere
There was a problem hiding this comment.
Done alongside of some polishing about unused code / export
https://github.com/patternfly/react-topology/compare/517e755c3eb88303111f29acfbba6874147dd44d..bf8270c7f316216ad32cf13bd9fd8dcd0b530c27
Closes patternfly#17 Co-authored-by: Cursor <cursoragent@cursor.com>
517e755 to
bf8270c
Compare
|
🎉 This PR is included in version 6.6.0-prerelease.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |






Summary
createAggregateEdgeswith agroupEdgesoption that splits cross-group leaf edges into exit → bridge → entry segments and merges parallel bridges between the same parent groups (addresses Topology - Aggregating edges between node groups #17 / PF-1994).collapsedGroupsaggregation behavior; adds leaf-id tracking (aggregatedEdgeIds,count, optional label carry onto the bridge).Test plan
yarn test packages/module/src/utils/__tests__/createAggregateEdges.spec.tsMade with Cursor