diff --git a/.gitignore b/.gitignore index 89abebe..04f5db4 100644 --- a/.gitignore +++ b/.gitignore @@ -397,4 +397,5 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml -.idea/ \ No newline at end of file +.idea/ +app_components.xml diff --git a/EA-ModelKit.Installer/AppComponents.wxs b/EA-ModelKit.Installer/AppComponents.wxs new file mode 100644 index 0000000..926faa2 --- /dev/null +++ b/EA-ModelKit.Installer/AppComponents.wxs @@ -0,0 +1,404 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/EA-ModelKit.Installer/EA-ModelKit.Installer.wixproj b/EA-ModelKit.Installer/EA-ModelKit.Installer.wixproj new file mode 100644 index 0000000..5199064 --- /dev/null +++ b/EA-ModelKit.Installer/EA-ModelKit.Installer.wixproj @@ -0,0 +1,17 @@ + + + 1.0.0 + EA-ModelKitInstaller_$(Version) + Debug;Release;CICD + + + + + + + + + + + + \ No newline at end of file diff --git a/EA-ModelKit.Installer/Folders.wxs b/EA-ModelKit.Installer/Folders.wxs new file mode 100644 index 0000000..df580e5 --- /dev/null +++ b/EA-ModelKit.Installer/Folders.wxs @@ -0,0 +1,7 @@ + + + + + + + diff --git a/EA-ModelKit.Installer/Package.en-us.wxl b/EA-ModelKit.Installer/Package.en-us.wxl new file mode 100644 index 0000000..e8311d4 --- /dev/null +++ b/EA-ModelKit.Installer/Package.en-us.wxl @@ -0,0 +1,8 @@ + + + + + + diff --git a/EA-ModelKit.Installer/Package.wxs b/EA-ModelKit.Installer/Package.wxs new file mode 100644 index 0000000..44e8bfa --- /dev/null +++ b/EA-ModelKit.Installer/Package.wxs @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/EA-ModelKit.Installer/RegistryKey.wxs b/EA-ModelKit.Installer/RegistryKey.wxs new file mode 100644 index 0000000..8716f4b --- /dev/null +++ b/EA-ModelKit.Installer/RegistryKey.wxs @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/EA-ModelKit.Installer/license.rtf b/EA-ModelKit.Installer/license.rtf new file mode 100644 index 0000000..7ca1788 --- /dev/null +++ b/EA-ModelKit.Installer/license.rtf @@ -0,0 +1,207 @@ +{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang2057{\fonttbl{\f0\fnil Calibri;}} +{\colortbl ;\red0\green0\blue255;} +{\*\generator Riched20 10.0.22621}\viewkind4\uc1 +\pard\sa200\sl276\slmult1\qc\f0\fs22\lang9216\par +Apache License\par +Version 2.0, January 2004\par +{{\field{\*\fldinst{HYPERLINK http://www.apache.org/licenses/ }}{\fldrslt{http://www.apache.org/licenses/\ul0\cf0}}}}\f0\fs22\par +\par + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\par +\par + 1. Definitions.\par +\par + "License" shall mean the terms and conditions for use, reproduction,\par + and distribution as defined by Sections 1 through 9 of this document.\par +\par + "Licensor" shall mean the copyright owner or entity authorized by\par + the copyright owner that is granting the License.\par +\par + "Legal Entity" shall mean the union of the acting entity and all\par + other entities that control, are controlled by, or are under common\par + control with that entity. For the purposes of this definition,\par + "control" means (i) the power, direct or indirect, to cause the\par + direction or management of such entity, whether by contract or\par + otherwise, or (ii) ownership of fifty percent (50%) or more of the\par + outstanding shares, or (iii) beneficial ownership of such entity.\par +\par + "You" (or "Your") shall mean an individual or Legal Entity\par + exercising permissions granted by this License.\par +\par + "Source" form shall mean the preferred form for making modifications,\par + including but not limited to software source code, documentation\par + source, and configuration files.\par +\par + "Object" form shall mean any form resulting from mechanical\par + transformation or translation of a Source form, including but\par + not limited to compiled object code, generated documentation,\par + and conversions to other media types.\par +\par + "Work" shall mean the work of authorship, whether in Source or\par + Object form, made available under the License, as indicated by a\par + copyright notice that is included in or attached to the work\par + (an example is provided in the Appendix below).\par +\par + "Derivative Works" shall mean any work, whether in Source or Object\par + form, that is based on (or derived from) the Work and for which the\par + editorial revisions, annotations, elaborations, or other modifications\par + represent, as a whole, an original work of authorship. For the purposes\par + of this License, Derivative Works shall not include works that remain\par + separable from, or merely link (or bind by name) to the interfaces of,\par + the Work and Derivative Works thereof.\par +\par + "Contribution" shall mean any work of authorship, including\par + the original version of the Work and any modifications or additions\par + to that Work or Derivative Works thereof, that is intentionally\par + submitted to Licensor for inclusion in the Work by the copyright owner\par + or by an individual or Legal Entity authorized to submit on behalf of\par + the copyright owner. For the purposes of this definition, "submitted"\par + means any form of electronic, verbal, or written communication sent\par + to the Licensor or its representatives, including but not limited to\par + communication on electronic mailing lists, source code control systems,\par + and issue tracking systems that are managed by, or on behalf of, the\par + Licensor for the purpose of discussing and improving the Work, but\par + excluding communication that is conspicuously marked or otherwise\par + designated in writing by the copyright owner as "Not a Contribution."\par +\par + "Contributor" shall mean Licensor and any individual or Legal Entity\par + on behalf of whom a Contribution has been received by Licensor and\par + subsequently incorporated within the Work.\par +\par + 2. Grant of Copyright License. Subject to the terms and conditions of\par + this License, each Contributor hereby grants to You a perpetual,\par + worldwide, non-exclusive, no-charge, royalty-free, irrevocable\par + copyright license to reproduce, prepare Derivative Works of,\par + publicly display, publicly perform, sublicense, and distribute the\par + Work and such Derivative Works in Source or Object form.\par +\par + 3. Grant of Patent License. Subject to the terms and conditions of\par + this License, each Contributor hereby grants to You a perpetual,\par + worldwide, non-exclusive, no-charge, royalty-free, irrevocable\par + (except as stated in this section) patent license to make, have made,\par + use, offer to sell, sell, import, and otherwise transfer the Work,\par + where such license applies only to those patent claims licensable\par + by such Contributor that are necessarily infringed by their\par + Contribution(s) alone or by combination of their Contribution(s)\par + with the Work to which such Contribution(s) was submitted. If You\par + institute patent litigation against any entity (including a\par + cross-claim or counterclaim in a lawsuit) alleging that the Work\par + or a Contribution incorporated within the Work constitutes direct\par + or contributory patent infringement, then any patent licenses\par + granted to You under this License for that Work shall terminate\par + as of the date such litigation is filed.\par +\par + 4. Redistribution. You may reproduce and distribute copies of the\par + Work or Derivative Works thereof in any medium, with or without\par + modifications, and in Source or Object form, provided that You\par + meet the following conditions:\par +\par + (a) You must give any other recipients of the Work or\par + Derivative Works a copy of this License; and\par +\par + (b) You must cause any modified files to carry prominent notices\par + stating that You changed the files; and\par +\par + (c) You must retain, in the Source form of any Derivative Works\par + that You distribute, all copyright, patent, trademark, and\par + attribution notices from the Source form of the Work,\par + excluding those notices that do not pertain to any part of\par + the Derivative Works; and\par +\par + (d) If the Work includes a "NOTICE" text file as part of its\par + distribution, then any Derivative Works that You distribute must\par + include a readable copy of the attribution notices contained\par + within such NOTICE file, excluding those notices that do not\par + pertain to any part of the Derivative Works, in at least one\par + of the following places: within a NOTICE text file distributed\par + as part of the Derivative Works; within the Source form or\par + documentation, if provided along with the Derivative Works; or,\par + within a display generated by the Derivative Works, if and\par + wherever such third-party notices normally appear. The contents\par + of the NOTICE file are for informational purposes only and\par + do not modify the License. You may add Your own attribution\par + notices within Derivative Works that You distribute, alongside\par + or as an addendum to the NOTICE text from the Work, provided\par + that such additional attribution notices cannot be construed\par + as modifying the License.\par +\par + You may add Your own copyright statement to Your modifications and\par + may provide additional or different license terms and conditions\par + for use, reproduction, or distribution of Your modifications, or\par + for any such Derivative Works as a whole, provided Your use,\par + reproduction, and distribution of the Work otherwise complies with\par + the conditions stated in this License.\par +\par + 5. Submission of Contributions. Unless You explicitly state otherwise,\par + any Contribution intentionally submitted for inclusion in the Work\par + by You to the Licensor shall be under the terms and conditions of\par + this License, without any additional terms or conditions.\par + Notwithstanding the above, nothing herein shall supersede or modify\par + the terms of any separate license agreement you may have executed\par + with Licensor regarding such Contributions.\par +\par + 6. Trademarks. This License does not grant permission to use the trade\par + names, trademarks, service marks, or product names of the Licensor,\par + except as required for reasonable and customary use in describing the\par + origin of the Work and reproducing the content of the NOTICE file.\par +\par + 7. Disclaimer of Warranty. Unless required by applicable law or\par + agreed to in writing, Licensor provides the Work (and each\par + Contributor provides its Contributions) on an "AS IS" BASIS,\par + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\par + implied, including, without limitation, any warranties or conditions\par + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\par + PARTICULAR PURPOSE. You are solely responsible for determining the\par + appropriateness of using or redistributing the Work and assume any\par + risks associated with Your exercise of permissions under this License.\par +\par + 8. Limitation of Liability. In no event and under no legal theory,\par + whether in tort (including negligence), contract, or otherwise,\par + unless required by applicable law (such as deliberate and grossly\par + negligent acts) or agreed to in writing, shall any Contributor be\par + liable to You for damages, including any direct, indirect, special,\par + incidental, or consequential damages of any character arising as a\par + result of this License or out of the use or inability to use the\par + Work (including but not limited to damages for loss of goodwill,\par + work stoppage, computer failure or malfunction, or any and all\par + other commercial damages or losses), even if such Contributor\par + has been advised of the possibility of such damages.\par +\par + 9. Accepting Warranty or Additional Liability. While redistributing\par + the Work or Derivative Works thereof, You may choose to offer,\par + and charge a fee for, acceptance of support, warranty, indemnity,\par + or other liability obligations and/or rights consistent with this\par + License. However, in accepting such obligations, You may act only\par + on Your own behalf and on Your sole responsibility, not on behalf\par + of any other Contributor, and only if You agree to indemnify,\par + defend, and hold each Contributor harmless for any liability\par + incurred by, or claims asserted against, such Contributor by reason\par + of your accepting any such warranty or additional liability.\par +\par + END OF TERMS AND CONDITIONS\par +\par + APPENDIX: How to apply the Apache License to your work.\par +\par + To apply the Apache License to your work, attach the following\par + boilerplate notice, with the fields enclosed by brackets "[]"\par + replaced with your own identifying information. (Don't include\par + the brackets!) The text should be enclosed in the appropriate\par + comment syntax for the file format. We also recommend that a\par + file or class name and description of purpose be included on the\par + same "printed page" as the copyright notice for easier\par + identification within third-party archives.\par +\par + Copyright [yyyy] [name of copyright owner]\par +\par + Licensed under the Apache License, Version 2.0 (the "License");\par + you may not use this file except in compliance with the License.\par + You may obtain a copy of the License at\par +\par + {{\field{\*\fldinst{HYPERLINK http://www.apache.org/licenses/LICENSE-2.0 }}{\fldrslt{http://www.apache.org/licenses/LICENSE-2.0\ul0\cf0}}}}\f0\fs22\par +\par + Unless required by applicable law or agreed to in writing, software\par + distributed under the License is distributed on an "AS IS" BASIS,\par + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\par + See the License for the specific language governing permissions and\par + limitations under the License.\par +} + \ No newline at end of file diff --git a/EA-ModelKit.Tests/EA-ModelKit.Tests.csproj b/EA-ModelKit.Tests/EA-ModelKit.Tests.csproj index 0c07b84..b923329 100644 --- a/EA-ModelKit.Tests/EA-ModelKit.Tests.csproj +++ b/EA-ModelKit.Tests/EA-ModelKit.Tests.csproj @@ -46,6 +46,12 @@ Always + + Always + + + Always + diff --git a/EA-ModelKit.Tests/Helpers/TestSlimElement.cs b/EA-ModelKit.Tests/Helpers/TestSlimElement.cs index dd1c9de..5d25665 100644 --- a/EA-ModelKit.Tests/Helpers/TestSlimElement.cs +++ b/EA-ModelKit.Tests/Helpers/TestSlimElement.cs @@ -36,12 +36,14 @@ internal class TestSlimElement: SlimElement /// /// The associated /// The associated collection of - public TestSlimElement(Element element, IReadOnlyList taggedValues) : base(element, taggedValues) + /// The associated collection of + public TestSlimElement(Element element, IReadOnlyCollection taggedValues, IReadOnlyCollection connectors) : base(element, taggedValues, connectors) { } - public TestSlimElement(string kind, string name, string alias, string notes, IReadOnlyList taggedValues): - this(CreateElement(kind, name, alias, notes), taggedValues) + public TestSlimElement(string kind, string name, string alias, string notes, IReadOnlyList taggedValues, + IReadOnlyCollection connectors): + this(CreateElement(kind, name, alias, notes), taggedValues, connectors) { } diff --git a/EA-ModelKit.Tests/Resources/CacheService/Connectors.xml b/EA-ModelKit.Tests/Resources/CacheService/Connectors.xml new file mode 100644 index 0000000..baa8eb0 --- /dev/null +++ b/EA-ModelKit.Tests/Resources/CacheService/Connectors.xml @@ -0,0 +1,10 @@ + + + + + + 20 + + + + diff --git a/EA-ModelKit.Tests/Resources/CacheService/EmptyConnectors.xml b/EA-ModelKit.Tests/Resources/CacheService/EmptyConnectors.xml new file mode 100644 index 0000000..77a2d7a --- /dev/null +++ b/EA-ModelKit.Tests/Resources/CacheService/EmptyConnectors.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/EA-ModelKit.Tests/Services/Cache/CacheServiceTestFixture.cs b/EA-ModelKit.Tests/Services/Cache/CacheServiceTestFixture.cs index 6e782d3..5f19264 100644 --- a/EA-ModelKit.Tests/Services/Cache/CacheServiceTestFixture.cs +++ b/EA-ModelKit.Tests/Services/Cache/CacheServiceTestFixture.cs @@ -23,19 +23,20 @@ namespace EAModelKit.Tests.Services.Cache using EA; using EAModelKit.Services.Cache; + using EAModelKit.Tests.Helpers; using Moq; using NUnit.Framework; - - using File = System.IO.File; + + using File = File; [TestFixture] public class CacheServiceTestFixture { private CacheService cacheService; private Mock repository; - + [SetUp] public void Setup() { @@ -45,6 +46,30 @@ public void Setup() this.repository.Setup(x => x.SQLQuery(It.Is(i => i.Contains("t_objectproperties")))) .Returns(QueryResourceContent("TaggedValues.xml")); + + this.repository.Setup(x => x.SQLQuery(It.Is(i => i.Contains(" Start_Object_ID=5")))) + .Returns(QueryResourceContent("Connectors.xml")); + + this.repository.Setup(x => x.SQLQuery(It.Is(i => i.Contains(" Start_Object_ID=15")))) + .Returns(QueryResourceContent("Connectors.xml")); + + this.repository.Setup(x => x.SQLQuery(It.Is(i => i.Contains(" Start_Object_ID=6")))) + .Returns(QueryResourceContent("EmptyConnectors.xml")); + + var connector = new Mock(); + connector.Setup(x => x.ConnectorID).Returns(20); + connector.Setup(x => x.ClientID).Returns(5); + connector.Setup(x => x.SupplierID).Returns(15); + connector.Setup(x => x.Type).Returns("Association"); + this.repository.Setup(x => x.GetConnectorByID(20)).Returns(connector.Object); + + var elements = new List + { + CreateNewElement("Requirement", "", "REQ-01", 5), + CreateNewElement("Block", "Function", "FUNC-01", 15) + }; + + this.repository.Setup(x => x.GetElementSet("5,15", 0)).Returns(new TestCollection(elements)); } [Test] @@ -52,13 +77,34 @@ public void VerifyGetTaggedValues() { Assert.Multiple(() => { - Assert.That(this.cacheService.GetTaggedValues(10).Count, Is.EqualTo(1)); - Assert.That(this.cacheService.GetTaggedValues(20).Count, Is.EqualTo(2)); - Assert.That(this.cacheService.GetTaggedValues(26).Count, Is.EqualTo(1)); - Assert.That(this.cacheService.GetTaggedValues(27).Count, Is.EqualTo(0)); - Assert.That(this.cacheService.GetTaggedValues([10,20,26]).Count, Is.EqualTo(4)); + Assert.That(this.cacheService.GetTaggedValues(10), Has.Count.EqualTo(1)); + Assert.That(this.cacheService.GetTaggedValues(20), Has.Count.EqualTo(2)); + Assert.That(this.cacheService.GetTaggedValues(26), Has.Count.EqualTo(1)); + Assert.That(this.cacheService.GetTaggedValues(27), Has.Count.EqualTo(0)); + Assert.That(this.cacheService.GetTaggedValues([10, 20, 26]), Has.Count.EqualTo(4)); }); } + + [Test] + public void VerifyGetConnectors() + { + Assert.Multiple(() => + { + Assert.That(this.cacheService.GetAssociatedConnectors(5),Has.Count.EqualTo(1)); + Assert.That(this.cacheService.GetAssociatedConnectors(15),Has.Count.EqualTo(1)); + Assert.That(this.cacheService.GetAssociatedConnectors(6),Has.Count.EqualTo(0)); + }); + } + + private static Element CreateNewElement(string type, string stereotype, string name, int elementId) + { + var element = new Mock(); + element.Setup(x => x.ElementID).Returns(elementId); + element.Setup(x => x.Type).Returns(type); + element.Setup(x => x.Stereotype).Returns(stereotype); + element.Setup(x => x.Name).Returns(name); + return element.Object; + } private static string QueryResourceContent(string fileName) { diff --git a/EA-ModelKit.Tests/Services/Exporter/GenericExporterServiceTestFixture.cs b/EA-ModelKit.Tests/Services/Exporter/GenericExporterServiceTestFixture.cs index 47829da..b8655c2 100644 --- a/EA-ModelKit.Tests/Services/Exporter/GenericExporterServiceTestFixture.cs +++ b/EA-ModelKit.Tests/Services/Exporter/GenericExporterServiceTestFixture.cs @@ -60,18 +60,30 @@ public async Task VerifyExportElements() Name = "abc", Value = "15" }; - + var element = new Mock(); element.Setup(x => x.Name).Returns("abc"); element.Setup(x => x.Stereotype).Returns("Function"); element.Setup(x => x.ElementID).Returns(slimTaggedValue.ContainerId); - var slimTaggedValues = new List { slimTaggedValue }; - var slimElement = new SlimElement(element.Object, slimTaggedValues); - + var targetElement = new Mock(); + targetElement.Setup(x => x.Name).Returns("def"); + element.Setup(x => x.Stereotype).Returns(""); + element.Setup(x => x.Type).Returns("Requirement"); + element.Setup(x => x.ElementID).Returns(45); + + var connector = new Mock(); + connector.Setup(x => x.Stereotype).Returns(""); + connector.Setup(x => x.Type).Returns("Dependency"); + connector.Setup(x => x.ClientID).Returns(element.Object.ElementID); + connector.Setup(x => x.SupplierID).Returns(targetElement.Object.ElementID); + + var slimConnector = new SlimConnector(connector.Object, element.Object, targetElement.Object); + var slimElement = new SlimElement(element.Object, [slimTaggedValue], [slimConnector]); + var genericConfigurations = new List { - new([slimElement], [slimTaggedValue.Name]) + new([slimElement], [slimTaggedValue.Name], [slimConnector.ComputeConnectorKindFullName(slimElement.ElementId)]) }; this.excelWriter.Setup(x => x.WriteAsync(It.IsAny>>(), It.IsAny())) @@ -84,7 +96,7 @@ public async Task VerifyExportElements() this.excelWriter.Setup(x => x.WriteAsync(It.IsAny>>(), It.IsAny())) .ThrowsAsync(new InvalidOperationException()); - Assert.That(() => this.exporterService.ExportElementsAsync("abcpath", genericConfigurations), Throws.InvalidOperationException); + await Assert.ThatAsync(() => this.exporterService.ExportElementsAsync("abcpath", genericConfigurations), Throws.InvalidOperationException); } } } diff --git a/EA-ModelKit.Tests/Services/Writer/ExcelWriterTestFixture.cs b/EA-ModelKit.Tests/Services/Writer/ExcelWriterTestFixture.cs index 06ae26a..469a0b9 100644 --- a/EA-ModelKit.Tests/Services/Writer/ExcelWriterTestFixture.cs +++ b/EA-ModelKit.Tests/Services/Writer/ExcelWriterTestFixture.cs @@ -52,7 +52,7 @@ public void Teardown() public void VerifyWrite() { const string kind = "TestElement"; - var element = new ExportableElement(new TestSlimElement(kind, "name", "alias", "a note", []), []); + var element = new ExportableElement(new TestSlimElement(kind, "name", "alias", "a note", [], []), [], []); var content = new Dictionary> { diff --git a/EA-ModelKit.Tests/ViewModels/Exporter/GenericExporterViewModelTestFixture.cs b/EA-ModelKit.Tests/ViewModels/Exporter/GenericExporterViewModelTestFixture.cs index 02a8865..b53026c 100644 --- a/EA-ModelKit.Tests/ViewModels/Exporter/GenericExporterViewModelTestFixture.cs +++ b/EA-ModelKit.Tests/ViewModels/Exporter/GenericExporterViewModelTestFixture.cs @@ -48,7 +48,7 @@ public class GenericExporterViewModelTestFixture private Mock builderService; private Mock exporterService; private List elements; - private Mock closeWindowBehavior; + private Mock closeWindowBehavior; [SetUp] public void Setup() @@ -98,9 +98,20 @@ public void Setup() Name = "123" } }; + + var connectors = new List + { + CreateNewSlimConnector("Association", "implements", this.elements[0], this.elements[1]), + CreateNewSlimConnector("Association", "", this.elements[2], this.elements[3]), + }; this.cacheService.Setup(x => x.GetTaggedValues(It.IsAny())) .Returns(taggedValues); + + this.cacheService.Setup(x => x.GetAssociatedConnectors(this.elements[0].ElementID)).Returns([connectors[0]]); + this.cacheService.Setup(x => x.GetAssociatedConnectors(this.elements[1].ElementID)).Returns([connectors[0]]); + this.cacheService.Setup(x => x.GetAssociatedConnectors(this.elements[2].ElementID)).Returns([connectors[1]]); + this.cacheService.Setup(x => x.GetAssociatedConnectors(this.elements[3].ElementID)).Returns([connectors[1]]); } [Test] @@ -110,7 +121,7 @@ public void VerifyViewModelProperties() { Assert.That(this.exporterViewModel.CanProceed, Is.False); Assert.That(this.exporterViewModel.SelectedFilePath, Is.Null); - Assert.That(this.exporterViewModel.ExportSetups.Items, Is.Empty); + Assert.That(this.exporterViewModel.AvailableExportSetups.Items, Is.Empty); Assert.That(this.exporterViewModel.OutputFileCommand, Is.Null); Assert.That(this.exporterViewModel.ExportCommand, Is.Null); }); @@ -130,22 +141,22 @@ public void VerifyInitializeViewModel() Assert.Multiple(() => { this.cacheService.Verify(x => x.GetTaggedValues(It.IsAny()), Times.Once); - Assert.That(this.exporterViewModel.ExportSetups.Items, Is.Not.Empty); - Assert.That(this.exporterViewModel.ExportSetups, Has.Count.EqualTo(3)); + Assert.That(this.exporterViewModel.AvailableExportSetups.Items, Is.Not.Empty); + Assert.That(this.exporterViewModel.AvailableExportSetups, Has.Count.EqualTo(3)); Assert.That(this.exporterViewModel.OutputFileCommand, Is.Not.Null); Assert.That(this.exporterViewModel.ExportCommand, Is.Not.Null); - Assert.That(this.exporterViewModel.ExportSetups.Items.All(x => x.ShouldBeExported), Is.True); + Assert.That(this.exporterViewModel.AvailableExportSetups.Items.All(x => x.ShouldBeExported), Is.True); - Assert.That(this.exporterViewModel.ExportSetups.Items.Single(x => x.ElementKind == "Requirement").AvailableTaggedValuesForExport + Assert.That(this.exporterViewModel.AvailableExportSetups.Items.Single(x => x.ElementKind == "Requirement").AvailableTaggedValuesForExport .Count(), Is.EqualTo(2)); - Assert.That(this.exporterViewModel.ExportSetups.Items.Single(x => x.ElementKind == "Function").AvailableTaggedValuesForExport + Assert.That(this.exporterViewModel.AvailableExportSetups.Items.Single(x => x.ElementKind == "Function").AvailableTaggedValuesForExport .Count(), Is.EqualTo(2)); - Assert.That(this.exporterViewModel.ExportSetups.Items.Single(x => x.ElementKind == "Product").HaveAnyTaggedValues, + Assert.That(this.exporterViewModel.AvailableExportSetups.Items.Single(x => x.ElementKind == "Product").HaveAnyTaggedValues, Is.False); - Assert.That(this.exporterViewModel.ExportSetups.Items.All(x => x.AvailableTaggedValuesForExport.Count() + Assert.That(this.exporterViewModel.AvailableExportSetups.Items.All(x => x.AvailableTaggedValuesForExport.Count() == x.SelectedTaggedValuesForExport.Count()), Is.True); }); } @@ -182,10 +193,10 @@ public void VerifyCanProceedComputation() this.exporterViewModel.OutputFileCommand.Execute().Subscribe(); Assert.That(this.exporterViewModel.CanProceed, Is.True); - this.exporterViewModel.ExportSetups.Items.ForEach(x => x.ShouldBeExported = false); + this.exporterViewModel.AvailableExportSetups.Items.ForEach(x => x.ShouldBeExported = false); Assert.That(this.exporterViewModel.CanProceed, Is.False); - this.exporterViewModel.ExportSetups.Items.First().ShouldBeExported = true; + this.exporterViewModel.AvailableExportSetups.Items[0].ShouldBeExported = true; Assert.That(this.exporterViewModel.CanProceed, Is.True); } @@ -226,5 +237,15 @@ private static Element CreateNewElement(int id, string typeName, string stereoty return element.Object; } + + private static SlimConnector CreateNewSlimConnector(string connectorType, string connectorStereotype, Element source, Element target) + { + var connector = new Mock(); + connector.Setup(x => x.Stereotype).Returns(connectorStereotype); + connector.Setup(x => x.Type).Returns(connectorType); + connector.Setup(x => x.ClientID).Returns(source.ElementID); + connector.Setup(x => x.SupplierID).Returns(target.ElementID); + return new SlimConnector(connector.Object, source, target); + } } } diff --git a/EA-ModelKit.sln b/EA-ModelKit.sln index e9f8054..f6ff75d 100644 --- a/EA-ModelKit.sln +++ b/EA-ModelKit.sln @@ -1,27 +1,104 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EA-ModelKit", "EA-ModelKit\EA-ModelKit.csproj", "{6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}" +# Visual Studio Version 17 +VisualStudioVersion = 17.10.35004.147 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EA-ModelKit", "EA-ModelKit\EA-ModelKit.csproj", "{6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EA-ModelKit.Tests", "EA-ModelKit.Tests\EA-ModelKit.Tests.csproj", "{C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EA-ModelKit.Tests", "EA-ModelKit.Tests\EA-ModelKit.Tests.csproj", "{C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}" +EndProject +Project("{B7DD6F7E-DEF8-4E67-B5B7-07EF123DB6F0}") = "EA-ModelKit.Installer", "EA-ModelKit.Installer\EA-ModelKit.Installer.wixproj", "{B60DE1DD-BFE7-4511-94FF-000AA5999B57}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + CICD|Any CPU = CICD|Any CPU + CICD|ARM64 = CICD|ARM64 + CICD|x64 = CICD|x64 + CICD|x86 = CICD|x86 Debug|Any CPU = Debug|Any CPU + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU - CICD|Any CPU = CICD|Any CPU + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.CICD|Any CPU.ActiveCfg = CICD|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.CICD|Any CPU.Build.0 = CICD|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.CICD|ARM64.ActiveCfg = CICD|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.CICD|ARM64.Build.0 = CICD|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.CICD|x64.ActiveCfg = CICD|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.CICD|x64.Build.0 = CICD|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.CICD|x86.ActiveCfg = CICD|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.CICD|x86.Build.0 = CICD|Any CPU {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Debug|ARM64.Build.0 = Debug|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Debug|x64.ActiveCfg = Debug|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Debug|x64.Build.0 = Debug|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Debug|x86.ActiveCfg = Debug|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Debug|x86.Build.0 = Debug|Any CPU {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Release|Any CPU.ActiveCfg = Release|Any CPU {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Release|Any CPU.Build.0 = Release|Any CPU - {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.CICD|Any CPU.ActiveCfg = CICD|Any CPU - {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.CICD|Any CPU.Build.0 = CICD|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Release|ARM64.ActiveCfg = Release|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Release|ARM64.Build.0 = Release|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Release|x64.ActiveCfg = Release|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Release|x64.Build.0 = Release|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Release|x86.ActiveCfg = Release|Any CPU + {6E1CFB9B-538B-4684-A66B-2C81A6AFA2A4}.Release|x86.Build.0 = Release|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.CICD|Any CPU.ActiveCfg = CICD|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.CICD|Any CPU.Build.0 = CICD|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.CICD|ARM64.ActiveCfg = CICD|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.CICD|ARM64.Build.0 = CICD|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.CICD|x64.ActiveCfg = CICD|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.CICD|x64.Build.0 = CICD|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.CICD|x86.ActiveCfg = CICD|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.CICD|x86.Build.0 = CICD|Any CPU {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Debug|ARM64.Build.0 = Debug|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Debug|x64.ActiveCfg = Debug|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Debug|x64.Build.0 = Debug|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Debug|x86.ActiveCfg = Debug|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Debug|x86.Build.0 = Debug|Any CPU {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Release|Any CPU.ActiveCfg = Release|Any CPU {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Release|Any CPU.Build.0 = Release|Any CPU - {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.CICD|Any CPU.ActiveCfg = CICD|Any CPU - {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.CICD|Any CPU.Build.0 = CICD|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Release|ARM64.ActiveCfg = Release|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Release|ARM64.Build.0 = Release|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Release|x64.ActiveCfg = Release|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Release|x64.Build.0 = Release|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Release|x86.ActiveCfg = Release|Any CPU + {C340292F-8ED3-4C46-BCFB-A7B7EA22D3A9}.Release|x86.Build.0 = Release|Any CPU + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.CICD|Any CPU.ActiveCfg = Debug|x64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.CICD|Any CPU.Build.0 = Debug|x64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.CICD|ARM64.ActiveCfg = Debug|ARM64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.CICD|ARM64.Build.0 = Debug|ARM64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.CICD|x64.ActiveCfg = Debug|x64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.CICD|x64.Build.0 = Debug|x64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.CICD|x86.ActiveCfg = Debug|x86 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.CICD|x86.Build.0 = Debug|x86 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Debug|Any CPU.ActiveCfg = Debug|x64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Debug|Any CPU.Build.0 = Debug|x64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Debug|ARM64.Build.0 = Debug|ARM64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Debug|x64.ActiveCfg = Debug|x64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Debug|x64.Build.0 = Debug|x64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Debug|x86.ActiveCfg = Debug|x86 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Debug|x86.Build.0 = Debug|x86 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Release|Any CPU.ActiveCfg = Release|x64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Release|Any CPU.Build.0 = Release|x64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Release|ARM64.ActiveCfg = Release|ARM64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Release|ARM64.Build.0 = Release|ARM64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Release|x64.ActiveCfg = Release|x64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Release|x64.Build.0 = Release|x64 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Release|x86.ActiveCfg = Release|x86 + {B60DE1DD-BFE7-4511-94FF-000AA5999B57}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection EndGlobal diff --git a/EA-ModelKit/EA-ModelKit.csproj b/EA-ModelKit/EA-ModelKit.csproj index c5df0ed..7785cde 100644 --- a/EA-ModelKit/EA-ModelKit.csproj +++ b/EA-ModelKit/EA-ModelKit.csproj @@ -34,7 +34,7 @@ - + diff --git a/EA-ModelKit/Extensions/ConnectorExtensions.cs b/EA-ModelKit/Extensions/ConnectorExtensions.cs new file mode 100644 index 0000000..d0f3788 --- /dev/null +++ b/EA-ModelKit/Extensions/ConnectorExtensions.cs @@ -0,0 +1,40 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + +namespace EAModelKit.Extensions +{ + using EA; + + /// + /// Extensions methods for the class + /// + internal static class ConnectorExtensions + { + /// + /// Query the 's kind + /// + /// An + /// The Stereotype if present, the type either + public static string QueryConnectorKind(this Connector connector) + { + return string.IsNullOrEmpty(connector.Stereotype) ? connector.Type : connector.Stereotype; + } + } +} diff --git a/EA-ModelKit/Extensions/ElementExtensions.cs b/EA-ModelKit/Extensions/ElementExtensions.cs new file mode 100644 index 0000000..f828b09 --- /dev/null +++ b/EA-ModelKit/Extensions/ElementExtensions.cs @@ -0,0 +1,40 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + +namespace EAModelKit.Extensions +{ + using EA; + + /// + /// Extensions methods for the class + /// + internal static class ElementExtensions + { + /// + /// Query the 's kind + /// + /// An + /// The Stereotype if present, the type either + public static string QueryElementKind(this Element element) + { + return string.IsNullOrEmpty(element.Stereotype) ? element.Type : element.Stereotype; + } + } +} diff --git a/EA-ModelKit/Model/Export/ExportableElement.cs b/EA-ModelKit/Model/Export/ExportableElement.cs index 19a0bbe..4b6dd74 100644 --- a/EA-ModelKit/Model/Export/ExportableElement.cs +++ b/EA-ModelKit/Model/Export/ExportableElement.cs @@ -38,16 +38,17 @@ internal class ExportableElement: ExportableObject /// Defines the base headers for the /// private readonly string[] baseHeaders = ["Name", "Alias", "Notes"]; - + /// /// Initializes a new instance of /// /// The that should be exported /// All name of TaggeValue that have to be exported - public ExportableElement(SlimElement element, IReadOnlyList taggedValuesToExport) + /// All name of Connector that have to be exported + public ExportableElement(SlimElement element, IReadOnlyList taggedValuesToExport, IReadOnlyList connectorsToExport) { this.KindName = element.ElementKind; - this.Headers = [..this.baseHeaders, ..taggedValuesToExport]; + this.Headers = [..this.baseHeaders, ..taggedValuesToExport, ..connectorsToExport]; var values = new List {element.Name, element.Alias,WebUtility.HtmlDecode(element.Notes)}; @@ -62,6 +63,13 @@ public ExportableElement(SlimElement element, IReadOnlyList taggedValues ? string.Join(Environment.NewLine, existingValue.Select(x => x.Value)) : string.Empty; } + + foreach (var connectorToExport in connectorsToExport) + { + this.ExportableValues[connectorToExport] = element.Connectors.TryGetValue(connectorToExport, out var existingConnectors) + ? string.Join(Environment.NewLine, existingConnectors.Select(x => x.GetOppositeElementName(element.ElementId))) + : string.Empty; + } } } } diff --git a/EA-ModelKit/Model/Export/GenericExportConfiguration.cs b/EA-ModelKit/Model/Export/GenericExportConfiguration.cs index b6cb65f..610da4f 100644 --- a/EA-ModelKit/Model/Export/GenericExportConfiguration.cs +++ b/EA-ModelKit/Model/Export/GenericExportConfiguration.cs @@ -37,12 +37,19 @@ internal class GenericExportConfiguration /// /// The collection of that should be exported /// The collection of TaggedValue names that should be exported - public GenericExportConfiguration(IReadOnlyList exportableElements, IReadOnlyList exportableTaggedValues) + /// The collection of Connector that should be exported + public GenericExportConfiguration(IReadOnlyList exportableElements, IReadOnlyList exportableTaggedValues, IReadOnlyList exportableConnectors) { this.ExportableElements = exportableElements; this.ExportableTaggedValues = exportableTaggedValues; + this.ExportableConnectors = exportableConnectors; } + /// + /// Gets the read-only collection of Connectors that should be exported + /// + public IReadOnlyList ExportableConnectors { get; } + /// /// Gets the read-only collection of that have to be exported /// diff --git a/EA-ModelKit/Model/Slims/SlimConnector.cs b/EA-ModelKit/Model/Slims/SlimConnector.cs new file mode 100644 index 0000000..9b6fae7 --- /dev/null +++ b/EA-ModelKit/Model/Slims/SlimConnector.cs @@ -0,0 +1,165 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + +namespace EAModelKit.Model.Slims +{ + using System; + using System.Collections.Generic; + + using EA; + + using EAModelKit.Extensions; + + /// + /// Slim class for + /// + internal class SlimConnector + { + /// + /// Initializes a new instance of + /// + /// The associated + /// The source of the + /// The target of the + public SlimConnector(Connector connector, Element source, Element target) + { + this.ConnectorType = connector.Type; + this.ConnectorStereotype = connector.Stereotype; + this.SourceId = connector.ClientID; + this.TargetId = connector.SupplierID; + this.SourceKind = source.QueryElementKind(); + this.TargetKind = target.QueryElementKind(); + this.SourceName = source.Name; + this.TargetName = target.Name; + } + + /// + /// Gets the name of the target + /// + private string TargetName { get; } + + /// + /// Gets the name of the source + /// + private string SourceName { get; set; } + + /// + /// Gets the source 's kind + /// + private string SourceKind { get; } + + /// + /// Gets the target 's kind + /// + private string TargetKind { get; } + + /// + /// Gets the id of the target + /// + private int TargetId { get; } + + /// + /// Gets the id of the source + /// + private int SourceId { get; } + + /// + /// Gets the applied stereotype to the + /// + private string ConnectorStereotype { get; } + + /// + /// Gets the type of the + /// + private string ConnectorType { get; } + + /// + /// Gets the 's name for the opposite + /// + /// The id of an , either the source or the target + /// The 's name of the opposite + /// If the provided id neither the source or target + public string GetOppositeElementName(int currentElementId) + { + return this.IsSource(currentElementId) ? this.TargetName : this.SourceName; + } + + /// + /// Computes the full name of a connector. The full name is computed as following : + /// - Type + /// - Stereotype + /// - Is tied element the source or target + /// - Opposite Element Kind + /// + /// The id of the + /// The computed Connector full name + public string ComputeConnectorKindFullName(int currentElementId) + { + this.VerifyValidElementId(currentElementId); + + var nameParts = new List { this.ConnectorType }; + + if (!string.IsNullOrEmpty(this.ConnectorStereotype)) + { + nameParts.Add(this.ConnectorStereotype); + } + + nameParts.Add(this.IsSource(currentElementId) ? "With Target" : "With Source"); + nameParts.Add(this.GetOppositeElementKind(currentElementId)); + return string.Join(" ", nameParts); + } + + /// + /// Gets the 's kind for the opposite + /// + /// The id of an , either the source or the target + /// The 's kind of the opposite + /// If the provided id neither the source or target + private string GetOppositeElementKind(int currentElementId) + { + return this.IsSource(currentElementId) ? this.TargetKind : this.SourceKind; + } + + /// + /// Asserts that the provided id is the source of the + /// + /// The id + /// The asserts + /// If the provided id neither the source or target + private bool IsSource(int currentElementId) + { + this.VerifyValidElementId(currentElementId); + return this.SourceId == currentElementId; + } + + /// + /// Verifies that the provided id is valid, either the id of the source or of the target + /// + /// The id to validate + /// If the provided id neither the source or target + private void VerifyValidElementId(int elementId) + { + if (elementId != this.SourceId && elementId != this.TargetId) + { + throw new ArgumentException($"The provided Element ID ({elementId}) is neither related to the source ({this.SourceId}) or the target ({this.TargetId})."); + } + } + } +} diff --git a/EA-ModelKit/Model/Slims/SlimElement.cs b/EA-ModelKit/Model/Slims/SlimElement.cs index b873c74..302e92b 100644 --- a/EA-ModelKit/Model/Slims/SlimElement.cs +++ b/EA-ModelKit/Model/Slims/SlimElement.cs @@ -25,29 +25,41 @@ namespace EAModelKit.Model.Slims using EA; + using EAModelKit.Extensions; + /// - /// Slim class for + /// Slim class for /// internal class SlimElement { /// /// Initializes a new instance of /// - /// The associated - /// The associated collection of - public SlimElement(Element element, IReadOnlyList taggedValues) + /// The associated + /// The associated collection of + /// The associated collection of + public SlimElement(Element element, IReadOnlyCollection taggedValues, IReadOnlyCollection connectors) { this.Name = element.Name; this.Notes = element.Notes; this.Alias = element.Alias; this.ElementType = element.Type; this.Stereotype = element.Stereotype; - this.ElementKind = string.IsNullOrEmpty(this.Stereotype) ? this.ElementType : this.Stereotype; - + this.ElementKind = element.QueryElementKind(); + this.ElementId = element.ElementID; + this.TaggedValues = taggedValues.GroupBy(x => x.Name) - .ToDictionary(x => x.Key, IReadOnlyList (x) => x.ToList()); + .ToDictionary(x => x.Key, IReadOnlyCollection (x) => x.ToList()); + + this.Connectors = connectors.GroupBy(x => x.ComputeConnectorKindFullName(this.ElementId)) + .ToDictionary(x => x.Key, IReadOnlyCollection (x) => x.ToList()); } + /// + /// Gets the ID on the associated + /// + public int ElementId { get; } + /// /// Gets the type of the /// @@ -64,23 +76,28 @@ public SlimElement(Element element, IReadOnlyList taggedValues) public string ElementKind { get; } /// - /// Gets the 's name + /// Gets the 's name /// public string Name { get; } /// - /// Gets the 's alias + /// Gets the 's alias /// public string Alias { get; } /// - /// Gets the 's Notes + /// Gets the 's Notes /// public string Notes { get; } - + + /// + /// Gets the associated dictionary of , grouped by TaggedValueName + /// + public IReadOnlyDictionary> TaggedValues { get; } + /// - /// Gets the associated dictionary of , grouped by TaggedValueName + /// Gets the associated collection of , grouped by the computed connectors full kind name /// - public IReadOnlyDictionary> TaggedValues { get; } + public IReadOnlyDictionary> Connectors { get; } } } diff --git a/EA-ModelKit/Services/Cache/CacheService.cs b/EA-ModelKit/Services/Cache/CacheService.cs index 19c47fb..a811871 100644 --- a/EA-ModelKit/Services/Cache/CacheService.cs +++ b/EA-ModelKit/Services/Cache/CacheService.cs @@ -35,6 +35,11 @@ namespace EAModelKit.Services.Cache /// internal class CacheService : ICacheService { + /// + /// Cache Dictiornary for all casted + /// + private readonly Dictionary cachedConnectors = new(); + /// /// The that should be use to perform queries /// @@ -59,7 +64,7 @@ public void Initialize(Repository repository) this.resetOnNextQuery = true; this.currentRepository = repository; } - + /// /// Get all contained by an /// @@ -82,13 +87,65 @@ public IReadOnlyList GetTaggedValues(int[] elementIds) var taggedValues = elementIds .AsParallel() - .SelectMany(id => this.taggedValuesPerElement.TryGetValue(id, out var cachedTaggedValues) - ? cachedTaggedValues + .SelectMany(id => this.taggedValuesPerElement.TryGetValue(id, out var cachedTaggedValues) + ? cachedTaggedValues : Enumerable.Empty()); return taggedValues.ToList(); } + /// + /// Gets all linked to an , + /// + /// The id of the + /// A collection of + public IReadOnlyList GetAssociatedConnectors(int elementId) + { + this.VerifyNeedReset(); + + var sqlQuery = $"SELECT Connector_ID from t_connector where Start_Object_ID={elementId} or End_Object_ID={elementId}"; + var sqlResult = this.currentRepository.SQLQuery(sqlQuery); + var xElement = XElement.Parse(sqlResult); + var xRows = xElement.Descendants("Row"); + + var connectorIds = xRows.Select(r => int.Parse(r.Elements().First(XElementHelper.MatchElementByName("Connector_ID")).Value, CultureInfo.InvariantCulture)); + var connectors = new List(); + var connectorsToBeCasted = new List(); + var elementsId = new HashSet(); + + foreach (var connectorId in connectorIds) + { + if (this.cachedConnectors.TryGetValue(connectorId, out var cachedSlimConnector)) + { + connectors.Add(cachedSlimConnector); + } + else + { + var connector = this.currentRepository.GetConnectorByID(connectorId); + connectorsToBeCasted.Add(connector); + elementsId.Add(connector.ClientID); + elementsId.Add(connector.SupplierID); + } + } + + if (elementsId.Count != 0) + { + var resolvedElements = this.currentRepository.GetElementSet(string.Join(",", elementsId), 0).OfType() + .ToDictionary(x => x.ElementID, x => x); + + foreach (var connectorToBeCasted in connectorsToBeCasted) + { + var slimConnector = new SlimConnector(connectorToBeCasted, resolvedElements[connectorToBeCasted.ClientID], + resolvedElements[connectorToBeCasted.SupplierID]); + + this.cachedConnectors.Add(connectorToBeCasted.ConnectorID, slimConnector); + connectors.Add(slimConnector); + } + } + + return connectors; + } + /// /// Verifies if cache should be reset or not /// @@ -100,6 +157,7 @@ private void VerifyNeedReset() } this.CacheSlimTaggedValues(); + this.cachedConnectors.Clear(); this.resetOnNextQuery = false; } diff --git a/EA-ModelKit/Services/Cache/ICacheService.cs b/EA-ModelKit/Services/Cache/ICacheService.cs index cd25241..8136645 100644 --- a/EA-ModelKit/Services/Cache/ICacheService.cs +++ b/EA-ModelKit/Services/Cache/ICacheService.cs @@ -50,5 +50,12 @@ internal interface ICacheService /// The ID of the container /// All contained IReadOnlyList GetTaggedValues(int elementId); + + /// + /// Gets all linked to an , + /// + /// The id of the + /// A collection of + IReadOnlyList GetAssociatedConnectors(int elementId); } } diff --git a/EA-ModelKit/Services/Exporter/GenericExporterService.cs b/EA-ModelKit/Services/Exporter/GenericExporterService.cs index 8036a7d..d8a4ef9 100644 --- a/EA-ModelKit/Services/Exporter/GenericExporterService.cs +++ b/EA-ModelKit/Services/Exporter/GenericExporterService.cs @@ -71,7 +71,7 @@ public async Task ExportElementsAsync(string filePath, IReadOnlyList new ExportableElement(x, elementsConfiguration.ExportableTaggedValues)) + .Select(x => new ExportableElement(x, elementsConfiguration.ExportableTaggedValues, elementsConfiguration.ExportableConnectors)) .ToList(); } diff --git a/EA-ModelKit/ViewModels/Exporter/GenericExportSetupViewModel.cs b/EA-ModelKit/ViewModels/Exporter/GenericExportSetupViewModel.cs index 80cadc9..4cc4809 100644 --- a/EA-ModelKit/ViewModels/Exporter/GenericExportSetupViewModel.cs +++ b/EA-ModelKit/ViewModels/Exporter/GenericExportSetupViewModel.cs @@ -36,9 +36,9 @@ namespace EAModelKit.ViewModels.Exporter internal class GenericExportSetupViewModel : ReactiveObject, IGenericExportSetupViewModel { /// - /// Backing field for + /// Backing field for /// - private IEnumerable availableTaggedValuesForExport; + private IEnumerable selectedConnectorsForExport; /// /// Backing field for @@ -67,16 +67,47 @@ public GenericExportSetupViewModel(IReadOnlyList elements) } this.ElementKind = elements[0].ElementKind; + this.ElementType = elements[0].ElementType; this.AvailableTaggedValuesForExport = elements .SelectMany(x => x.TaggedValues.Keys) .Distinct() .OrderBy(x => x); + this.AvailableConnectorsForExport = elements + .SelectMany(x => x.Connectors.Keys) + .Distinct() + .OrderBy(x => x); + this.SelectedTaggedValuesForExport = [..this.AvailableTaggedValuesForExport]; + this.SelectedConnectorsForExport = [..this.AvailableConnectorsForExport]; this.ExportableElements = elements; } + /// + /// Gets the Type + /// + public string ElementType { get; } + + /// + /// Gets the collection of available Connectors kind that could be exported + /// + public IEnumerable AvailableConnectorsForExport { get; } + + /// + /// Gets or sets the collection of selected Connectors kind that have to be exported + /// + public IEnumerable SelectedConnectorsForExport + { + get => this.selectedConnectorsForExport; + set => this.RaiseAndSetIfChanged(ref this.selectedConnectorsForExport, value); + } + + /// + /// Asserts that any Connector are available for export + /// + public bool HaveAnyConnectors => this.AvailableConnectorsForExport.Any(); + /// /// Gets the collection of exportable tied to this setup /// @@ -111,12 +142,8 @@ public bool ShouldBeExported } /// - /// Gets or sets the collection of available TaggedValues name that could be exported + /// Gets the collection of available TaggedValues name that could be exported /// - public IEnumerable AvailableTaggedValuesForExport - { - get => this.availableTaggedValuesForExport; - set => this.RaiseAndSetIfChanged(ref this.availableTaggedValuesForExport, value); - } + public IEnumerable AvailableTaggedValuesForExport { get; } } } diff --git a/EA-ModelKit/ViewModels/Exporter/GenericExporterViewModel.cs b/EA-ModelKit/ViewModels/Exporter/GenericExporterViewModel.cs index 38c0bf2..1530464 100644 --- a/EA-ModelKit/ViewModels/Exporter/GenericExporterViewModel.cs +++ b/EA-ModelKit/ViewModels/Exporter/GenericExporterViewModel.cs @@ -53,6 +53,11 @@ internal class GenericExporterViewModel : BaseDialogViewModel, IGenericExporterV /// private readonly ICacheService cacheService; + /// + /// Gets the injected + /// + private readonly IGenericExporterService exporterService; + /// /// The injected /// @@ -64,14 +69,19 @@ internal class GenericExporterViewModel : BaseDialogViewModel, IGenericExporterV private bool canProceed; /// - /// Backing field for + /// Backing field for /// - private string selectedFilePath; + private bool haveSelectedExportSetup; /// - /// Gets the injected + /// Backing field for /// - private readonly IGenericExporterService exporterService; + private IGenericExportSetupViewModel selectedExportSetup; + + /// + /// Backing field for + /// + private string selectedFilePath; /// /// Initialize a new instance of @@ -79,7 +89,7 @@ internal class GenericExporterViewModel : BaseDialogViewModel, IGenericExporterV /// The /// The injected /// The injected - /// The injected + /// The injected public GenericExporterViewModel(ILoggerService loggerService, ICacheService cacheService, IViewBuilderService viewBuilderService, IGenericExporterService exporterService) : base(loggerService) { @@ -109,7 +119,7 @@ public bool CanProceed /// /// Gets the of /// - public SourceList ExportSetups { get; } = new(); + public SourceList AvailableExportSetups { get; } = new(); /// /// Gets the that allows the selection of the output file @@ -121,6 +131,24 @@ public bool CanProceed /// public ReactiveCommand ExportCommand { get; private set; } + /// + /// Gets or sets the currently selected + /// + public IGenericExportSetupViewModel SelectedExportSetup + { + get => this.selectedExportSetup; + set => this.RaiseAndSetIfChanged(ref this.selectedExportSetup, value); + } + + /// + /// Asserts that the an is selected or not + /// + public bool HaveSelectedExportSetup + { + get => this.haveSelectedExportSetup; + private set => this.RaiseAndSetIfChanged(ref this.haveSelectedExportSetup, value); + } + /// /// Initialies properties of the ViewModel /// @@ -143,11 +171,15 @@ public void InitializeViewModel(IReadOnlyList elements) var slimElements = elements.Select(x => new SlimElement(x, taggedValues.TryGetValue(x.ElementID, out var existingTaggedValues) ? existingTaggedValues - : [])); + : [], this.cacheService.GetAssociatedConnectors(x.ElementID))); - this.ExportSetups.AddRange(slimElements.GroupBy(x => x.ElementKind) - .Select(e => new GenericExportSetupViewModel(e.ToList()))); + this.AvailableExportSetups.AddRange(slimElements + .GroupBy(x => x.ElementKind) + .Select(e => new GenericExportSetupViewModel(e.ToList())) + .OrderBy(x => x.ElementType) + .ThenBy(x => x.ElementKind)); + this.SelectedExportSetup = this.AvailableExportSetups.Items[0]; this.InitializeObservablesAndCommands(); } @@ -158,10 +190,14 @@ private void InitializeObservablesAndCommands() { this.OutputFileCommand = ReactiveCommand.Create(this.OnOutputFileSelect); - this.Disposables.Add(this.ExportSetups.Connect().WhenPropertyChanged(x => x.ShouldBeExported) + this.Disposables.Add(this.AvailableExportSetups.Connect().WhenPropertyChanged(x => x.ShouldBeExported) .Subscribe(_ => this.ComputeCanProceed())); this.Disposables.Add(this.WhenPropertyChanged(x => x.SelectedFilePath).Subscribe(_ => this.ComputeCanProceed())); + + this.Disposables.Add(this.WhenPropertyChanged(x => x.SelectedExportSetup) + .Subscribe(_ => this.HaveSelectedExportSetup = this.SelectedExportSetup != null)); + this.ExportCommand = ReactiveCommand.CreateFromTask(this.OnExportAsync, this.WhenAnyValue(x => x.CanProceed)); } @@ -174,9 +210,10 @@ private async Task OnExportAsync() try { - var exportConfiguration = this.ExportSetups.Items.Where(x => x.ShouldBeExported) - .Select(x => new GenericExportConfiguration(x.ExportableElements, x.SelectedTaggedValuesForExport.ToList())); - + var exportConfiguration = this.AvailableExportSetups.Items.Where(x => x.ShouldBeExported) + .Select(x => new GenericExportConfiguration(x.ExportableElements, + [..x.SelectedTaggedValuesForExport], [..x.SelectedConnectorsForExport])); + await this.exporterService.ExportElementsAsync(this.selectedFilePath, [..exportConfiguration]); this.CloseWindowBehavior.Close(); } @@ -201,7 +238,7 @@ private void ComputeCanProceed() return; } - this.CanProceed = this.ExportSetups.Items.Any(x => x.ShouldBeExported); + this.CanProceed = this.AvailableExportSetups.Items.Any(x => x.ShouldBeExported); } /// diff --git a/EA-ModelKit/ViewModels/Exporter/IGenericExportSetupViewModel.cs b/EA-ModelKit/ViewModels/Exporter/IGenericExportSetupViewModel.cs index b7db725..7dd03c7 100644 --- a/EA-ModelKit/ViewModels/Exporter/IGenericExportSetupViewModel.cs +++ b/EA-ModelKit/ViewModels/Exporter/IGenericExportSetupViewModel.cs @@ -48,18 +48,38 @@ internal interface IGenericExportSetupViewModel: INotifyPropertyChanged bool ShouldBeExported { get; set; } /// - /// Gets or sets the collection of available TaggedValues name that could be exported + /// Gets the collection of available TaggedValues name that could be exported /// - IEnumerable AvailableTaggedValuesForExport { get; set; } + IEnumerable AvailableTaggedValuesForExport { get; } /// /// Asserts that any TaggedValue are available for export /// bool HaveAnyTaggedValues { get; } + /// + /// Asserts that any Connector are available for export + /// + bool HaveAnyConnectors { get; } + /// /// Gets the collection of exportable tied to this setup /// IReadOnlyList ExportableElements { get; } + + /// + /// Gets the collection of available Connectors kind that could be exported + /// + IEnumerable AvailableConnectorsForExport { get; } + + /// + /// Gets or sets the collection of selected Connectors kind that have to be exported + /// + IEnumerable SelectedConnectorsForExport { get; set; } + + /// + /// Gets the Type + /// + string ElementType { get; } } } diff --git a/EA-ModelKit/ViewModels/Exporter/IGenericExporterViewModel.cs b/EA-ModelKit/ViewModels/Exporter/IGenericExporterViewModel.cs index 708385e..7527333 100644 --- a/EA-ModelKit/ViewModels/Exporter/IGenericExporterViewModel.cs +++ b/EA-ModelKit/ViewModels/Exporter/IGenericExporterViewModel.cs @@ -39,7 +39,7 @@ internal interface IGenericExporterViewModel : IBaseDialogViewModel /// /// Gets the of /// - SourceList ExportSetups { get; } + SourceList AvailableExportSetups { get; } /// /// Gets the path to the file that should be use for export @@ -61,6 +61,16 @@ internal interface IGenericExporterViewModel : IBaseDialogViewModel /// ReactiveCommand ExportCommand { get; } + /// + /// Gets or sets the currently selected + /// + IGenericExportSetupViewModel SelectedExportSetup { get; set; } + + /// + /// Asserts that the an is selected or not + /// + bool HaveSelectedExportSetup { get; } + /// /// Initialies properties of the ViewModel /// diff --git a/EA-ModelKit/Views/Export/GenericExport.xaml b/EA-ModelKit/Views/Export/GenericExport.xaml index 8538a7a..10f5e2a 100644 --- a/EA-ModelKit/Views/Export/GenericExport.xaml +++ b/EA-ModelKit/Views/Export/GenericExport.xaml @@ -3,18 +3,18 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:local="clr-namespace:EAModelKit.Views.Export" xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm" xmlns:behaviors="clr-namespace:EAModelKit.Behaviors" - xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors" + xmlns:export="clr-namespace:EAModelKit.Views.Export" + xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid" xmlns:converters="clr-namespace:EAModelKit.Converters" mc:Ignorable="d" Title="Generic Export" MinHeight="100" Height="Auto" + MaxWidth="1000" SizeToContent="Height" - MaxWidth="600" Topmost="{Binding IsTopMost}" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" @@ -25,10 +25,7 @@ - - - - + @@ -45,74 +42,48 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Selected Output File: - - -