From 4cc411582d53c2ce750c4e3bc15cbfa17371a58a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Rua?= <140734849+joao4all@users.noreply.github.com> Date: Mon, 3 Jun 2024 11:51:07 +0100 Subject: [PATCH] Feat #613 [Engineering Model] Refactor Options page to be inline with Measurement Scale page (#653) --- .../OptionsTableTestFixture.cs | 109 +++++++++--------- .../EngineeringModel/OptionsForm.razor | 5 +- .../EngineeringModel/OptionsTable.razor | 99 ++++++---------- .../EngineeringModel/OptionsTable.razor.cs | 82 ++++++------- .../EngineeringModelsForm.razor | 3 +- .../Options/OptionsTableViewModel.cs | 49 ++++---- 6 files changed, 163 insertions(+), 184 deletions(-) diff --git a/COMETwebapp.Tests/Components/EngineeringModel/OptionsTableTestFixture.cs b/COMETwebapp.Tests/Components/EngineeringModel/OptionsTableTestFixture.cs index 2bb74b45..79799b79 100644 --- a/COMETwebapp.Tests/Components/EngineeringModel/OptionsTableTestFixture.cs +++ b/COMETwebapp.Tests/Components/EngineeringModel/OptionsTableTestFixture.cs @@ -1,32 +1,29 @@ // -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2023-2024 Starion Group S.A. -// -// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Antoine Théate, João Rua -// -// This file is part of CDP4-COMET WEB Community Edition -// The CDP4-COMET WEB Community Edition is the Starion Web Application implementation of ECSS-E-TM-10-25 Annex A and Annex C. -// -// The CDP4-COMET WEB Community Edition is free software; you can redistribute it and/or -// modify it under the terms of the GNU Affero General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// The CDP4-COMET WEB Community Edition is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// +// Copyright (c) 2024 Starion Group S.A. +// +// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Théate Antoine, João Rua +// +// This file is part of COMET WEB Community Edition +// The COMET WEB Community Edition is the Starion Group Web Application implementation of ECSS-E-TM-10-25 Annex A and Annex C. +// +// The COMET WEB Community Edition is free software; you can redistribute it and/or +// modify it under the terms of the GNU Affero General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// The COMET WEB Community Edition is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Affero General Public License for more details. -// +// // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -// -// -------------------------------------------------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------------------------------------------------- namespace COMETwebapp.Tests.Components.EngineeringModel { - using System.Linq; - using System.Threading.Tasks; - using Bunit; using CDP4Common.EngineeringModelData; @@ -63,24 +60,21 @@ public void SetUp() this.context = new TestContext(); this.viewModel = new Mock(); - this.option = new Option() + this.option = new Option { Name = "A name", ShortName = "AName", - Container = new Iteration(), + Container = new Iteration() }; var rows = new SourceList(); - rows.Add(new OptionRowViewModel(this.option){ IsDefault = true}); + rows.Add(new OptionRowViewModel(this.option) { IsDefault = true }); this.viewModel.Setup(x => x.Rows).Returns(rows); this.viewModel.Setup(x => x.CurrentThing).Returns(new Option()); - + this.context.ConfigureDevExpressBlazor(); - this.renderer = this.context.RenderComponent(parameters => - { - parameters.Add(p => p.ViewModel, this.viewModel.Object); - }); + this.renderer = this.context.RenderComponent(parameters => { parameters.Add(p => p.ViewModel, this.viewModel.Object); }); } [TearDown] @@ -91,23 +85,33 @@ public void Teardown() } [Test] - public void VerifyOnInitialized() + public async Task VerifyCreateOption() { + var addOptionButton = this.renderer.FindComponents().First(x => x.Instance.Id == "dataItemDetailsButton"); + await this.renderer.InvokeAsync(addOptionButton.Instance.Click.InvokeAsync); + var form = this.renderer.FindComponent(); + Assert.Multiple(() => { - Assert.That(this.renderer.Instance.ShouldCreateThing, Is.EqualTo(false)); - Assert.That(this.renderer.Instance.ViewModel, Is.EqualTo(this.viewModel.Object)); - Assert.That(this.renderer.Markup, Does.Contain(this.option.Name)); - this.viewModel.Verify(x => x.InitializeViewModel(), Times.Once); + Assert.That(form, Is.Not.Null); + Assert.That(form.Instance.IsVisible, Is.EqualTo(true)); + Assert.That(form.Instance.ShouldCreate, Is.EqualTo(true)); }); + + var editForm = form.FindComponent(); + await form.InvokeAsync(editForm.Instance.OnValidSubmit.InvokeAsync); + this.viewModel.Verify(x => x.CreateOrEditOption(true), Times.Once); } [Test] public async Task VerifyDeleteOption() { - var deleteButton = this.renderer.FindComponents().First(x => x.Instance.Id == "deleteButton"); + var grid = this.renderer.FindComponent(); + await this.renderer.InvokeAsync(() => grid.Instance.SelectedDataItemChanged.InvokeAsync(this.viewModel.Object.Rows.Items.First())); + + var deleteButton = this.renderer.FindComponents().First(x => x.Instance.Id == "deleteItemButton"); await this.renderer.InvokeAsync(deleteButton.Instance.Click.InvokeAsync); - this.viewModel.Verify(x => x.OnDeleteButtonClick(It.IsAny()), Times.Once); + this.viewModel.VerifySet(x => x.IsOnDeletionMode = true, Times.Once); this.viewModel.Setup(x => x.IsOnDeletionMode).Returns(true); this.renderer.Render(); @@ -118,25 +122,6 @@ public async Task VerifyDeleteOption() this.viewModel.Verify(x => x.OnConfirmPopupButtonClick(), Times.Once); } - [Test] - public async Task VerifyCreateOption() - { - var addOptionButton = this.renderer.FindComponents().First(x => x.Instance.Id == "addOptionButton"); - await this.renderer.InvokeAsync(addOptionButton.Instance.Click.InvokeAsync); - var form = this.renderer.FindComponent(); - - Assert.Multiple(() => - { - Assert.That(form, Is.Not.Null); - Assert.That(form.Instance.IsVisible, Is.EqualTo(true)); - Assert.That(form.Instance.ShouldCreate, Is.EqualTo(true)); - }); - - var editForm = form.FindComponent(); - await form.InvokeAsync(editForm.Instance.OnValidSubmit.InvokeAsync); - this.viewModel.Verify(x => x.CreateOrEditOption(true), Times.Once); - } - [Test] public async Task VerifyEditOption() { @@ -161,5 +146,17 @@ public async Task VerifyEditOption() await editForm.InvokeAsync(cancelButton.Instance.Click.InvokeAsync); Assert.That(this.renderer.Instance.IsOnEditMode, Is.EqualTo(false)); } + + [Test] + public void VerifyOnInitialized() + { + Assert.Multiple(() => + { + Assert.That(this.renderer.Instance.ShouldCreateThing, Is.EqualTo(false)); + Assert.That(this.renderer.Instance.ViewModel, Is.EqualTo(this.viewModel.Object)); + Assert.That(this.renderer.Markup, Does.Contain(this.option.Name)); + this.viewModel.Verify(x => x.InitializeViewModel(), Times.Once); + }); + } } } diff --git a/COMETwebapp/Components/EngineeringModel/OptionsForm.razor b/COMETwebapp/Components/EngineeringModel/OptionsForm.razor index 336e7ca3..391434ab 100644 --- a/COMETwebapp/Components/EngineeringModel/OptionsForm.razor +++ b/COMETwebapp/Components/EngineeringModel/OptionsForm.razor @@ -31,5 +31,8 @@ Copyright (c) 2023-2024 Starion Group S.A. + OnDelete="@(() => this.ViewModel.IsOnDeletionMode = true)" + DeleteButtonVisible="@(!this.ShouldCreate)" + ValidationMessages="@(this.MapOfValidationMessages.SelectMany(x => x.Value))" + IsLoading="@(this.ViewModel.IsLoading)" /> diff --git a/COMETwebapp/Components/EngineeringModel/OptionsTable.razor b/COMETwebapp/Components/EngineeringModel/OptionsTable.razor index 9d4c84e3..d5d634bd 100644 --- a/COMETwebapp/Components/EngineeringModel/OptionsTable.razor +++ b/COMETwebapp/Components/EngineeringModel/OptionsTable.razor @@ -16,70 +16,45 @@ Copyright (c) 2023-2024 Starion Group S.A. -------------------------------------------------------------------------------> @inherits SelectedDataItemBase - -
- - - - - - - - - - - @{ - var row = (OptionRowViewModel)context.DataItem; +
+ + + + + + + - - } - - - + - - - - - - - - -
- + + +
- - @this.ViewModel.PopupDialog + + @(this.ViewModel.PopupDialog)
- - + +
-
+
\ No newline at end of file diff --git a/COMETwebapp/Components/EngineeringModel/OptionsTable.razor.cs b/COMETwebapp/Components/EngineeringModel/OptionsTable.razor.cs index 4db84854..e56b5222 100644 --- a/COMETwebapp/Components/EngineeringModel/OptionsTable.razor.cs +++ b/COMETwebapp/Components/EngineeringModel/OptionsTable.razor.cs @@ -1,26 +1,26 @@ // -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2023-2024 Starion Group S.A. -// -// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Théate Antoine, João Rua -// -// This file is part of CDP4-COMET WEB Community Edition -// The CDP4-COMET WEB Community Edition is the Starion Web Application implementation of ECSS-E-TM-10-25 Annex A and Annex C. -// -// The CDP4-COMET WEB Community Edition is free software; you can redistribute it and/or -// modify it under the terms of the GNU Affero General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// The CDP4-COMET WEB Community Edition is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// +// Copyright (c) 2024 Starion Group S.A. +// +// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Théate Antoine, João Rua +// +// This file is part of COMET WEB Community Edition +// The COMET WEB Community Edition is the Starion Group Web Application implementation of ECSS-E-TM-10-25 Annex A and Annex C. +// +// The COMET WEB Community Edition is free software; you can redistribute it and/or +// modify it under the terms of the GNU Affero General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// The COMET WEB Community Edition is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Affero General Public License for more details. -// +// // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -// -// -------------------------------------------------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------------------------------------------------- namespace COMETwebapp.Components.EngineeringModel { @@ -28,6 +28,8 @@ namespace COMETwebapp.Components.EngineeringModel using CDP4Common.EngineeringModelData; + using COMET.Web.Common.Extensions; + using COMETwebapp.Components.Common; using COMETwebapp.ViewModels.Components.EngineeringModel.Options; using COMETwebapp.ViewModels.Components.EngineeringModel.Rows; @@ -36,15 +38,18 @@ namespace COMETwebapp.Components.EngineeringModel using Microsoft.AspNetCore.Components; + using ReactiveUI; + /// - /// Support class for the + /// Support class for the /// public partial class OptionsTable : SelectedDataItemBase { /// /// The for this component /// - [Parameter, Required] + [Parameter] + [Required] public IOptionsTableViewModel ViewModel { get; set; } /// @@ -55,20 +60,7 @@ protected override void OnInitialized() { base.OnInitialized(); this.Initialize(this.ViewModel); - } - - /// - /// Method invoked when creating a new thing - /// - /// A - protected override void CustomizeEditThing(GridCustomizeEditModelEventArgs e) - { - base.CustomizeEditThing(e); - - var dataItem = (OptionRowViewModel)e.DataItem; - this.ViewModel.CurrentThing = dataItem == null ? new Option().Clone(true) : dataItem.Thing.Clone(true); - e.EditModel = this.ViewModel.CurrentThing; - this.IsOnEditMode = false; + this.Disposables.Add(this.WhenAnyValue(x => x.ViewModel.IsOnDeletionMode).SubscribeAsync(_ => this.InvokeAsync(this.StateHasChanged))); } /// @@ -78,14 +70,26 @@ protected override void CustomizeEditThing(GridCustomizeEditModelEventArgs e) protected override void OnSelectedDataItemChanged(OptionRowViewModel row) { base.OnSelectedDataItemChanged(row); + this.ShouldCreateThing = false; this.ViewModel.CurrentThing = row.Thing.Clone(true); } /// - /// Method invoked when the deletion popup is confirmed + /// Method invoked before creating a new thing + /// + private void OnAddThingClick() + { + this.ShouldCreateThing = true; + this.IsOnEditMode = true; + this.ViewModel.CurrentThing = new Option(); + this.InvokeAsync(this.StateHasChanged); + } + + /// + /// Method invoked when the deletion of a thing is confirmed /// - /// - private async Task OnConfirmDelete() + /// A + private async Task OnDeletionConfirmed() { await this.ViewModel.OnConfirmPopupButtonClick(); this.IsOnEditMode = false; @@ -94,7 +98,7 @@ private async Task OnConfirmDelete() /// /// Method invoked to "Show/Hide Deprecated Items" /// - /// The + /// The private static void HighlightDefaultOptionRow(GridCustomizeElementEventArgs e) { if (e.ElementType == GridElementType.DataRow && (bool)e.Grid.GetRowValue(e.VisibleIndex, nameof(OptionRowViewModel.IsDefault))) diff --git a/COMETwebapp/Components/SiteDirectory/EngineeringModel/EngineeringModelsForm.razor b/COMETwebapp/Components/SiteDirectory/EngineeringModel/EngineeringModelsForm.razor index a12be4a1..742c2eb2 100644 --- a/COMETwebapp/Components/SiteDirectory/EngineeringModel/EngineeringModelsForm.razor +++ b/COMETwebapp/Components/SiteDirectory/EngineeringModel/EngineeringModelsForm.razor @@ -84,5 +84,4 @@ Copyright (c) 2024 Starion Group S.A. OnDelete="@(() => this.ViewModel.IsOnDeletionMode = true)" DeleteButtonVisible="@(!this.ShouldCreate)" ValidationMessages="@(this.MapOfValidationMessages.SelectMany(x => x.Value))"/> - - \ No newline at end of file + diff --git a/COMETwebapp/ViewModels/Components/EngineeringModel/Options/OptionsTableViewModel.cs b/COMETwebapp/ViewModels/Components/EngineeringModel/Options/OptionsTableViewModel.cs index a6012531..b4f2b646 100644 --- a/COMETwebapp/ViewModels/Components/EngineeringModel/Options/OptionsTableViewModel.cs +++ b/COMETwebapp/ViewModels/Components/EngineeringModel/Options/OptionsTableViewModel.cs @@ -89,37 +89,38 @@ public void SetCurrentIteration(Iteration iteration) /// A public async Task CreateOrEditOption(bool shouldCreate) { - this.IsLoading = true; - - var iterationClone = this.CurrentIteration.Clone(false); - var thingsToCreate = new List(); - var originalOption = (Option)this.CurrentThing.Original; - - iterationClone.DefaultOption = this.SelectedIsDefaultValue switch - { - true when !originalOption.IsDefault => this.CurrentThing, - false when originalOption.IsDefault => null, - _ => iterationClone.DefaultOption - }; - - if (shouldCreate) - { - iterationClone.Option.Add(this.CurrentThing); - } - - thingsToCreate.Add(iterationClone); - thingsToCreate.Add(this.CurrentThing); - try { + this.IsLoading = true; + + var iterationClone = this.CurrentIteration.Clone(false); + var thingsToCreate = new List(); + var originalOption = (Option)this.CurrentThing.Original ?? this.CurrentThing; + + iterationClone.DefaultOption = this.SelectedIsDefaultValue switch + { + true when !originalOption.IsDefault => this.CurrentThing, + false when originalOption.IsDefault => null, + _ => iterationClone.DefaultOption + }; + + if (shouldCreate) + { + iterationClone.Option.Add(this.CurrentThing); + } + + thingsToCreate.Add(iterationClone); + thingsToCreate.Add(this.CurrentThing); await this.SessionService.CreateOrUpdateThingsWithNotification(this.CurrentIteration.Container.Clone(true), thingsToCreate, this.GetNotificationDescription(shouldCreate)); } catch (Exception ex) { - this.Logger.LogError(ex, "An error has occurred while creating or editing an Option"); + this.Logger.LogError(ex, "Create or Update Option failed"); + } + finally + { + this.IsLoading = false; } - - this.IsLoading = false; } ///