From 3ae8639a54ffa8f2d12329a9023fd042cd298a64 Mon Sep 17 00:00:00 2001 From: Lars Westermann Date: Tue, 6 Dec 2022 11:42:05 +0100 Subject: [PATCH 01/17] Fix link hover stroke opacity --- src/Blazor.Diagrams/Components/LinkWidget.razor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Blazor.Diagrams/Components/LinkWidget.razor.cs b/src/Blazor.Diagrams/Components/LinkWidget.razor.cs index 6eb3a51a1..31850326d 100644 --- a/src/Blazor.Diagrams/Components/LinkWidget.razor.cs +++ b/src/Blazor.Diagrams/Components/LinkWidget.razor.cs @@ -23,7 +23,7 @@ private RenderFragment GetSelectionHelperPath(string color, string d, int index) builder.AddAttribute(3, "stroke-width", 12); builder.AddAttribute(4, "d", d); builder.AddAttribute(5, "stroke-linecap", "butt"); - builder.AddAttribute(6, "stroke-opacity", _hovered ? 0.05 : 0); + builder.AddAttribute(6, "stroke-opacity", _hovered ? "0.05" : "0"); builder.AddAttribute(7, "fill", "none"); builder.AddAttribute(8, "onmouseenter", EventCallback.Factory.Create(this, OnMouseEnter)); builder.AddAttribute(9, "onmouseleave", EventCallback.Factory.Create(this, OnMouseLeave)); @@ -60,4 +60,4 @@ private LinkVertexModel CreateVertex(double clientX, double clientY, int index) Link.Refresh(); return vertex; } -} \ No newline at end of file +} From 4cfc10feaa65e4bf72cb57ef836c997917224bd2 Mon Sep 17 00:00:00 2001 From: Haytam Zanid Date: Sat, 30 Sep 2023 11:12:58 +0100 Subject: [PATCH 02/17] Add Radius example to Path Generators documentation --- .../Pages/Documentation/Links/PathGenerators.razor | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/site/Site/Pages/Documentation/Links/PathGenerators.razor b/site/Site/Pages/Documentation/Links/PathGenerators.razor index 4b78263ce..4589d5052 100644 --- a/site/Site/Pages/Documentation/Links/PathGenerators.razor +++ b/site/Site/Pages/Documentation/Links/PathGenerators.razor @@ -35,7 +35,8 @@ link.PathGenerator = new SmoothPathGenerator();

Straight Path Generator

- The StraightPathGenerator generates straight lines. + The StraightPathGenerator generates straight lines.
+ You can also choose a radius for when the path contains vertices or direction changes.

Usage

