Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ and this project adheres to

### Fixed

- Fix paths swapping positions when clicking edges in auto-layout mode
[#4328](https://github.com/OpenFn/lightning/issues/4328)
- Fix clicking nodes causing unwanted zoom in workflow diagram
[#4327](https://github.com/OpenFn/lightning/issues/4327)

Expand Down
2 changes: 1 addition & 1 deletion assets/js/workflow-diagram/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,5 +222,5 @@ export const sortOrderForSvg = (a: object, b: object) => {
return -1;
}

return a.selected - b.selected;
Comment thread
doc-han marked this conversation as resolved.
return 0;
};
2 changes: 1 addition & 1 deletion assets/js/workflow-diagram/util/update-selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default (model: Flow.Model, newSelection: string | null) => {

const updatedModel = {
nodes: model.nodes.map(updateItem) as Flow.Node[],
// Must put selected edge LAST to ensure it stays on top.
// Sort edges by enabled status. Selection state does not affect order.
edges: model.edges.map(updateItem).sort(sortOrderForSvg) as Flow.Edge[],
};

Expand Down
90 changes: 90 additions & 0 deletions assets/test/workflow-diagram/styles.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { describe, expect, test } from 'vitest';

import { sortOrderForSvg } from '../../js/workflow-diagram/styles';

describe.concurrent('sortOrderForSvg', () => {
test('sorts disabled edges before enabled edges', () => {
const edges = [
{ data: { enabled: true }, selected: false },
{ data: { enabled: false }, selected: false },
];

const sorted = [...edges].sort(sortOrderForSvg);

expect(sorted[0].data.enabled).toBe(false);
expect(sorted[1].data.enabled).toBe(true);
});

test('maintains stable order for edges with same enabled status', () => {
const edges = [
{ id: 'edge1', data: { enabled: true }, selected: false },
{ id: 'edge2', data: { enabled: true }, selected: false },
{ id: 'edge3', data: { enabled: true }, selected: false },
];

const sorted = [...edges].sort(sortOrderForSvg);

// Order should remain unchanged when all have same enabled status
expect(sorted[0].id).toBe('edge1');
expect(sorted[1].id).toBe('edge2');
expect(sorted[2].id).toBe('edge3');
});

test('preserves stable order when selection state changes', () => {
// This test ensures that selecting edges doesn't cause layout shifts
const edges = [
{ id: 'edge1', data: { enabled: true }, selected: false },
{ id: 'edge2', data: { enabled: true }, selected: false },
{ id: 'edge3', data: { enabled: true }, selected: false },
];

// Sort once with no selection
const sortedBefore = [...edges].sort(sortOrderForSvg);

// Simulate selecting middle edge
const edgesWithSelection = [
{ id: 'edge1', data: { enabled: true }, selected: false },
{ id: 'edge2', data: { enabled: true }, selected: true },
{ id: 'edge3', data: { enabled: true }, selected: false },
];

const sortedAfter = [...edgesWithSelection].sort(sortOrderForSvg);

// Order should NOT change when selection changes
expect(sortedBefore[0].id).toBe(sortedAfter[0].id);
expect(sortedBefore[1].id).toBe(sortedAfter[1].id);
expect(sortedBefore[2].id).toBe(sortedAfter[2].id);
});

test('handles mix of enabled and disabled edges correctly', () => {
const edges = [
{ id: 'disabled1', data: { enabled: false }, selected: false },
{ id: 'enabled1', data: { enabled: true }, selected: false },
{ id: 'disabled2', data: { enabled: false }, selected: false },
{ id: 'enabled2', data: { enabled: true }, selected: false },
];

const sorted = [...edges].sort(sortOrderForSvg);

// All disabled edges should come before enabled edges
expect(sorted[0].id).toBe('disabled1');
expect(sorted[1].id).toBe('disabled2');
expect(sorted[2].id).toBe('enabled1');
expect(sorted[3].id).toBe('enabled2');
});

test('maintains stable order within disabled edge group', () => {
const edges = [
{ id: 'disabled1', data: { enabled: false }, selected: false },
{ id: 'disabled2', data: { enabled: false }, selected: true },
{ id: 'disabled3', data: { enabled: false }, selected: false },
];

const sorted = [...edges].sort(sortOrderForSvg);

// Order within disabled group should remain stable regardless of selection
expect(sorted[0].id).toBe('disabled1');
expect(sorted[1].id).toBe('disabled2');
expect(sorted[2].id).toBe('disabled3');
});
});