Skip to content

Commit

Permalink
Feat #659 Side by side view (#695)
Browse files Browse the repository at this point in the history
  • Loading branch information
joao4all authored Jul 16, 2024
1 parent caa3117 commit e494cd6
Show file tree
Hide file tree
Showing 19 changed files with 562 additions and 81 deletions.
8 changes: 5 additions & 3 deletions COMETwebapp.Tests/Components/Tabs/OpenTabTestFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,11 @@ public void VerifyOnInitialized()
[Test]
public async Task VerifyOpenButton()
{
var panel = new TabPanelInformation();

var openButton = this.renderer.FindComponents<DxButton>().First(x => x.Instance.Id == "opentab__button");
await this.renderer.InvokeAsync(openButton.Instance.Click.InvokeAsync);
this.viewModel.Verify(x => x.OpenTab(), Times.Once);
this.viewModel.Verify(x => x.OpenTab(It.IsAny<TabPanelInformation>()), Times.Once);

var bookEditorBodyComponent = new TabbedApplication
{
Expand All @@ -118,7 +120,7 @@ public async Task VerifyOpenButton()

this.viewModel.Setup(x => x.SelectedApplication).Returns(bookEditorBodyComponent);
await this.renderer.InvokeAsync(openButton.Instance.Click.InvokeAsync);
this.viewModel.Verify(x => x.OpenTab(), Times.Exactly(2));
this.viewModel.Verify(x => x.OpenTab(It.IsAny<TabPanelInformation>()), Times.Exactly(2));

var modelDashboardBodyComponent = new TabbedApplication
{
Expand All @@ -130,7 +132,7 @@ public async Task VerifyOpenButton()
this.viewModel.Setup(x => x.SelectedApplication).Returns(modelDashboardBodyComponent);
this.renderer.Render();
await this.renderer.InvokeAsync(openButton.Instance.Click.InvokeAsync);
this.viewModel.Verify(x => x.OpenTab(), Times.Exactly(3));
this.viewModel.Verify(x => x.OpenTab(It.IsAny<TabPanelInformation>()), Times.Exactly(3));
}
}
}
140 changes: 140 additions & 0 deletions COMETwebapp.Tests/Components/Tabs/TabsPanelComponentTestFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TabsPanelComponentTestFixture.cs" company="Starion Group S.A.">
// 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 <http://www.gnu.org/licenses/>.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace COMETwebapp.Tests.Components.Tabs
{
using Bunit;

using CDP4Common.EngineeringModelData;
using CDP4Common.SiteDirectoryData;

using COMET.Web.Common.Model.Configuration;
using COMET.Web.Common.Services.ConfigurationService;
using COMET.Web.Common.Test.Helpers;

using COMETwebapp.Components.EngineeringModel;
using COMETwebapp.Components.Tabs;
using COMETwebapp.Model;
using COMETwebapp.Utilities;
using COMETwebapp.ViewModels.Components.EngineeringModel;
using COMETwebapp.ViewModels.Components.EngineeringModel.Options;
using COMETwebapp.ViewModels.Components.EngineeringModel.Rows;
using COMETwebapp.ViewModels.Pages;

using DevExpress.Blazor;

using DynamicData;

using Microsoft.Extensions.DependencyInjection;

using Moq;

using NUnit.Framework;

using TestContext = Bunit.TestContext;

[TestFixture]
public class TabsPanelComponentTestFixture
{
private TestContext context;
private IRenderedComponent<TabsPanelComponent> renderer;
private Mock<ITabsViewModel> viewModel;
private Mock<IEngineeringModelBodyViewModel> engineeringModelBodyViewModel;
private Iteration iteration;

[SetUp]
public void SetUp()
{
this.context = new TestContext();
this.context.ConfigureDevExpressBlazor();

var engineeringModelBodyApplication = Applications.ExistingApplications.OfType<TabbedApplication>().First(x => x.Url == WebAppConstantValues.EngineeringModelPage);

var optionsTableViewModel = new Mock<IOptionsTableViewModel>();
optionsTableViewModel.Setup(x => x.Rows).Returns(new SourceList<OptionRowViewModel>());
optionsTableViewModel.Setup(x => x.CurrentThing).Returns(new Option());
this.engineeringModelBodyViewModel = new Mock<IEngineeringModelBodyViewModel>();
this.engineeringModelBodyViewModel.Setup(x => x.OptionsTableViewModel).Returns(optionsTableViewModel.Object);

this.iteration = new Iteration
{
IterationSetup = new IterationSetup
{
Container = new EngineeringModelSetup()
}
};

var configuration = new Mock<IConfigurationService>();
configuration.Setup(x => x.ServerConfiguration).Returns(new ServerConfiguration());

this.viewModel = new Mock<ITabsViewModel>();
var openTabs = new SourceList<TabbedApplicationInformation>();
openTabs.Add(new TabbedApplicationInformation(this.engineeringModelBodyViewModel.Object, typeof(EngineeringModelBody), this.iteration));
this.viewModel.Setup(x => x.OpenTabs).Returns(openTabs);
this.viewModel.Setup(x => x.CurrentTab).Returns(openTabs.Items.First());
this.viewModel.Setup(x => x.SelectedApplication).Returns(engineeringModelBodyApplication);
this.viewModel.Setup(x => x.SidePanels).Returns(new SourceList<TabPanelInformation>());

this.context.Services.AddSingleton(this.viewModel.Object);
this.context.Services.AddSingleton(this.engineeringModelBodyViewModel.Object);
this.context.Services.AddSingleton(configuration.Object);

this.renderer = this.context.RenderComponent<TabsPanelComponent>(parameters =>
{
parameters.Add(p => p.ViewModel, this.viewModel.Object);
parameters.Add(p => p.Handler, this.viewModel.Object);
parameters.Add(p => p.CssClass, "css-test-class");
parameters.Add(p => p.IsSidePanelAvailable, true);
parameters.Add(p => p.Tabs, this.viewModel.Object.OpenTabs.Items.ToList());
});
}

[TearDown]
public void Teardown()
{
this.context.CleanContext();
this.context.Dispose();
}

[Test]
public async Task VerifyAddSidePanel()
{
var sidePanelButton = this.renderer.FindComponents<DxButton>().First(x => x.Instance.Id == "new-side-panel-button");
await this.renderer.InvokeAsync(sidePanelButton.Instance.Click.InvokeAsync);

this.viewModel.VerifySet(x => x.CurrentTab = null, Times.Once);
}

[Test]
public void VerifyComponent()
{
Assert.Multiple(() =>
{
Assert.That(this.renderer.Instance.ViewModel, Is.EqualTo(this.viewModel.Object));
Assert.That(this.renderer.Instance, Is.Not.Null);
Assert.That(this.renderer.Markup, Does.Contain("css-test-class"));
});
}
}
}
4 changes: 4 additions & 0 deletions COMETwebapp.Tests/Pages/TabsTestFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,12 @@ public void Setup()