@@ -78,12 +79,13 @@ link.PathGenerator = new StraightPathGenerator(); // Straight Path Generator var stpgNode1 = _stpgDiagram.Nodes.Add(new NodeModel(new Point(150, 50))); var stpgNode2 = _stpgDiagram.Nodes.Add(new NodeModel(new Point(450, 110))); - var stpgBottomPort1 = stpgNode1.AddPort(PortAlignment.BottomRight); + var stpgBottomPort1 = stpgNode1.AddPort(PortAlignment.Bottom); var stpgRightPort1 = stpgNode1.AddPort(PortAlignment.Right); var stpgBottomPort2 = stpgNode2.AddPort(PortAlignment.BottomLeft); var stpgLeftPort2 = stpgNode2.AddPort(PortAlignment.Left); - _stpgDiagram.Links.Add(new LinkModel(stpgBottomPort1, stpgBottomPort2)).PathGenerator = new StraightPathGenerator(); _stpgDiagram.Links.Add(new LinkModel(stpgRightPort1, stpgLeftPort2)).PathGenerator = new StraightPathGenerator(); - + var link = _stpgDiagram.Links.Add(new LinkModel(stpgBottomPort1, stpgBottomPort2)); + link.PathGenerator = new StraightPathGenerator(10); + link.AddVertex(new Point(200, 250)); } } \ No newline at end of file From 832a030a3f96c0bf91fb3c7ed741f3279b754f88 Mon Sep 17 00:00:00 2001 From: Suraj Date: Mon, 16 Oct 2023 12:09:20 +0530 Subject: [PATCH 03/17] fix type of diagram --- docs/Diagram-Demo/Pages/Diagrams.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Diagram-Demo/Pages/Diagrams.razor b/docs/Diagram-Demo/Pages/Diagrams.razor index 2c56d7ef7..305809e73 100644 --- a/docs/Diagram-Demo/Pages/Diagrams.razor +++ b/docs/Diagram-Demo/Pages/Diagrams.razor @@ -28,7 +28,7 @@ or it will not be rendered. @code { - private Diagram Diagram { get; set; } + private BlazorDiagram Diagram { get; set; } protected override void OnInitialized() { From 240320696a928558ff3937515aa7e9a686bc6e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20Z=C3=B6bl?= <41567572+K0369@users.noreply.github.com> Date: Mon, 16 Oct 2023 12:01:37 +0200 Subject: [PATCH 04/17] Adding check for target being a portModel --- site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs b/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs index 835c8fdcd..2de170860 100644 --- a/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs +++ b/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs @@ -76,7 +76,7 @@ private void OnLinKTargetChanged(BaseLinkModel link, Anchor? oldTarget, Anchor? private void OnLinkRemoved(BaseLinkModel link) { (link.Source.Model as PortModel)!.Parent.Refresh(); - if (link.Target != null) (link.Target.Model as PortModel)!.Parent.Refresh(); + if (link.Target != null && link.Target.Model is PortModel portModel) portModel.Parent.Refresh(); link.TargetChanged -= OnLinKTargetChanged; } } \ No newline at end of file From 93b154baa10ecc4e12c1ec1a60ac30475d393b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20Z=C3=B6bl?= <41567572+K0369@users.noreply.github.com> Date: Mon, 16 Oct 2023 12:02:50 +0200 Subject: [PATCH 05/17] Fixing nodes not updating on change of the link target --- site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs b/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs index 2de170860..4e5717172 100644 --- a/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs +++ b/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs @@ -67,7 +67,7 @@ private void OnLinkAdded(BaseLinkModel link) private void OnLinKTargetChanged(BaseLinkModel link, Anchor? oldTarget, Anchor? newTarget) { - if (oldTarget == null && newTarget != null) // First attach + if (link.IsAttached && newTarget is not null) { (newTarget.Model as PortModel)!.Parent.Refresh(); } From ff0fd5a0d07021e5cf224a57659ebdf14a37cc72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20Z=C3=B6bl?= <41567572+K0369@users.noreply.github.com> Date: Sun, 22 Oct 2023 13:53:58 +0200 Subject: [PATCH 06/17] fixing NRE of onLinkRemoved in landing showcase diagram --- site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs b/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs index 4e5717172..c78b72851 100644 --- a/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs +++ b/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs @@ -76,7 +76,10 @@ private void OnLinKTargetChanged(BaseLinkModel link, Anchor? oldTarget, Anchor? private void OnLinkRemoved(BaseLinkModel link) { (link.Source.Model as PortModel)!.Parent.Refresh(); - if (link.Target != null && link.Target.Model is PortModel portModel) portModel.Parent.Refresh(); + if (link.Target is SinglePortAnchor anchor && anchor.Model is PortModel portModel) + { + portModel.Parent.Refresh(); + } link.TargetChanged -= OnLinKTargetChanged; } } \ No newline at end of file From 95a9734b6a518c740114774041780da529a687fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20Z=C3=B6bl?= <41567572+K0369@users.noreply.github.com> Date: Sun, 22 Oct 2023 14:24:55 +0200 Subject: [PATCH 07/17] refactoring link target refreshing in landing showcase diagram --- .../Components/Landing/LandingShowcaseDiagram.razor.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs b/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs index c78b72851..17ffd29ba 100644 --- a/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs +++ b/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs @@ -67,9 +67,12 @@ private void OnLinkAdded(BaseLinkModel link) private void OnLinKTargetChanged(BaseLinkModel link, Anchor? oldTarget, Anchor? newTarget) { - if (link.IsAttached && newTarget is not null) + // only refresh on the first time the link is attached + if (oldTarget is PositionAnchor + && newTarget.Model is PortModel targetModel + && link.IsAttached) { - (newTarget.Model as PortModel)!.Parent.Refresh(); + targetModel.Parent.Refresh(); } } From f1032af5db2120ec9ffeee7845559f075f3d655b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20Z=C3=B6bl?= <41567572+K0369@users.noreply.github.com> Date: Sun, 22 Oct 2023 14:27:04 +0200 Subject: [PATCH 08/17] Demo-site: changing signature of onChange to reflect actual values --- site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs b/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs index 17ffd29ba..d2933a427 100644 --- a/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs +++ b/site/Site/Components/Landing/LandingShowcaseDiagram.razor.cs @@ -65,7 +65,7 @@ private void OnLinkAdded(BaseLinkModel link) link.TargetChanged += OnLinKTargetChanged; } - private void OnLinKTargetChanged(BaseLinkModel link, Anchor? oldTarget, Anchor? newTarget) + private void OnLinKTargetChanged(BaseLinkModel link, Anchor oldTarget, Anchor newTarget) { // only refresh on the first time the link is attached if (oldTarget is PositionAnchor From 9836fa34befef483973baf07ec663c9a9a73819a Mon Sep 17 00:00:00 2001 From: Haytam Zanid Date: Sun, 22 Oct 2023 19:06:36 +0100 Subject: [PATCH 09/17] Add Route property to BaseLinkModel --- .../Models/Base/BaseLinkModel.cs | 3 +++ src/Blazor.Diagrams/wwwroot/script.js | 5 +++-- src/Blazor.Diagrams/wwwroot/script.min.js | 2 +- src/Blazor.Diagrams/wwwroot/script.min.js.gz | Bin 520 -> 521 bytes 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Blazor.Diagrams.Core/Models/Base/BaseLinkModel.cs b/src/Blazor.Diagrams.Core/Models/Base/BaseLinkModel.cs index acba5848e..26a28dae2 100644 --- a/src/Blazor.Diagrams.Core/Models/Base/BaseLinkModel.cs +++ b/src/Blazor.Diagrams.Core/Models/Base/BaseLinkModel.cs @@ -30,6 +30,7 @@ protected BaseLinkModel(string id, Anchor source, Anchor target) : base(id) public Anchor Source { get; private set; } public Anchor Target { get; private set; } public Diagram? Diagram { get; internal set; } + public Point[]? Route { get; private set; } public PathGeneratorResult? PathGeneratorResult { get; private set; } public bool IsAttached => Source is not PositionAnchor && Target is not PositionAnchor; public Router? Router { get; set; } @@ -129,11 +130,13 @@ private void GeneratePath() var target = Target.GetPosition(this, route); if (source != null && target != null) { + Route = route; PathGeneratorResult = pathGenerator.GetResult(Diagram, this, route, source, target); return; } } + Route = null; PathGeneratorResult = null; } diff --git a/src/Blazor.Diagrams/wwwroot/script.js b/src/Blazor.Diagrams/wwwroot/script.js index 293b8768d..be3b4728c 100644 --- a/src/Blazor.Diagrams/wwwroot/script.js +++ b/src/Blazor.Diagrams/wwwroot/script.js @@ -40,8 +40,9 @@ var s = { } }, unobserve: (element, id) => { - if (!element) return; - s.ro.unobserve(element); + if (element) { + s.ro.unobserve(element); + } delete s.tracked[id]; delete s.canvases[id]; } diff --git a/src/Blazor.Diagrams/wwwroot/script.min.js b/src/Blazor.Diagrams/wwwroot/script.min.js index f295e538c..a4065277c 100644 --- a/src/Blazor.Diagrams/wwwroot/script.min.js +++ b/src/Blazor.Diagrams/wwwroot/script.min.js @@ -1 +1 @@ -var s={canvases:{},tracked:{},getBoundingClientRect:n=>n.getBoundingClientRect(),mo:new MutationObserver(()=>{for(id in s.canvases){const t=s.canvases[id],i=t.lastBounds,n=t.elem.getBoundingClientRect();(i.left!==n.left||i.top!==n.top||i.width!==n.width||i.height!==n.height)&&(t.lastBounds=n,t.ref.invokeMethodAsync("OnResize",n))}}),ro:new ResizeObserver(n=>{for(const t of n){let i=Array.from(t.target.attributes).find(n=>n.name.startsWith("_bl")).name.substring(4),n=s.tracked[i];n&&n.ref.invokeMethodAsync("OnResize",t.target.getBoundingClientRect())}}),observe:(n,t,i)=>{n&&(s.ro.observe(n),s.tracked[i]={ref:t},n.classList.contains("diagram-canvas")&&(s.canvases[i]={elem:n,ref:t,lastBounds:n.getBoundingClientRect()}))},unobserve:(n,t)=>{n&&(s.ro.unobserve(n),delete s.tracked[t],delete s.canvases[t])}};window.ZBlazorDiagrams=s;window.addEventListener("scroll",()=>{for(id in s.canvases){const n=s.canvases[id];n.lastBounds=n.elem.getBoundingClientRect();n.ref.invokeMethodAsync("OnResize",n.lastBounds)}});s.mo.observe(document.body,{childList:!0,subtree:!0}); \ No newline at end of file +var s={canvases:{},tracked:{},getBoundingClientRect:n=>n.getBoundingClientRect(),mo:new MutationObserver(()=>{for(id in s.canvases){const t=s.canvases[id],i=t.lastBounds,n=t.elem.getBoundingClientRect();(i.left!==n.left||i.top!==n.top||i.width!==n.width||i.height!==n.height)&&(t.lastBounds=n,t.ref.invokeMethodAsync("OnResize",n))}}),ro:new ResizeObserver(n=>{for(const t of n){let i=Array.from(t.target.attributes).find(n=>n.name.startsWith("_bl")).name.substring(4),n=s.tracked[i];n&&n.ref.invokeMethodAsync("OnResize",t.target.getBoundingClientRect())}}),observe:(n,t,i)=>{n&&(s.ro.observe(n),s.tracked[i]={ref:t},n.classList.contains("diagram-canvas")&&(s.canvases[i]={elem:n,ref:t,lastBounds:n.getBoundingClientRect()}))},unobserve:(n,t)=>{n&&s.ro.unobserve(n),delete s.tracked[t],delete s.canvases[t]}};window.ZBlazorDiagrams=s;window.addEventListener("scroll",()=>{for(id in s.canvases){const n=s.canvases[id];n.lastBounds=n.elem.getBoundingClientRect();n.ref.invokeMethodAsync("OnResize",n.lastBounds)}});s.mo.observe(document.body,{childList:!0,subtree:!0}); \ No newline at end of file diff --git a/src/Blazor.Diagrams/wwwroot/script.min.js.gz b/src/Blazor.Diagrams/wwwroot/script.min.js.gz index e444f12bdf743d6e9412c5556505e665bd16d3f3..a4db964787449a2e8b2e14e006712d8890102ecb 100644 GIT binary patch delta 503 zcmV2*)vhHMx zH2L1+!S`)#ygZv$goUH6p_%$dwV7Ue4>?@JF6GgRl?qkl6S;S|b7#|b71pr>tY zdkJ~XoNR1`S4zPcyu3Jx{>S*HZ+ae_!Fo)LQA*X;?dqv%3i)cqmcR-G%3v$$VDF#o zoyFRln|Oqh<@fMlqkFcw0M3Vji!iC5vM22@OP_^izRH02jm6BVn-KI-R>8M~iaL-w zsS$(Qc1X*Sm45@127mUJNALos-m1-d~};NtXA;0 zf)o0M{f_$lB&lGu6ycJkG@L~lyqrr6xLBgAo{$S11jv$>8o#)Rk`{s5L1ejcdKYy2 zZgM_P%U_-WwI|OD5aSeawxzguf&)<%9W1HNL`R;dN^oLoXgb>LOc*!k+=&KmhGBgm zBm6;ryKVHd51%I9QN`DSHs( z(&Xdgd%u7F+M1BXa;OY$O@vqsdqu%i4`5Tc0lM}*T8EpDtplVxsHnj567^q8LaNRe z2)pd2CqvHT?K(o(LJ&fhmqYD?a5i(8Mg0OPhstB5jLK8)-hbJZawX~3#0e%UD9R;CdANu=czq}dlxmJ%4vbvTUZJk|sPT)7r1=nJ97d5_XEwof z?V1_;|a3U#`=0665XKbNU6STO_u03Qzg>;M1& From 6321a2951fed858f8fad972c31bb4b079bd563a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20Z=C3=B6bl?= <41567572+K0369@users.noreply.github.com> Date: Mon, 23 Oct 2023 16:46:12 +0200 Subject: [PATCH 10/17] Adding check for "ShouldDelete"-constraint to remove control --- .../Controls/Default/RemoveControl.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Blazor.Diagrams.Core/Controls/Default/RemoveControl.cs b/src/Blazor.Diagrams.Core/Controls/Default/RemoveControl.cs index 1e1704256..b9dacfc8a 100644 --- a/src/Blazor.Diagrams.Core/Controls/Default/RemoveControl.cs +++ b/src/Blazor.Diagrams.Core/Controls/Default/RemoveControl.cs @@ -23,18 +23,25 @@ public RemoveControl(IPositionProvider positionProvider) public override Point? GetPosition(Model model) => _positionProvider.GetPosition(model); - public override ValueTask OnPointerDown(Diagram diagram, Model model, PointerEventArgs _) + public override async ValueTask OnPointerDown(Diagram diagram, Model model, PointerEventArgs _) { switch (model) { + case NodeModel node: - diagram.Nodes.Remove(node); + if (await diagram.Options.Constraints.ShouldDeleteNode.Invoke(node)) + { + diagram.Nodes.Remove(node); + } break; case BaseLinkModel link: - diagram.Links.Remove(link); + if (await diagram.Options.Constraints.ShouldDeleteLink.Invoke(link)) + { + diagram.Links.Remove(link); + } break; - } - return ValueTask.CompletedTask; + + } } } \ No newline at end of file From 58bcdb33d93706c02d3b694cc86422472c9acf94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20Z=C3=B6bl?= <41567572+K0369@users.noreply.github.com> Date: Mon, 23 Oct 2023 16:47:30 +0200 Subject: [PATCH 11/17] Adding unit tests --- .../Controls/RemoveControlTests.cs | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 tests/Blazor.Diagrams.Core.Tests/Controls/RemoveControlTests.cs diff --git a/tests/Blazor.Diagrams.Core.Tests/Controls/RemoveControlTests.cs b/tests/Blazor.Diagrams.Core.Tests/Controls/RemoveControlTests.cs new file mode 100644 index 000000000..e24fce0ba --- /dev/null +++ b/tests/Blazor.Diagrams.Core.Tests/Controls/RemoveControlTests.cs @@ -0,0 +1,179 @@ +using Blazor.Diagrams.Core.Controls.Default; +using Blazor.Diagrams.Core.Events; +using Blazor.Diagrams.Core.Geometry; +using Blazor.Diagrams.Core.Models; +using Blazor.Diagrams.Core.Models.Base; +using Moq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Blazor.Diagrams.Core.Tests.Controls +{ + public class RemoveControlTests + { + public PointerEventArgs PointerEventArgs + => new(100, 100, 0, 0, false, false, false, 0, 0, 0, 0, 0, 0, string.Empty, true); + + [Fact] + public async Task OnPointerDown_NoConstraints_RemovesNode() + { + // Arrange + RemoveControl removeControl = new(0, 0); + Diagram diagram = new TestDiagram(); + var nodeMock = new Mock(Point.Zero); + var node = diagram.Nodes.Add(nodeMock.Object); + + // Act + await removeControl.OnPointerDown(diagram, node, PointerEventArgs); + + // Assert + Assert.Empty(diagram.Nodes); + } + + [Fact] + public async Task OnPointerDown_ShouldDeleteNodeTrue_RemovesNode() + { + // Arrange + RemoveControl removeControl = new(0, 0); + Diagram diagram = new TestDiagram( + new Options.DiagramOptions + { + Constraints = + { + ShouldDeleteNode = (node) => ValueTask.FromResult(true) + } + }); + var nodeMock = new Mock(Point.Zero); + var node = diagram.Nodes.Add(nodeMock.Object); + + // Act + await removeControl.OnPointerDown(diagram, node, PointerEventArgs); + + // Assert + Assert.Empty(diagram.Nodes); + } + + [Fact] + public async Task OnPointerDown_ShouldDeleteNodeFalse_KeepsNode() + { + // Arrange + RemoveControl removeControl = new(0, 0); + Diagram diagram = new TestDiagram( + new Options.DiagramOptions + { + Constraints = + { + ShouldDeleteNode = (node) => ValueTask.FromResult(false) + } + }); + var nodeMock = new Mock(Point.Zero); + var node = diagram.Nodes.Add(nodeMock.Object); + + // Act + await removeControl.OnPointerDown(diagram, node, PointerEventArgs); + + // Assert + Assert.Contains(node, diagram.Nodes); + } + + [Fact] + public async Task OnPointerDown_NoConstraints_RemovesLink() + { + // Arrange + RemoveControl removeControl = new(0, 0); + Diagram diagram = new TestDiagram(); + + var node1 = new NodeModel(new Point(50, 50)); + var node2 = new NodeModel(new Point(300, 300)); + diagram.Nodes.Add(new[] { node1, node2 }); + node1.AddPort(PortAlignment.Right); + node2.AddPort(PortAlignment.Left); + + var link = new LinkModel( + node1.GetPort(PortAlignment.Right)!, + node2.GetPort(PortAlignment.Left)! + ); + + diagram.Links.Add(link); + + // Act + await removeControl.OnPointerDown(diagram, link, PointerEventArgs); + + // Assert + Assert.Empty(diagram.Links); + } + + [Fact] + public async Task OnPointerDown_ShouldDeleteLinkTrue_RemovesLink() + { + // Arrange + RemoveControl removeControl = new(0, 0); + Diagram diagram = new TestDiagram( + new Options.DiagramOptions + { + Constraints = + { + ShouldDeleteLink = (node) => ValueTask.FromResult(true) + } + }); + + var node1 = new NodeModel(new Point(50, 50)); + var node2 = new NodeModel(new Point(300, 300)); + diagram.Nodes.Add(new[] { node1, node2 }); + node1.AddPort(PortAlignment.Right); + node2.AddPort(PortAlignment.Left); + + var link = new LinkModel( + node1.GetPort(PortAlignment.Right)!, + node2.GetPort(PortAlignment.Left)! + ); + + diagram.Links.Add(link); + + // Act + await removeControl.OnPointerDown(diagram, link, PointerEventArgs); + + // Assert + Assert.Empty(diagram.Links); + } + + [Fact] + public async Task OnPointerDown_ShouldDeleteLinkFalse_KeepsLink() + { + // Arrange + RemoveControl removeControl = new(0, 0); + Diagram diagram = new TestDiagram( + new Options.DiagramOptions + { + Constraints = + { + ShouldDeleteLink = (node) => ValueTask.FromResult(false) + } + }); + + var node1 = new NodeModel(new Point(50, 50)); + var node2 = new NodeModel(new Point(300, 300)); + diagram.Nodes.Add(new[] { node1, node2 }); + node1.AddPort(PortAlignment.Right); + node2.AddPort(PortAlignment.Left); + + var link = new LinkModel( + node1.GetPort(PortAlignment.Right)!, + node2.GetPort(PortAlignment.Left)! + ); + + diagram.Links.Add(link); + + // Act + await removeControl.OnPointerDown(diagram, link, PointerEventArgs); + + // Assert + Assert.Contains(link, diagram.Links); + } + + } +} From 27422d0096b917a85b92560e6770d2f6f3f3d6e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20Z=C3=B6bl?= <41567572+K0369@users.noreply.github.com> Date: Mon, 23 Oct 2023 17:28:43 +0200 Subject: [PATCH 12/17] Fixing #369 by adding invariant culture conversion --- .../TestComponents/CustomVertexWidget.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Blazor.Diagrams.Tests/TestComponents/CustomVertexWidget.razor b/tests/Blazor.Diagrams.Tests/TestComponents/CustomVertexWidget.razor index 21bc519c4..73d2b4d8a 100644 --- a/tests/Blazor.Diagrams.Tests/TestComponents/CustomVertexWidget.razor +++ b/tests/Blazor.Diagrams.Tests/TestComponents/CustomVertexWidget.razor @@ -1,6 +1,6 @@ @using Blazor.Diagrams.Core.Models; - + @code { [Parameter] public LinkVertexModel Vertex { get; set; } = null!; From e58624574dfab9f98276bbf3119cf1ebf53b9920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20Z=C3=B6bl?= Date: Thu, 26 Oct 2023 10:03:32 +0200 Subject: [PATCH 13/17] Adding functionality for GroupModel Removal to RemoveControl --- .../Controls/Default/RemoveControl.cs | 43 ++++++--- .../Controls/RemoveControlTests.cs | 93 +++++++++++++++++++ 2 files changed, 124 insertions(+), 12 deletions(-) diff --git a/src/Blazor.Diagrams.Core/Controls/Default/RemoveControl.cs b/src/Blazor.Diagrams.Core/Controls/Default/RemoveControl.cs index b9dacfc8a..9227fcf98 100644 --- a/src/Blazor.Diagrams.Core/Controls/Default/RemoveControl.cs +++ b/src/Blazor.Diagrams.Core/Controls/Default/RemoveControl.cs @@ -25,23 +25,42 @@ public RemoveControl(IPositionProvider positionProvider) public override async ValueTask OnPointerDown(Diagram diagram, Model model, PointerEventArgs _) { - switch (model) + if (await ShouldDeleteModel(diagram, model)) { + DeleteModel(diagram, model); + } + } + private static void DeleteModel(Diagram diagram, Model model) + { + switch (model) + { + case GroupModel group: + diagram.Groups.Delete(group); + return; case NodeModel node: - if (await diagram.Options.Constraints.ShouldDeleteNode.Invoke(node)) - { - diagram.Nodes.Remove(node); - } - break; + diagram.Nodes.Remove(node); + return; + case BaseLinkModel link: - if (await diagram.Options.Constraints.ShouldDeleteLink.Invoke(link)) - { - diagram.Links.Remove(link); - } - break; + diagram.Links.Remove(link); + return; + } + } - + private static async ValueTask ShouldDeleteModel(Diagram diagram, Model model) + { + if (model.Locked) + { + return false; } + + return model switch + { + GroupModel group => await diagram.Options.Constraints.ShouldDeleteGroup.Invoke(group), + NodeModel node => await diagram.Options.Constraints.ShouldDeleteNode.Invoke(node), + BaseLinkModel link => await diagram.Options.Constraints.ShouldDeleteLink.Invoke(link), + _ => false, + }; } } \ No newline at end of file diff --git a/tests/Blazor.Diagrams.Core.Tests/Controls/RemoveControlTests.cs b/tests/Blazor.Diagrams.Core.Tests/Controls/RemoveControlTests.cs index e24fce0ba..1b2201ef5 100644 --- a/tests/Blazor.Diagrams.Core.Tests/Controls/RemoveControlTests.cs +++ b/tests/Blazor.Diagrams.Core.Tests/Controls/RemoveControlTests.cs @@ -175,5 +175,98 @@ public async Task OnPointerDown_ShouldDeleteLinkFalse_KeepsLink() Assert.Contains(link, diagram.Links); } + [Fact] + public async Task OnPointerDown_NoConstraints_RemovesGroup() + { + // Arrange + RemoveControl removeControl = new(0, 0); + Diagram diagram = new TestDiagram(); + + var node1 = new NodeModel(new Point(50, 50)); + var node2 = new NodeModel(new Point(300, 300)); + diagram.Nodes.Add(new[] { node1, node2 }); + node1.AddPort(PortAlignment.Right); + node2.AddPort(PortAlignment.Left); + + var group = new GroupModel(new[] { node1, node2 }); + + + diagram.Groups.Add(group); + + // Act + await removeControl.OnPointerDown(diagram, group, PointerEventArgs); + + // Assert + Assert.Empty(diagram.Groups); + Assert.Empty(diagram.Nodes); + } + + [Fact] + public async Task OnPointerDown_ShouldDeleteGroupTrue_RemovesGroup() + { + // Arrange + RemoveControl removeControl = new(0, 0); + Diagram diagram = new TestDiagram( + new Options.DiagramOptions + { + Constraints = + { + ShouldDeleteGroup = (node) => ValueTask.FromResult(true) + } + }); + + var node1 = new NodeModel(new Point(50, 50)); + var node2 = new NodeModel(new Point(300, 300)); + diagram.Nodes.Add(new[] { node1, node2 }); + node1.AddPort(PortAlignment.Right); + node2.AddPort(PortAlignment.Left); + + var group = new GroupModel(new[] { node1, node2 }); + + + diagram.Groups.Add(group); + + // Act + await removeControl.OnPointerDown(diagram, group, PointerEventArgs); + + // Assert + Assert.Empty(diagram.Groups); + Assert.Empty(diagram.Nodes); + } + + [Fact] + public async Task OnPointerDown_ShouldDeleteGroupFalse_KeepsGroup() + { + // Arrange + RemoveControl removeControl = new(0, 0); + Diagram diagram = new TestDiagram( + new Options.DiagramOptions + { + Constraints = + { + ShouldDeleteGroup = (node) => ValueTask.FromResult(false) + } + }); + + var node1 = new NodeModel(new Point(50, 50)); + var node2 = new NodeModel(new Point(300, 300)); + diagram.Nodes.Add(new[] { node1, node2 }); + node1.AddPort(PortAlignment.Right); + node2.AddPort(PortAlignment.Left); + + var group = new GroupModel(new[] { node1, node2 }); + + + diagram.Groups.Add(group); + + // Act + await removeControl.OnPointerDown(diagram, group, PointerEventArgs); + + // Assert + Assert.Contains(group, diagram.Groups); + Assert.Contains(node1, diagram.Nodes); + Assert.Contains(node2, diagram.Nodes); + } + } } From 434de9311521f0f88c19bbcd1986054dba7442c3 Mon Sep 17 00:00:00 2001 From: Haytam Zanid Date: Fri, 27 Oct 2023 11:30:10 +0100 Subject: [PATCH 14/17] Update Versions and CHANGELOG --- CHANGELOG.md | 13 +++++++++++++ .../Blazor.Diagrams.Algorithms.csproj | 6 +++--- .../Blazor.Diagrams.Core.csproj | 6 +++--- src/Blazor.Diagrams/Blazor.Diagrams.csproj | 6 +++--- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5358a9a8..bd66b19c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Diagrams (3.0.1) - 2023-10-27 + +### Added + +- `Route` property to `BaseLinkModel` to hold the result of the executed router + +### Fixed + +- Constraints not checked when using `RemoveControl` (thanks to @[K0369](https://github.com/K0369)) +- NRE Exception on the landing page demo when dragging a new link and not linking it to something (thanks to @[K0369](https://github.com/K0369)) +- `LinkVertexWidgetTests` failing on cultures that are not using a dot as decimal separator (thanks to @[K0369](https://github.com/K0369)) +- NRE exception in the Diagram Demo project (thanks to @[Suraj0500](https://github.com/Suraj0500)) + ## Diagrams (3.0.0) - 2023-08-14 Finally, the new documentation website is here! diff --git a/src/Blazor.Diagrams.Algorithms/Blazor.Diagrams.Algorithms.csproj b/src/Blazor.Diagrams.Algorithms/Blazor.Diagrams.Algorithms.csproj index 8681e4d5c..e137e0a10 100644 --- a/src/Blazor.Diagrams.Algorithms/Blazor.Diagrams.Algorithms.csproj +++ b/src/Blazor.Diagrams.Algorithms/Blazor.Diagrams.Algorithms.csproj @@ -7,10 +7,10 @@ MIT zHaytam Algorithms for Z.Blazor.Diagrams - 3.0.0 - 3.0.0 + 3.0.1 + 3.0.1 https://github.com/zHaytam/Blazor.Diagrams - 3.0.0 + 3.0.1 Z.Blazor.Diagrams.Algorithms blazor diagrams diagramming svg drag algorithms layouts Z.Blazor.Diagrams.Algorithms diff --git a/src/Blazor.Diagrams.Core/Blazor.Diagrams.Core.csproj b/src/Blazor.Diagrams.Core/Blazor.Diagrams.Core.csproj index 496607a3b..cb81f6203 100644 --- a/src/Blazor.Diagrams.Core/Blazor.Diagrams.Core.csproj +++ b/src/Blazor.Diagrams.Core/Blazor.Diagrams.Core.csproj @@ -7,10 +7,10 @@ MIT zHaytam A fully customizable and extensible all-purpose diagrams library for Blazor - 3.0.0 - 3.0.0 + 3.0.1 + 3.0.1 https://github.com/Blazor-Diagrams/Blazor.Diagrams - 3.0.0 + 3.0.1 Z.Blazor.Diagrams.Core blazor diagrams diagramming svg drag Z.Blazor.Diagrams.Core diff --git a/src/Blazor.Diagrams/Blazor.Diagrams.csproj b/src/Blazor.Diagrams/Blazor.Diagrams.csproj index 099acd468..ba3b26340 100644 --- a/src/Blazor.Diagrams/Blazor.Diagrams.csproj +++ b/src/Blazor.Diagrams/Blazor.Diagrams.csproj @@ -5,11 +5,11 @@ enable zHaytam MIT - 3.0.0 - 3.0.0 + 3.0.1 + 3.0.1 https://github.com/Blazor-Diagrams/Blazor.Diagrams A fully customizable and extensible all-purpose diagrams library for Blazor - 3.0.0 + 3.0.1 true blazor diagrams diagramming svg drag Z.Blazor.Diagrams From 11798a1ae9151a9c381979c89ec7ef81161e5599 Mon Sep 17 00:00:00 2001 From: Haytam Zanid Date: Fri, 27 Oct 2023 11:30:23 +0100 Subject: [PATCH 15/17] Add new workflow to push to nuget --- .github/workflows/push.yml | 30 ++++++++++++++++++++++++++++++ Blazor.Diagrams.sln | 1 + 2 files changed, 31 insertions(+) create mode 100644 .github/workflows/push.yml diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 000000000..73a9ff327 --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,30 @@ +name: PushToNuget +env: + NUGET_DIR: '${{ github.workspace }}/nuget' + +on: + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Pack Blazor.Diagrams.Core + working-directory: src/Blazor.Diagrams.Core + run: 'dotnet pack --configuration Release --output ${{ env.NUGET_DIR }}' + + - name: Pack Blazor.Diagrams + working-directory: src/Blazor.Diagrams + run: 'dotnet pack --configuration Release --output ${{ env.NUGET_DIR }}' + + - name: Pack Blazor.Diagrams.Algorithms + working-directory: src/Blazor.Diagrams.Algorithms + run: 'dotnet pack --configuration Release --output ${{ env.NUGET_DIR }}' + + - name: Push + run: | + foreach($file in (Get-ChildItem "${{ env.NUGET_DIR }}" -Recurse -Include *.nupkg)) { + dotnet nuget push $file --api-key "${{ secrets.NUGET_API_KEY }}" --source https://api.nuget.org/v3/index.json --skip-duplicate + } diff --git a/Blazor.Diagrams.sln b/Blazor.Diagrams.sln index 5f73d1027..862fc051e 100644 --- a/Blazor.Diagrams.sln +++ b/Blazor.Diagrams.sln @@ -24,6 +24,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .github\workflows\build.yml = .github\workflows\build.yml CHANGELOG.md = CHANGELOG.md .github\workflows\main.yml = .github\workflows\main.yml + .github\workflows\push.yml = .github\workflows\push.yml README.md = README.md EndProjectSection EndProject From 0d359254803a4432d9d45984dcccbe285c9d39ac Mon Sep 17 00:00:00 2001 From: Haytam Zanid <34218324+zHaytam@users.noreply.github.com> Date: Fri, 27 Oct 2023 12:17:55 +0100 Subject: [PATCH 16/17] Update push.yml --- .github/workflows/push.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 73a9ff327..e2b92944a 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -13,15 +13,15 @@ jobs: - name: Pack Blazor.Diagrams.Core working-directory: src/Blazor.Diagrams.Core - run: 'dotnet pack --configuration Release --output ${{ env.NUGET_DIR }}' + run: 'dotnet pack -p:GeneratePackageOnBuild=false --configuration Release --output ${{ env.NUGET_DIR }}' - name: Pack Blazor.Diagrams working-directory: src/Blazor.Diagrams - run: 'dotnet pack --configuration Release --output ${{ env.NUGET_DIR }}' + run: 'dotnet pack -p:GeneratePackageOnBuild=false --configuration Release --output ${{ env.NUGET_DIR }}' - name: Pack Blazor.Diagrams.Algorithms working-directory: src/Blazor.Diagrams.Algorithms - run: 'dotnet pack --configuration Release --output ${{ env.NUGET_DIR }}' + run: 'dotnet pack -p:GeneratePackageOnBuild=false --configuration Release --output ${{ env.NUGET_DIR }}' - name: Push run: | From 46d9800d0d81ee3130208e9565b160829b19e02d Mon Sep 17 00:00:00 2001 From: Haytam Zanid <34218324+zHaytam@users.noreply.github.com> Date: Fri, 27 Oct 2023 12:40:02 +0100 Subject: [PATCH 17/17] Update push.yml --- .github/workflows/push.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index e2b92944a..d15fccc35 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -23,8 +23,11 @@ jobs: working-directory: src/Blazor.Diagrams.Algorithms run: 'dotnet pack -p:GeneratePackageOnBuild=false --configuration Release --output ${{ env.NUGET_DIR }}' - - name: Push - run: | - foreach($file in (Get-ChildItem "${{ env.NUGET_DIR }}" -Recurse -Include *.nupkg)) { - dotnet nuget push $file --api-key "${{ secrets.NUGET_API_KEY }}" --source https://api.nuget.org/v3/index.json --skip-duplicate - } + - name: Push Blazor.Diagrams.Core + run: 'dotnet nuget push ${{ env.NUGET_DIR }}/Z.Blazor.Diagrams.Core.3.0.1.nupkg --api-key "${{ secrets.NUGET_API_KEY }}" --source https://api.nuget.org/v3/index.json --skip-duplicate' + + - name: Push Blazor.Diagrams + run: 'dotnet nuget push ${{ env.NUGET_DIR }}/Z.Blazor.Diagrams.3.0.1.nupkg --api-key "${{ secrets.NUGET_API_KEY }}" --source https://api.nuget.org/v3/index.json --skip-duplicate' + + - name: Push Blazor.Diagrams.Algorithms + run: 'dotnet nuget push ${{ env.NUGET_DIR }}/Z.Blazor.Diagrams.Algorithms.3.0.1.nupkg --api-key "${{ secrets.NUGET_API_KEY }}" --source https://api.nuget.org/v3/index.json --skip-duplicate'