Skip to content

Commit 4660cf2

Browse files
authored
Make space for counter node when collapsed nodes exceed max columns (#1277)
1 parent b175238 commit 4660cf2

5 files changed

Lines changed: 25 additions & 21 deletions

File tree

src/main/frontend/pipeline-graph-view/pipeline-graph/main/PipelineGraph.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,14 @@ export function PipelineGraph({
6464

6565
const apply = (width: number) => {
6666
if (width <= 0) return;
67+
const reservedSpace =
68+
fullLayout.nodeSpacingH / 2 + // before start
69+
fullLayout.nodeSpacingH * 0.7 + // start node with reduced spacing
70+
-fullLayout.nodeSpacingH * 0.3 + // reduced spacing to end node
71+
fullLayout.nodeSpacingH / 2; // after end;
6772
const next = Math.max(
6873
MIN_COLUMNS_WHEN_COLLAPSED,
69-
Math.floor(width / fullLayout.nodeSpacingH) - 2,
74+
Math.floor((width - reservedSpace) / fullLayout.nodeSpacingH),
7075
);
7176
setMaxColumnsWhenCollapsed((prev) => (prev === next ? prev : next));
7277
};

src/main/frontend/pipeline-graph-view/pipeline-graph/main/PipelineGraphLayout.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -442,22 +442,22 @@ describe("PipelineGraphLayout", () => {
442442
it("uses the default threshold of 13 when no override is provided", () => {
443443
const graph = callLayout(25, true);
444444

445-
expect(graph.nodes.length).toBe(16);
446-
expect(counterFor(graph)?.stages.length).toBe(12);
445+
expect(graph.nodes.length).toBe(15);
446+
expect(counterFor(graph)?.stages.length).toBe(13);
447447
});
448448

449449
it("respects an explicit lower maxColumns override", () => {
450450
const graph = callLayout(25, true, 5);
451451

452-
expect(graph.nodes.length).toBe(8);
453-
expect(counterFor(graph)?.stages.length).toBe(20);
452+
expect(graph.nodes.length).toBe(7);
453+
expect(counterFor(graph)?.stages.length).toBe(21);
454454
});
455455

456456
it("respects an explicit higher maxColumns override", () => {
457457
const graph = callLayout(25, true, 20);
458458

459-
expect(graph.nodes.length).toBe(23);
460-
expect(counterFor(graph)?.stages.length).toBe(5);
459+
expect(graph.nodes.length).toBe(22);
460+
expect(counterFor(graph)?.stages.length).toBe(6);
461461
});
462462

463463
it("omits the counter when maxColumns exceeds the stage count", () => {

src/main/frontend/pipeline-graph-view/pipeline-graph/main/PipelineGraphLayout.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -108,22 +108,21 @@ export function layoutGraph(
108108

109109
const newMiddleNodes = createNodeColumns(middleStages);
110110

111-
const visibleNodes = newMiddleNodes.slice(0, maxColumnsWhenCollapsed);
112-
const hiddenNodes = newMiddleNodes.slice(maxColumnsWhenCollapsed);
111+
if (newMiddleNodes.length <= maxColumnsWhenCollapsed) {
112+
return [start, ...newMiddleNodes, end];
113+
}
113114

114-
const result = [start, ...visibleNodes];
115+
// Make space for the counter node.
116+
const breakPoint = maxColumnsWhenCollapsed - 1;
115117

116-
if (hiddenNodes.length > 0) {
117-
counterNode.stages = hiddenNodes.flatMap((node) =>
118+
counterNode.stages = newMiddleNodes
119+
.slice(breakPoint)
120+
.flatMap((node) =>
118121
node.rows.flatMap((row) =>
119122
row.flatMap((e) => (e as StageNodeInfo).stage),
120123
),
121124
);
122-
result.push(counter);
123-
}
124-
125-
result.push(end);
126-
return result;
125+
return [start, ...newMiddleNodes.slice(0, breakPoint), counter, end];
127126
}
128127

129128
const allNodeColumns: Array<NodeColumn> = filterWhenCollapsed([

src/main/frontend/pipeline-graph-view/pipeline-graph/main/support/nodes.spec.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,21 @@ describe("Counter node with 50+ parallel stages", () => {
6868
const graph = buildGraphWithManyStages(55, 5);
6969
const counter = counterFor(graph);
7070
expect(counter).toBeDefined();
71-
expect(counter?.stages.length).toBe(50);
71+
expect(counter?.stages.length).toBe(51);
7272
});
7373

7474
it("collapses 100 stages into a counter node with correct count", () => {
7575
const graph = buildGraphWithManyStages(100, 5);
7676
const counter = counterFor(graph);
7777
expect(counter).toBeDefined();
78-
expect(counter?.stages.length).toBe(95);
78+
expect(counter?.stages.length).toBe(96);
7979
});
8080

8181
it("counter node holds all stage references for 60 stages at default threshold", () => {
8282
const graph = buildGraphWithManyStages(60, 13);
8383
const counter = counterFor(graph);
8484
expect(counter).toBeDefined();
85-
expect(counter?.stages.length).toBe(47);
85+
expect(counter?.stages.length).toBe(48);
8686
// Each stage should retain its identity
8787
counter?.stages.forEach((stage) => {
8888
expect(stage.name).toMatch(/^Stage \d+$/);

src/test/java/io/jenkins/plugins/pipelinegraphview/PipelineGraphViewTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void smokeTest(Page p, JenkinsConfiguredWithCodeRule j) throws Exception {
4141
.goTo()
4242
.hasBuilds(1)
4343
.nthBuild(0)
44-
.hasStages(5, "Checkout", "Test", "A1", "A2", "Build")
44+
.hasStages(4, "Checkout", "Test", "A1", "A2" /* counter */)
4545
.goToBuild()
4646
.hasStagesInGraph(4, /*A*/ "Checkout", "Test", /*B*/ "Build", "Parallel")
4747
.goToPipelineOverview()

0 commit comments

Comments
 (0)