From 00ac6ccb373f625669c652b8d74db8e3592acac5 Mon Sep 17 00:00:00 2001 From: Matheus B Date: Fri, 22 Dec 2023 20:42:24 -0300 Subject: [PATCH 01/13] Add parallelCommits config option for gitGraphs --- packages/mermaid/src/schemas/config.schema.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/mermaid/src/schemas/config.schema.yaml b/packages/mermaid/src/schemas/config.schema.yaml index 2791c32d4..51e419cd6 100644 --- a/packages/mermaid/src/schemas/config.schema.yaml +++ b/packages/mermaid/src/schemas/config.schema.yaml @@ -780,6 +780,9 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file) rotateCommitLabel: type: boolean default: true + parallelCommits: + type: boolean + default: false # YAML anchor reference, don't use $ref since ajv doesn't load defaults arrowMarkerAbsolute: *arrowMarkerAbsolute From 222c46e7f002bb1a5b3c7b4ca31d24e51393c4d6 Mon Sep 17 00:00:00 2001 From: Matheus B Date: Fri, 22 Dec 2023 21:08:15 -0300 Subject: [PATCH 02/13] Implement support for parallel commits config --- .../src/diagrams/git/gitGraphRenderer.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js index 66e2277de..ce2b6c5f6 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js +++ b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js @@ -64,6 +64,29 @@ const drawText = (txt) => { return svgLabel; }; +/** + * Searches for the closest parent from the parents list passed as argument. + * The parents list comes from an individual commit. The closest parent is actually + * the one farther down the graph, since that means it is closer to its child. + * + * @param {string[]} parents + * @returns {string} + */ +const findClosestParent = (parents) => { + let closestParent = ''; + let maxPosition = 0; + + parents.forEach((parent) => { + const parentPosition = dir === 'TB' ? commitPos[parent].y : commitPos[parent].x; + if (parentPosition >= maxPosition) { + closestParent = parent; + maxPosition = parentPosition; + } + }); + + return closestParent; +}; + /** * Draws the commits with its symbol and labels. The function has two modes, one which only * calculates the positions and one that does the actual drawing. This for a simple way getting the @@ -87,9 +110,18 @@ const drawCommits = (svg, commits, modifyGraph) => { const sortedKeys = keys.sort((a, b) => { return commits[a].seq - commits[b].seq; }); + + const isParallelCommits = getConfig().gitGraph.parallelCommits; sortedKeys.forEach((key) => { const commit = commits[key]; + if (isParallelCommits) { + if (commit.parents.length) { + const closestParent = findClosestParent(commit.parents, commits); + pos = dir === 'TB' ? commitPos[closestParent].y + 40 : commitPos[closestParent].x + 40; + } + } + const y = dir === 'TB' ? pos + 10 : branchPos[commit.branch].pos; const x = dir === 'TB' ? branchPos[commit.branch].pos : pos + 10; From eb3e924c440cde93255b42f65f01ec09d7c6c582 Mon Sep 17 00:00:00 2001 From: Matheus B Date: Fri, 22 Dec 2023 21:11:50 -0300 Subject: [PATCH 03/13] Add tests for gitGraph with parallel commits --- .../integration/rendering/gitGraph.spec.js | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/cypress/integration/rendering/gitGraph.spec.js b/cypress/integration/rendering/gitGraph.spec.js index 2aab34c34..339a5f028 100644 --- a/cypress/integration/rendering/gitGraph.spec.js +++ b/cypress/integration/rendering/gitGraph.spec.js @@ -811,4 +811,61 @@ gitGraph TB: {} ); }); + it('40: should render default GitGraph with parallelCommits set to false', () => { + imgSnapshotTest( + `gitGraph + commit id:"1-abcdefg" + commit id:"2-abcdefg" + branch develop + commit id:"3-abcdefg" + commit id:"4-abcdefg" + checkout main + branch feature + commit id:"5-abcdefg" + commit id:"6-abcdefg" + checkout main + commit id:"7-abcdefg" + commit id:"8-abcdefg" + `, + { gitGraph: { parallelCommits: false } } + ); + }); + it('41: should render GitGraph with parallel commits', () => { + imgSnapshotTest( + `gitGraph + commit id:"1-abcdefg" + commit id:"2-abcdefg" + branch develop + commit id:"3-abcdefg" + commit id:"4-abcdefg" + checkout main + branch feature + commit id:"5-abcdefg" + commit id:"6-abcdefg" + checkout main + commit id:"7-abcdefg" + commit id:"8-abcdefg" + `, + { gitGraph: { parallelCommits: true } } + ); + }); + it('42: should render GitGraph with parallel commits | Vertical Branch', () => { + imgSnapshotTest( + `gitGraph TB: + commit id:"1-abcdefg" + commit id:"2-abcdefg" + branch develop + commit id:"3-abcdefg" + commit id:"4-abcdefg" + checkout main + branch feature + commit id:"5-abcdefg" + commit id:"6-abcdefg" + checkout main + commit id:"7-abcdefg" + commit id:"8-abcdefg" + `, + { gitGraph: { parallelCommits: true } } + ); + }); }); From 41f3f9fb322eca07cf947b2b542f14a6e3ccd487 Mon Sep 17 00:00:00 2001 From: Matheus B Date: Fri, 22 Dec 2023 21:48:19 -0300 Subject: [PATCH 04/13] Fix linter issues --- packages/mermaid/src/diagrams/git/gitGraphRenderer.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js index ce2b6c5f6..1aec8ebd8 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js +++ b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js @@ -115,11 +115,9 @@ const drawCommits = (svg, commits, modifyGraph) => { sortedKeys.forEach((key) => { const commit = commits[key]; - if (isParallelCommits) { - if (commit.parents.length) { - const closestParent = findClosestParent(commit.parents, commits); - pos = dir === 'TB' ? commitPos[closestParent].y + 40 : commitPos[closestParent].x + 40; - } + if (isParallelCommits && commit.parents.length) { + const closestParent = findClosestParent(commit.parents, commits); + pos = dir === 'TB' ? commitPos[closestParent].y + 40 : commitPos[closestParent].x + 40; } const y = dir === 'TB' ? pos + 10 : branchPos[commit.branch].pos; From c50a82a60e11550166a21850b1c53580210d1b15 Mon Sep 17 00:00:00 2001 From: Matheus B Date: Fri, 22 Dec 2023 21:52:19 -0300 Subject: [PATCH 05/13] Build config types --- packages/mermaid/src/config.type.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/mermaid/src/config.type.ts b/packages/mermaid/src/config.type.ts index a5bc22f6f..575f428dd 100644 --- a/packages/mermaid/src/config.type.ts +++ b/packages/mermaid/src/config.type.ts @@ -576,6 +576,7 @@ export interface GitGraphDiagramConfig extends BaseDiagramConfig { showCommitLabel?: boolean; showBranches?: boolean; rotateCommitLabel?: boolean; + parallelCommits?: boolean; /** * Controls whether or arrow markers in html code are absolute paths or anchors. * This matters if you are using base tag settings. From 6f09bc7dc7a2082cba861ccfec3f635e3e4d09ba Mon Sep 17 00:00:00 2001 From: Matheus B Date: Tue, 16 Jan 2024 19:34:16 -0300 Subject: [PATCH 06/13] Use already defined const instead of method call --- packages/mermaid/src/diagrams/git/gitGraphRenderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js index 1aec8ebd8..47b8afaad 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js +++ b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js @@ -111,7 +111,7 @@ const drawCommits = (svg, commits, modifyGraph) => { return commits[a].seq - commits[b].seq; }); - const isParallelCommits = getConfig().gitGraph.parallelCommits; + const isParallelCommits = gitGraphConfig.parallelCommits; sortedKeys.forEach((key) => { const commit = commits[key]; From bf1edd99f9c2cb68e7ba2e424b66045f2932a988 Mon Sep 17 00:00:00 2001 From: Matheus B Date: Tue, 16 Jan 2024 19:37:52 -0300 Subject: [PATCH 07/13] Remove unnecessary argument on findClosestParent call --- packages/mermaid/src/diagrams/git/gitGraphRenderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js index 47b8afaad..d14404db4 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js +++ b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js @@ -116,7 +116,7 @@ const drawCommits = (svg, commits, modifyGraph) => { const commit = commits[key]; if (isParallelCommits && commit.parents.length) { - const closestParent = findClosestParent(commit.parents, commits); + const closestParent = findClosestParent(commit.parents); pos = dir === 'TB' ? commitPos[closestParent].y + 40 : commitPos[closestParent].x + 40; } From 02246f64d2ae39150bba9476ffb3cf2eaf7414cf Mon Sep 17 00:00:00 2001 From: Matheus B Date: Tue, 16 Jan 2024 20:01:03 -0300 Subject: [PATCH 08/13] Include undefined on findClosestParent return types and update the function --- packages/mermaid/src/diagrams/git/gitGraphRenderer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js index d14404db4..f9df1db34 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js +++ b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js @@ -70,7 +70,7 @@ const drawText = (txt) => { * the one farther down the graph, since that means it is closer to its child. * * @param {string[]} parents - * @returns {string} + * @returns {string | undefined} */ const findClosestParent = (parents) => { let closestParent = ''; @@ -84,7 +84,7 @@ const findClosestParent = (parents) => { } }); - return closestParent; + return closestParent || undefined; }; /** From c77a6e156c6fe30c2851019dba74bbad76bd5ef7 Mon Sep 17 00:00:00 2001 From: Matheus B Date: Tue, 16 Jan 2024 20:54:26 -0300 Subject: [PATCH 09/13] Include logic for gitgraph with unconnected branches --- .../mermaid/src/diagrams/git/gitGraphRenderer.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js index f9df1db34..4790949b5 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js +++ b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js @@ -115,9 +115,16 @@ const drawCommits = (svg, commits, modifyGraph) => { sortedKeys.forEach((key) => { const commit = commits[key]; - if (isParallelCommits && commit.parents.length) { - const closestParent = findClosestParent(commit.parents); - pos = dir === 'TB' ? commitPos[closestParent].y + 40 : commitPos[closestParent].x + 40; + if (isParallelCommits) { + if (!commit.parents.length) { + pos = 0; + if (dir === 'TB') { + pos = 30; + } + } else { + const closestParent = findClosestParent(commit.parents); + pos = dir === 'TB' ? commitPos[closestParent].y + 40 : commitPos[closestParent].x + 40; + } } const y = dir === 'TB' ? pos + 10 : branchPos[commit.branch].pos; From 9213afbacd0932cc54e229e845909e1b034398b9 Mon Sep 17 00:00:00 2001 From: Matheus B Date: Tue, 16 Jan 2024 20:55:42 -0300 Subject: [PATCH 10/13] Add tests for gitgraphs with unconnected branches --- .../integration/rendering/gitGraph.spec.js | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/cypress/integration/rendering/gitGraph.spec.js b/cypress/integration/rendering/gitGraph.spec.js index a2836c51a..19ddde31d 100644 --- a/cypress/integration/rendering/gitGraph.spec.js +++ b/cypress/integration/rendering/gitGraph.spec.js @@ -883,4 +883,64 @@ gitGraph TB: { gitGraph: { parallelCommits: true } } ); }); + it('44: should render GitGraph with unconnected branches and no parallel commits', () => { + imgSnapshotTest( + `gitGraph + branch dev + branch v2 + branch feat + commit id:"1-abcdefg" + commit id:"2-abcdefg" + checkout main + commit id:"3-abcdefg" + checkout dev + commit id:"4-abcdefg" + checkout v2 + commit id:"5-abcdefg" + checkout main + commit id:"6-abcdefg" + `, + { gitGraph: { parallelCommits: false } } + ); + }); + it('45: should render GitGraph with unconnected branches and parallel commits', () => { + imgSnapshotTest( + `gitGraph + branch dev + branch v2 + branch feat + commit id:"1-abcdefg" + commit id:"2-abcdefg" + checkout main + commit id:"3-abcdefg" + checkout dev + commit id:"4-abcdefg" + checkout v2 + commit id:"5-abcdefg" + checkout main + commit id:"6-abcdefg" + `, + { gitGraph: { parallelCommits: true } } + ); + }); + it('46: should render GitGraph with unconnected branches and parallel commits | Vertical Branch', () => { + imgSnapshotTest( + `gitGraph TB: + branch dev + branch v2 + branch feat + commit id:"1-abcdefg" + commit id:"2-abcdefg" + checkout main + commit id:"3-abcdefg" + checkout dev + commit id:"4-abcdefg" + checkout v2 + commit id:"5-abcdefg" + checkout main + commit id:"6-abcdefg" + `, + { gitGraph: { parallelCommits: true } } + ); + }); }); From 4f60a2747256f11902b5dc3bf19d55654205c772 Mon Sep 17 00:00:00 2001 From: Matheus B Date: Sat, 20 Jan 2024 20:57:58 -0300 Subject: [PATCH 11/13] Change repetitive values into consts --- .../src/diagrams/git/gitGraphRenderer.js | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js index 4790949b5..6124d72c6 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js +++ b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js @@ -112,8 +112,11 @@ const drawCommits = (svg, commits, modifyGraph) => { }); const isParallelCommits = gitGraphConfig.parallelCommits; + const layoutOffset = 10; + const commitStep = 40; sortedKeys.forEach((key) => { const commit = commits[key]; + const posWithOffset = pos + layoutOffset; if (isParallelCommits) { if (!commit.parents.length) { @@ -123,12 +126,15 @@ const drawCommits = (svg, commits, modifyGraph) => { } } else { const closestParent = findClosestParent(commit.parents); - pos = dir === 'TB' ? commitPos[closestParent].y + 40 : commitPos[closestParent].x + 40; + pos = + dir === 'TB' + ? commitPos[closestParent].y + commitStep + : commitPos[closestParent].x + commitStep; } } - const y = dir === 'TB' ? pos + 10 : branchPos[commit.branch].pos; - const x = dir === 'TB' ? branchPos[commit.branch].pos : pos + 10; + const y = dir === 'TB' ? posWithOffset : branchPos[commit.branch].pos; + const x = dir === 'TB' ? branchPos[commit.branch].pos : posWithOffset; // Don't draw the commits now but calculate the positioning which is used by the branch lines etc. if (modifyGraph) { @@ -253,9 +259,9 @@ const drawCommits = (svg, commits, modifyGraph) => { } } if (dir === 'TB') { - commitPos[commit.id] = { x: x, y: pos + 10 }; + commitPos[commit.id] = { x: x, y: posWithOffset }; } else { - commitPos[commit.id] = { x: pos + 10, y: y }; + commitPos[commit.id] = { x: posWithOffset, y: y }; } // The first iteration over the commits are for positioning purposes, this @@ -284,7 +290,7 @@ const drawCommits = (svg, commits, modifyGraph) => { // Now we have the label, lets position the background labelBkg - .attr('x', pos + 10 - bbox.width / 2 - py) + .attr('x', posWithOffset - bbox.width / 2 - py) .attr('y', y + 13.5) .attr('width', bbox.width + 2 * py) .attr('height', bbox.height + 2 * py); @@ -295,7 +301,7 @@ const drawCommits = (svg, commits, modifyGraph) => { } if (dir !== 'TB') { - text.attr('x', pos + 10 - bbox.width / 2); + text.attr('x', posWithOffset - bbox.width / 2); } if (gitGraphConfig.rotateCommitLabel) { if (dir === 'TB') { @@ -321,7 +327,7 @@ const drawCommits = (svg, commits, modifyGraph) => { .attr('class', 'tag-label') .text(commit.tag); let tagBbox = tag.node().getBBox(); - tag.attr('x', pos + 10 - tagBbox.width / 2); + tag.attr('x', posWithOffset - tagBbox.width / 2); const h2 = tagBbox.height / 2; const ly = y - 19.2; @@ -330,10 +336,10 @@ const drawCommits = (svg, commits, modifyGraph) => { ` ${pos - tagBbox.width / 2 - px / 2},${ly + py} ${pos - tagBbox.width / 2 - px / 2},${ly - py} - ${pos + 10 - tagBbox.width / 2 - px},${ly - h2 - py} - ${pos + 10 + tagBbox.width / 2 + px},${ly - h2 - py} - ${pos + 10 + tagBbox.width / 2 + px},${ly + h2 + py} - ${pos + 10 - tagBbox.width / 2 - px},${ly + h2 + py}` + ${posWithOffset - tagBbox.width / 2 - px},${ly - h2 - py} + ${posWithOffset + tagBbox.width / 2 + px},${ly - h2 - py} + ${posWithOffset + tagBbox.width / 2 + px},${ly + h2 + py} + ${posWithOffset - tagBbox.width / 2 - px},${ly + h2 + py}` ); hole @@ -350,10 +356,10 @@ const drawCommits = (svg, commits, modifyGraph) => { ` ${x},${pos + py} ${x},${pos - py} - ${x + 10},${pos - h2 - py} - ${x + 10 + tagBbox.width + px},${pos - h2 - py} - ${x + 10 + tagBbox.width + px},${pos + h2 + py} - ${x + 10},${pos + h2 + py}` + ${x + layoutOffset},${pos - h2 - py} + ${x + layoutOffset + tagBbox.width + px},${pos - h2 - py} + ${x + layoutOffset + tagBbox.width + px},${pos + h2 + py} + ${x + layoutOffset},${pos + h2 + py}` ) .attr('transform', 'translate(12,12) rotate(45, ' + x + ',' + pos + ')'); hole @@ -367,7 +373,7 @@ const drawCommits = (svg, commits, modifyGraph) => { } } } - pos += 50; + pos += commitStep + layoutOffset; if (pos > maxPos) { maxPos = pos; } From e668698b5c5510c2f1ff9a6cc875d0dbdf413de2 Mon Sep 17 00:00:00 2001 From: Matheus B Date: Mon, 22 Jan 2024 19:56:25 -0300 Subject: [PATCH 12/13] Reposition const declaration to ideal place --- packages/mermaid/src/diagrams/git/gitGraphRenderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js index 6124d72c6..cefbe89c1 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js +++ b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js @@ -116,7 +116,6 @@ const drawCommits = (svg, commits, modifyGraph) => { const commitStep = 40; sortedKeys.forEach((key) => { const commit = commits[key]; - const posWithOffset = pos + layoutOffset; if (isParallelCommits) { if (!commit.parents.length) { @@ -133,6 +132,7 @@ const drawCommits = (svg, commits, modifyGraph) => { } } + const posWithOffset = pos + layoutOffset; const y = dir === 'TB' ? posWithOffset : branchPos[commit.branch].pos; const x = dir === 'TB' ? branchPos[commit.branch].pos : posWithOffset; From 81825f22f508eee53a9ab809361935d52bc3caf0 Mon Sep 17 00:00:00 2001 From: Matheus B Date: Mon, 22 Jan 2024 20:09:20 -0300 Subject: [PATCH 13/13] Swap condition blocks to avoid using negation --- .../mermaid/src/diagrams/git/gitGraphRenderer.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js index cefbe89c1..84b8f41a1 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js +++ b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js @@ -118,17 +118,17 @@ const drawCommits = (svg, commits, modifyGraph) => { const commit = commits[key]; if (isParallelCommits) { - if (!commit.parents.length) { - pos = 0; - if (dir === 'TB') { - pos = 30; - } - } else { + if (commit.parents.length) { const closestParent = findClosestParent(commit.parents); pos = dir === 'TB' ? commitPos[closestParent].y + commitStep : commitPos[closestParent].x + commitStep; + } else { + pos = 0; + if (dir === 'TB') { + pos = 30; + } } }