From 1611f87990c9627f9becaef27109bb8ab7b07c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Th=C3=A9ate?= <97221392+antoineatrhea@users.noreply.github.com> Date: Mon, 8 Jan 2024 09:17:40 +0100 Subject: [PATCH] Fix #475: Added EngineeringModelId inside Template and improvement (#492) --- .dockerignore | 3 +- .gitignore | 2 + ...ringModelApplicationTemplateTestFixture.cs | 203 ++++++++++++++++++ ...IterationApplicationTemplateTestFixture.cs | 16 +- COMET.Web.Common/COMET.Web.Common.csproj | 2 +- ...eEngineeringModelApplicationTemplate.razor | 2 +- ...gineeringModelApplicationTemplate.razor.cs | 66 +++++- ...ingleIterationApplicationTemplate.razor.cs | 21 +- ...leIterationApplicationTemplateViewModel.cs | 2 +- .../ModelDashboardTestFixture.cs | 2 +- .../ParameterEditorTestFixture.cs | 2 +- .../Pages/Viewer/ViewerTestFixture.cs | 2 +- COMETwebapp.sln.DotSettings | 5 +- 13 files changed, 303 insertions(+), 25 deletions(-) create mode 100644 COMET.Web.Common.Tests/Components/Applications/SingleEngineeringModelApplicationTemplateTestFixture.cs diff --git a/.dockerignore b/.dockerignore index cf34eb6d..bac51aa4 100644 --- a/.dockerignore +++ b/.dockerignore @@ -14,4 +14,5 @@ **/docker-compose* **/Dockerfile* **/obj -!nginx.conf \ No newline at end of file +!nginx.conf +switcher.json \ No newline at end of file diff --git a/.gitignore b/.gitignore index d93cc446..1c0c0a38 100644 --- a/.gitignore +++ b/.gitignore @@ -352,3 +352,5 @@ MigrationBackup/ # Jetbrains folders .idea/ + +switcher.json \ No newline at end of file diff --git a/COMET.Web.Common.Tests/Components/Applications/SingleEngineeringModelApplicationTemplateTestFixture.cs b/COMET.Web.Common.Tests/Components/Applications/SingleEngineeringModelApplicationTemplateTestFixture.cs new file mode 100644 index 00000000..41191f2a --- /dev/null +++ b/COMET.Web.Common.Tests/Components/Applications/SingleEngineeringModelApplicationTemplateTestFixture.cs @@ -0,0 +1,203 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2024 RHEA System S.A. +// +// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Théate Antoine +// +// This file is part of COMET WEB Community Edition +// The COMET WEB Community Edition is the RHEA Web Application implementation of ECSS-E-TM-10-25 +// Annex A and Annex C. +// +// 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 COMET.Web.Common.Tests.Components.Applications +{ + using Bunit; + + using CDP4Common.EngineeringModelData; + using CDP4Common.Extensions; + + using CDP4Dal; + + using COMET.Web.Common.Components; + using COMET.Web.Common.Components.Applications; + using COMET.Web.Common.Components.Selectors; + using COMET.Web.Common.Model.Configuration; + using COMET.Web.Common.Services.ConfigurationService; + using COMET.Web.Common.Services.SessionManagement; + using COMET.Web.Common.Services.StringTableService; + using COMET.Web.Common.Test.Helpers; + using COMET.Web.Common.ViewModels.Components; + using COMET.Web.Common.ViewModels.Components.Applications; + using COMET.Web.Common.ViewModels.Components.Selectors; + + using DynamicData; + + using Microsoft.AspNetCore.Components; + using Microsoft.Extensions.DependencyInjection; + + using Moq; + + using NUnit.Framework; + + using TestContext = Bunit.TestContext; + + [TestFixture] + public class SingleEngineeringModelApplicationTemplateTestFixture + { + private Mock viewModel; + private List openEngineeringModels; + private TestContext context; + + [SetUp] + public void Setup() + { + this.context = new TestContext(); + this.viewModel = new Mock(); + + this.openEngineeringModels = []; + var sessionService = new Mock(); + sessionService.Setup(x => x.OpenEngineeringModels).Returns(this.openEngineeringModels); + sessionService.Setup(x => x.OpenIterations).Returns(new SourceList()); + var session = new Mock(); + session.Setup(x => x.DataSourceUri).Returns("http://localhost:5000"); + sessionService.Setup(x => x.Session).Returns(session.Object); + this.viewModel.Setup(x => x.SessionService).Returns(sessionService.Object); + var mockConfigurationService = new Mock(); + mockConfigurationService.Setup(x => x.ServerConfiguration).Returns(new ServerConfiguration()); + this.context.Services.AddSingleton(this.viewModel.Object); + this.context.Services.AddSingleton(); + this.context.Services.AddSingleton(mockConfigurationService.Object); + this.context.Services.AddSingleton(new Mock().Object); + this.context.Services.AddSingleton(sessionService.Object); + this.context.ConfigureDevExpressBlazor(); + } + + [TearDown] + public void Teardown() + { + this.context.CleanContext(); + } + + [Test] + public void VerifyWithEngineeringModelIdParameter() + { + this.openEngineeringModels.Add(new EngineeringModel + { + Iid = Guid.NewGuid() + }); + + this.viewModel.Setup(x => x.OnThingSelect(It.IsAny())).Callback((EngineeringModel engineeringModel) => this.viewModel.Setup(x => x.SelectedThing).Returns(engineeringModel)); + var renderer = this.context.RenderComponent(parameters => { parameters.Add(p => p.EngineeringModelId, Guid.NewGuid()); }); + + Assert.Multiple(() => + { + Assert.That(renderer.Instance.EngineeringModelId, Is.EqualTo(this.openEngineeringModels[0].Iid)); + this.viewModel.Verify(x => x.OnThingSelect(this.openEngineeringModels[0]), Times.Once); + }); + + this.viewModel.Setup(x => x.SelectedThing).Returns((EngineeringModel)null); + _ = this.context.RenderComponent(parameters => { parameters.Add(p => p.EngineeringModelId, this.openEngineeringModels[0].Iid); }); + + this.viewModel.Verify(x => x.OnThingSelect(this.openEngineeringModels[0]), Times.Exactly(2)); + + this.viewModel.Setup(x => x.SelectedThing).Returns(new EngineeringModel + { + Iid = Guid.NewGuid() + }); + + renderer = this.context.RenderComponent(parameters => { parameters.Add(p => p.EngineeringModelId, this.openEngineeringModels[0].Iid); }); + + Assert.Multiple(() => + { + Assert.That(renderer.Instance.EngineeringModelId, Is.EqualTo(this.viewModel.Object.SelectedThing.Iid)); + this.viewModel.Verify(x => x.OnThingSelect(this.openEngineeringModels[0]), Times.Exactly(2)); + }); + } + + [Test] + public void VerifyWithoutEngineeringModelIdParameter() + { + this.openEngineeringModels.Add(new EngineeringModel() + { + Iid = Guid.NewGuid() + }); + + var renderer = this.context.RenderComponent(parameters => + { + parameters.Add(p => p.Body, builder => + { + builder.OpenElement(0, "p"); + builder.AddContent(1, "body"); + builder.CloseComponent(); + }); + }); + + var navigationManager = this.context.Services.GetService(); + + Assert.Multiple(() => + { + Assert.That(navigationManager.Uri, Is.EqualTo("http://localhost/")); + this.viewModel.Verify(x => x.OnThingSelect(this.openEngineeringModels[0]), Times.Exactly(2)); + }); + + this.viewModel.Setup(x => x.SelectedThing).Returns(this.openEngineeringModels[0]); + renderer.Instance.SetCorrectUrl(); + var engineeringModel = this.viewModel.Object.SelectedThing; + + Assert.Multiple(() => + { + Assert.That(navigationManager.Uri, Does.Contain("localhost%3A5000")); + Assert.That(navigationManager.Uri, Does.Contain(engineeringModel.Iid.ToShortGuid())); + }); + + renderer.Render(); + + var pElement = renderer.Find("p"); + Assert.That(pElement.TextContent, Is.EqualTo("body")); + + this.openEngineeringModels.Add(new EngineeringModel()); + + renderer = this.context.RenderComponent(parameters => + { + parameters.Add(p => p.Body, builder => + { + builder.OpenElement(0, "p"); + builder.AddContent(1, "body"); + builder.CloseComponent(); + }); + }); + + Assert.That(() => renderer.FindComponent(), Throws.Exception); + this.viewModel.Verify(x => x.AskToSelectThing(), Times.Once); + this.viewModel.Setup(x => x.IsOnSelectionMode).Returns(true); + this.viewModel.Setup(x => x.EngineeringModelSelectorViewModel).Returns(new EngineeringModelSelectorViewModel()); + renderer.Render(); + Assert.That(() => renderer.FindComponent(), Throws.Nothing); + this.openEngineeringModels.Clear(); + this.viewModel.Setup(x => x.SelectedThing).Returns((EngineeringModel)null); + renderer.Instance.SetCorrectUrl(); + + renderer.Render(); + + Assert.Multiple(() => + { + Assert.That(navigationManager.Uri, Is.EqualTo("http://localhost/")); + Assert.That(() => renderer.FindComponent(), Throws.Nothing); + }); + } + } +} diff --git a/COMET.Web.Common.Tests/Components/Applications/SingleIterationApplicationTemplateTestFixture.cs b/COMET.Web.Common.Tests/Components/Applications/SingleIterationApplicationTemplateTestFixture.cs index 0e50713c..3fde4584 100644 --- a/COMET.Web.Common.Tests/Components/Applications/SingleIterationApplicationTemplateTestFixture.cs +++ b/COMET.Web.Common.Tests/Components/Applications/SingleIterationApplicationTemplateTestFixture.cs @@ -108,13 +108,19 @@ public void VerifyWithIterationIdParameter() } }); + this.viewModel.Setup(x => x.OnThingSelect(It.IsAny())).Callback((Iteration iteration) => this.viewModel.Setup(x => x.SelectedThing).Returns(iteration)); var renderer = this.context.RenderComponent(parameters => { parameters.Add(p => p.IterationId, Guid.NewGuid()); }); - Assert.That(renderer.Instance.IterationId, Is.EqualTo(Guid.Empty)); + Assert.Multiple(() => + { + Assert.That(renderer.Instance.IterationId, Is.EqualTo(this.openIterations.Items.First().Iid)); + this.viewModel.Verify(x => x.OnThingSelect(this.openIterations.Items.First()), Times.Once); + }); + this.viewModel.Setup(x => x.SelectedThing).Returns((Iteration)null); _ = this.context.RenderComponent(parameters => { parameters.Add(p => p.IterationId, this.openIterations.Items.First().Iid); }); - this.viewModel.Verify(x => x.OnThingSelect(this.openIterations.Items.First()), Times.Once); + this.viewModel.Verify(x => x.OnThingSelect(this.openIterations.Items.First()), Times.Exactly(2)); this.viewModel.Setup(x => x.SelectedThing).Returns(new Iteration { @@ -132,8 +138,8 @@ public void VerifyWithIterationIdParameter() Assert.Multiple(() => { - Assert.That(renderer.Instance.IterationId, Is.EqualTo(this.openIterations.Items.First().Iid)); - this.viewModel.Verify(x => x.OnThingSelect(this.openIterations.Items.First()), Times.Once); + Assert.That(renderer.Instance.IterationId, Is.EqualTo(this.viewModel.Object.SelectedThing.Iid)); + this.viewModel.Verify(x => x.OnThingSelect(this.openIterations.Items.First()), Times.Exactly(2)); }); } @@ -167,7 +173,7 @@ public void VerifyWithoutIterationIdParameter() Assert.Multiple(() => { Assert.That(navigationManager.Uri, Is.EqualTo("http://localhost/")); - this.viewModel.Verify(x => x.OnThingSelect(this.openIterations.Items.First()), Times.Once); + this.viewModel.Verify(x => x.OnThingSelect(this.openIterations.Items.First()), Times.Exactly(2)); }); this.viewModel.Setup(x => x.SelectedThing).Returns(this.openIterations.Items.First()); diff --git a/COMET.Web.Common/COMET.Web.Common.csproj b/COMET.Web.Common/COMET.Web.Common.csproj index 38ce46af..a3294e2b 100644 --- a/COMET.Web.Common/COMET.Web.Common.csproj +++ b/COMET.Web.Common/COMET.Web.Common.csproj @@ -25,7 +25,7 @@ - + diff --git a/COMET.Web.Common/Components/Applications/SingleEngineeringModelApplicationTemplate.razor b/COMET.Web.Common/Components/Applications/SingleEngineeringModelApplicationTemplate.razor index d9480a1b..8541adc3 100644 --- a/COMET.Web.Common/Components/Applications/SingleEngineeringModelApplicationTemplate.razor +++ b/COMET.Web.Common/Components/Applications/SingleEngineeringModelApplicationTemplate.razor @@ -27,7 +27,7 @@ -@if (this.ViewModel.SessionService.OpenIterations.Count == 0) +@if (this.ViewModel.SessionService.OpenEngineeringModels.Count == 0) { diff --git a/COMET.Web.Common/Components/Applications/SingleEngineeringModelApplicationTemplate.razor.cs b/COMET.Web.Common/Components/Applications/SingleEngineeringModelApplicationTemplate.razor.cs index 06a50c2b..8ed19b3c 100644 --- a/COMET.Web.Common/Components/Applications/SingleEngineeringModelApplicationTemplate.razor.cs +++ b/COMET.Web.Common/Components/Applications/SingleEngineeringModelApplicationTemplate.razor.cs @@ -27,12 +27,76 @@ namespace COMET.Web.Common.Components.Applications { using CDP4Common.EngineeringModelData; - using COMET.Web.Common.ViewModels.Components.Applications; + using COMET.Web.Common.Extensions; + using COMET.Web.Common.Utilities; + + using Microsoft.AspNetCore.Components; /// /// Shared component that will englobe all applications where only one needs to be selected /// public partial class SingleEngineeringModelApplicationTemplate { + /// + /// The of selected + /// + [Parameter] + public Guid EngineeringModelId { get; set; } + + /// + /// Method invoked when the component is ready to start, having received its + /// initial parameters from its parent in the render tree. + /// + protected override void OnInitialized() + { + this.UpdateProperties(); + base.OnInitialized(); + } + + /// + /// Method invoked when the component has received parameters from its parent in + /// the render tree, and the incoming values have been assigned to properties. + /// + protected override void OnParametersSet() + { + base.OnParametersSet(); + this.UpdateProperties(); + } + + /// + /// Update properties of the viewmodel based on provided parameters + /// + private void UpdateProperties() + { + if (this.EngineeringModelId == Guid.Empty) + { + switch (this.ViewModel.SessionService.OpenEngineeringModels.Count) + { + case 1: + this.ViewModel.OnThingSelect(this.ViewModel.SessionService.OpenEngineeringModels.First()); + break; + case > 1: + this.ViewModel.AskToSelectThing(); + break; + } + } + else if (this.EngineeringModelId != Guid.Empty && this.ViewModel.SelectedThing == null) + { + this.ViewModel.OnThingSelect(this.ViewModel.SessionService.OpenEngineeringModels.FirstOrDefault(x => x.Iid == this.EngineeringModelId)); + } + + this.EngineeringModelId = this.ViewModel.SelectedThing?.Iid ?? Guid.Empty; + } + + /// + /// Set URL parameters based on the current context + /// + /// A of URL parameters + protected override void SetUrlParameters(Dictionary currentOptions) + { + base.SetUrlParameters(currentOptions); + + currentOptions[QueryKeys.ModelKey] = this.ViewModel.SelectedThing.Iid.ToShortGuid(); + } } } diff --git a/COMET.Web.Common/Components/Applications/SingleIterationApplicationTemplate.razor.cs b/COMET.Web.Common/Components/Applications/SingleIterationApplicationTemplate.razor.cs index a90bf3bc..c2fa561c 100644 --- a/COMET.Web.Common/Components/Applications/SingleIterationApplicationTemplate.razor.cs +++ b/COMET.Web.Common/Components/Applications/SingleIterationApplicationTemplate.razor.cs @@ -51,6 +51,7 @@ public partial class SingleIterationApplicationTemplate /// protected override void OnInitialized() { + this.UpdateProperties(); base.OnInitialized(); this.Disposables.Add(CDPMessageBus.Current.Listen() @@ -64,7 +65,14 @@ protected override void OnInitialized() protected override void OnParametersSet() { base.OnParametersSet(); + this.UpdateProperties(); + } + /// + /// Update properties of the viewmodel based on provided parameters + /// + private void UpdateProperties() + { if (this.IterationId == Guid.Empty) { switch (this.ViewModel.SessionService.OpenIterations.Count) @@ -79,17 +87,10 @@ protected override void OnParametersSet() } else if (this.IterationId != Guid.Empty && this.ViewModel.SelectedThing == null) { - var iteration = this.ViewModel.SessionService.OpenIterations.Items.FirstOrDefault(x => x.Iid == this.IterationId); - - if (iteration != null) - { - this.ViewModel.OnThingSelect(iteration); - } - else - { - this.IterationId = Guid.Empty; - } + this.ViewModel.OnThingSelect(this.ViewModel.SessionService.OpenIterations.Items.FirstOrDefault(x => x.Iid == this.IterationId)); } + + this.IterationId = this.ViewModel.SelectedThing?.Iid ?? Guid.Empty; } /// diff --git a/COMET.Web.Common/ViewModels/Components/Applications/SingleIterationApplicationTemplateViewModel.cs b/COMET.Web.Common/ViewModels/Components/Applications/SingleIterationApplicationTemplateViewModel.cs index 9ed70210..6a9e4fe7 100644 --- a/COMET.Web.Common/ViewModels/Components/Applications/SingleIterationApplicationTemplateViewModel.cs +++ b/COMET.Web.Common/ViewModels/Components/Applications/SingleIterationApplicationTemplateViewModel.cs @@ -62,7 +62,7 @@ public SingleIterationApplicationTemplateViewModel(ISessionService sessionServic public override void OnThingSelect(Iteration thing) { base.OnThingSelect(thing); - this.SelectedIterationData = new IterationData(thing.IterationSetup, true); + this.SelectedIterationData = thing == null ? null : new IterationData(thing.IterationSetup, true); } /// diff --git a/COMETwebapp.Tests/Pages/ModelDashboard/ModelDashboardTestFixture.cs b/COMETwebapp.Tests/Pages/ModelDashboard/ModelDashboardTestFixture.cs index 2e9c5b65..fd24b21a 100644 --- a/COMETwebapp.Tests/Pages/ModelDashboard/ModelDashboardTestFixture.cs +++ b/COMETwebapp.Tests/Pages/ModelDashboard/ModelDashboardTestFixture.cs @@ -192,7 +192,7 @@ public void VerifyIterationPreselection() parameters.Add(p => p.IterationId, this.secondIteration.Iid.ToShortGuid()); }); - Assert.That(this.viewModel.SelectedThing, Is.Null); + Assert.That(this.viewModel.SelectedThing, Is.EqualTo(this.firstIteration)); } } } diff --git a/COMETwebapp.Tests/Pages/ParameterEditor/ParameterEditorTestFixture.cs b/COMETwebapp.Tests/Pages/ParameterEditor/ParameterEditorTestFixture.cs index 3e8a81fa..a4dc362c 100644 --- a/COMETwebapp.Tests/Pages/ParameterEditor/ParameterEditorTestFixture.cs +++ b/COMETwebapp.Tests/Pages/ParameterEditor/ParameterEditorTestFixture.cs @@ -201,7 +201,7 @@ public void VerifyIterationPreselection() parameters.Add(p => p.IterationId, this.secondIteration.Iid.ToShortGuid()); }); - Assert.That(this.viewModel.SelectedThing, Is.Null); + Assert.That(this.viewModel.SelectedThing, Is.EqualTo(this.firstIteration)); } } } diff --git a/COMETwebapp.Tests/Pages/Viewer/ViewerTestFixture.cs b/COMETwebapp.Tests/Pages/Viewer/ViewerTestFixture.cs index bea12ed9..47730250 100644 --- a/COMETwebapp.Tests/Pages/Viewer/ViewerTestFixture.cs +++ b/COMETwebapp.Tests/Pages/Viewer/ViewerTestFixture.cs @@ -162,7 +162,7 @@ public void VerifyIterationPreselection() this.context.RenderComponent(parameters => { parameters.Add(p => p.IterationId, this.secondIteration.Iid.ToShortGuid()); }); - Assert.That(this.viewModel.SelectedThing, Is.Null); + Assert.That(this.viewModel.SelectedThing, Is.EqualTo(this.firstIteration)); } [Test] diff --git a/COMETwebapp.sln.DotSettings b/COMETwebapp.sln.DotSettings index 10dc2de5..d6f1c489 100644 --- a/COMETwebapp.sln.DotSettings +++ b/COMETwebapp.sln.DotSettings @@ -252,8 +252,8 @@ True True -------------------------------------------------------------------------------------------------------------------- - <copyright file="$FILENAME$" company="RHEA System S.A."> - Copyright (c) $CURRENT_YEAR$ RHEA System S.A. + <copyright file="${File.FileName}" company="RHEA System S.A."> + Copyright (c) ${CurrentDate.Year} RHEA System S.A. Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Théate Antoine @@ -282,6 +282,7 @@ False <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + True True True True