var engineeringModelBodyApplication = Applications.ExistingApplications.OfType<TabbedApplication>().First(x => x.Url == WebAppConstantValues.EngineeringModelPage);
this.viewModel = new Mock<ITabsViewModel>();

var sidePanels = new SourceList<TabPanelInformation>();
sidePanels.Add(new TabPanelInformation());
this.viewModel.Setup(x => x.OpenTabs).Returns(new SourceList<TabbedApplicationInformation>());
this.viewModel.Setup(x => x.SelectedApplication).Returns(engineeringModelBodyApplication);
this.viewModel.Setup(x => x.SidePanels).Returns(sidePanels);

var optionsTableViewModel = new Mock<IOptionsTableViewModel>();
optionsTableViewModel.Setup(x => x.Rows).Returns(new SourceList<OptionRowViewModel>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ public void Teardown()
[Test]
public async Task VerifyOpenIterationAndModel()
{
await this.viewModel.OpenTab();
var panel = new TabPanelInformation();
await this.viewModel.OpenTab(panel);

Assert.Multiple(() =>
{
Expand All @@ -106,18 +107,18 @@ public async Task VerifyOpenIterationAndModel()
this.viewModel.SelectedEngineeringModel = ((EngineeringModel)this.sessionService.Object.OpenIterations.Items.First().Container).EngineeringModelSetup;
this.viewModel.SelectedIterationSetup = new IterationData(this.viewModel.SelectedEngineeringModel.IterationSetup[0]);
this.viewModel.SelectedDomainOfExpertise = new DomainOfExpertise();
await this.viewModel.OpenTab();
await this.viewModel.OpenTab(panel);

Assert.Multiple(() =>
{
this.tabsViewModel.Verify(x => x.CreateNewTab(It.IsAny<TabbedApplication>(), It.IsAny<Guid>()), Times.Once);
this.tabsViewModel.Verify(x => x.CreateNewTab(It.IsAny<TabbedApplication>(), It.IsAny<Guid>(), It.IsAny<TabPanelInformation>()), Times.Once);
this.sessionService.Verify(x => x.ReadIteration(It.IsAny<IterationSetup>(), It.IsAny<DomainOfExpertise>()), Times.Once);
});

var newEngineeringModel = new EngineeringModel { EngineeringModelSetup = this.viewModel.SelectedEngineeringModel };
this.sessionService.Setup(x => x.OpenEngineeringModels).Returns([newEngineeringModel]);

await this.viewModel.OpenTab();
await this.viewModel.OpenTab(panel);
this.sessionService.Verify(x => x.SwitchDomain(It.IsAny<Iteration>(), It.IsAny<DomainOfExpertise>()), Times.Once);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public void VerifyTabRemoval()
var engineeringModelApplication2 = this.viewModel.AvailableApplications.First(x => x.Url == WebAppConstantValues.EngineeringModelPage);
this.viewModel.CreateNewTab(engineeringModelApplication1, Guid.Empty);
this.viewModel.CreateNewTab(engineeringModelApplication2, Guid.Empty);
this.viewModel.SidePanels.Add(new TabPanelInformation());

var removedTab = this.viewModel.OpenTabs.Items.ElementAt(1);

Expand Down
14 changes: 10 additions & 4 deletions COMETwebapp/Components/Tabs/OpenTab.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ namespace COMETwebapp.Components.Tabs

using COMET.Web.Common.Components;
using COMET.Web.Common.Extensions;
using COMET.Web.Common.ViewModels.Components.Applications;

using COMETwebapp.Model;
using COMETwebapp.ViewModels.Components.Common.OpenTab;

using Microsoft.AspNetCore.Components;
Expand Down Expand Up @@ -60,12 +60,18 @@ public partial class OpenTab : OpenModel
public Action OnTabOpened { get; set; }

/// <summary>
/// Gets the condition to check if the selected application thing type is an <see cref="EngineeringModel"/>
/// Gets or sets the panel to open the new tab, if any
/// </summary>
[Parameter]
public TabPanelInformation Panel { get; set; }

/// <summary>
/// Gets the condition to check if the selected application thing type is an <see cref="EngineeringModel" />
/// </summary>
private bool IsEngineeringModelView => this.ViewModel.SelectedApplication?.ThingTypeOfInterest == typeof(EngineeringModel);

/// <summary>
/// Gets the condition to check if the selected application thing type is an <see cref="Iteration"/>
/// Gets the condition to check if the selected application thing type is an <see cref="Iteration" />
/// </summary>
private bool IsIterationView => this.ViewModel.SelectedApplication?.ThingTypeOfInterest == typeof(Iteration);

Expand Down Expand Up @@ -99,7 +105,7 @@ protected override bool AreRequiredFieldSelected()
/// <returns>A <see cref="Task" /></returns>
private async Task OpenModelAndNavigateToView()
{
await this.ViewModel.OpenTab();
await this.ViewModel.OpenTab(this.Panel);
await this.InvokeAsync(this.StateHasChanged);
this.OnTabOpened?.Invoke();
}
Expand Down
63 changes: 63 additions & 0 deletions COMETwebapp/Components/Tabs/TabsPanelComponent.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<!------------------------------------------------------------------------------
// 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
// 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 http://www.gnu.org/licenses/.
------------------------------------------------------------------------------->
@using CDP4Common.CommonData
@inherits DisposableComponent

<div class="panel-view @(this.CssClass)">
@if (this.Handler.CurrentTab is not null)
{
<div class="d-flex gap-2 tabs-row">

@foreach (var tab in this.Tabs)
{
<TabComponent Text="@(GetTabText(tab.ObjectOfInterest))"
Icon="typeof(FeatherX)"
OnClick="@(() => this.OnTabClick.InvokeAsync((tab, this.Handler)))"
OnIconClick="@(() => this.OnRemoveTabClick.InvokeAsync(tab))"
IsCurrent="@(tab == this.Handler.CurrentTab)"
@key="tab"/>
}

<TabComponent Text="Open Model"
Icon="typeof(FeatherPlus)"
OnClick="@(() => this.OnOpenTabClick.Invoke())"/>

@if (this.IsSidePanelAvailable)
{
<DxButton Click="@(() => this.AddSidePanel())"
RenderStyle="ButtonRenderStyle.None"
Id="new-side-panel-button"
style="position: absolute; right: 10px;">
<FeatherColumns Size="30"
Color="currentColor"
StrokeWidth="1.8f"/>
</DxButton>
}

</div>
<div class="template-container" id="tabs-page-content">
<DynamicApplicationBase ViewModel="this.Handler.CurrentTab.ApplicationBaseViewModel"
ApplicationBaseType="this.Handler.CurrentTab.ComponentType"
CurrentThing="this.Handler.CurrentTab.ObjectOfInterest as Thing"/>
</div>
}
</div>
Loading

0 comments on commit e494cd6

Please sign in to comment.