From 945cb56432652ab134e559981ca69b79dac1c433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Rua?= <140734849+joao4all@users.noreply.github.com> Date: Tue, 4 Jun 2024 08:45:59 +0100 Subject: [PATCH] Feat #614 [Engineering Model] Refactor CommonFilestore page to be inline with Measurement Scale page (#654) --- .../CommonFileStoresTableTestFixture.cs | 13 ++- ...ommonFileStoreTableViewModelTestFixture.cs | 57 +++++----- .../FileHandlerViewModelTestFixture.cs | 8 +- ...FolderFileStructureViewModelTestFixture.cs | 38 ++++--- .../FolderHandlerViewModelTestFixture.cs | 8 +- .../CommonFileStoresForm.razor | 52 ++++++--- .../CommonFileStoresForm.razor.cs | 5 + .../CommonFileStoresTable.razor | 101 ++++++------------ .../CommonFileStoresTable.razor.cs | 90 +++++++--------- .../FileStore/FolderFileStructure.razor | 47 ++++---- .../EngineeringModel/OptionsTable.razor | 2 +- .../EngineeringModel/PublicationsTable.razor | 2 +- .../CommonFileStoreTableViewModel.cs | 39 +++---- .../ICommonFileStoreTableViewModel.cs | 5 - .../FileHandler/FileHandlerViewModel.cs | 23 ++-- .../FileHandler/IFileHandlerViewModel.cs | 4 +- .../FileStore/FolderFileStructureViewModel.cs | 98 ++++++++++------- .../FolderHandler/FolderHandlerViewModel.cs | 24 ++--- .../FolderHandler/IFolderHandlerViewModel.cs | 4 +- .../Rows/CommonFileStoreRowViewModel.cs | 6 +- 20 files changed, 308 insertions(+), 318 deletions(-) diff --git a/COMETwebapp.Tests/Components/EngineeringModel/CommonFileStoresTableTestFixture.cs b/COMETwebapp.Tests/Components/EngineeringModel/CommonFileStoresTableTestFixture.cs index 77e3b68b..4f06027e 100644 --- a/COMETwebapp.Tests/Components/EngineeringModel/CommonFileStoresTableTestFixture.cs +++ b/COMETwebapp.Tests/Components/EngineeringModel/CommonFileStoresTableTestFixture.cs @@ -33,6 +33,7 @@ namespace COMETwebapp.Tests.Components.EngineeringModel using CDP4Common.SiteDirectoryData; using COMET.Web.Common.Test.Helpers; + using COMET.Web.Common.ViewModels.Components.Selectors; using COMETwebapp.Components.EngineeringModel; using COMETwebapp.ViewModels.Components.EngineeringModel.CommonFileStore; @@ -75,6 +76,7 @@ public void SetUp() rows.Add(new CommonFileStoreRowViewModel(this.commonFileStore)); this.viewModel.Setup(x => x.Rows).Returns(rows); this.viewModel.Setup(x => x.CurrentThing).Returns(new CommonFileStore()); + this.viewModel.Setup(x => x.DomainOfExpertiseSelectorViewModel).Returns(new Mock().Object); this.context.ConfigureDevExpressBlazor(); @@ -105,14 +107,17 @@ public void VerifyOnInitialized() [Test] public async Task VerifyDeleteCommonFileStore() { - 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(); - var deletionPopup = this.renderer.FindComponent(); + var deletionPopup = this.renderer.FindComponents().First(x => x.Instance.Visible); var confirmDeletionButton = deletionPopup.FindComponents().ElementAt(1); await deletionPopup.InvokeAsync(confirmDeletionButton.Instance.Click.InvokeAsync); this.viewModel.Verify(x => x.OnConfirmPopupButtonClick(), Times.Once); @@ -121,7 +126,7 @@ public async Task VerifyDeleteCommonFileStore() [Test] public async Task VerifyCreateCommonFileStore() { - var addOptionButton = this.renderer.FindComponents().First(x => x.Instance.Id == "addCommonFileStoreButton"); + var addOptionButton = this.renderer.FindComponents().First(x => x.Instance.Id == "dataItemDetailsButton"); await this.renderer.InvokeAsync(addOptionButton.Instance.Click.InvokeAsync); var form = this.renderer.FindComponent(); diff --git a/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/CommonFileStoreTableViewModelTestFixture.cs b/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/CommonFileStoreTableViewModelTestFixture.cs index 1b1d0599..8ed0b030 100644 --- a/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/CommonFileStoreTableViewModelTestFixture.cs +++ b/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/CommonFileStoreTableViewModelTestFixture.cs @@ -1,18 +1,18 @@ // -------------------------------------------------------------------------------------------------------------------- // -// Copyright (c) 2023-2024 Starion Group S.A. +// Copyright (c) 2024 Starion Group S.A. // -// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Antoine Théate, João Rua +// 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. +// 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 CDP4-COMET WEB Community Edition is free software; you can redistribute it and/or +// 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 CDP4-COMET WEB Community Edition is distributed in the hope that it will be useful, +// 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. @@ -27,7 +27,6 @@ namespace COMETwebapp.Tests.ViewModels.Components.EngineeringModel using CDP4Common.CommonData; using CDP4Common.EngineeringModelData; using CDP4Common.SiteDirectoryData; - using CDP4Common.Types; using CDP4Dal; using CDP4Dal.Permission; @@ -52,7 +51,6 @@ public class CommonFileStoreTableViewModelTestFixture private Mock sessionService; private Mock folderFileStructureViewModel; private Mock permissionService; - private Assembler assembler; private Mock> loggerMock; private CDPMessageBus messageBus; private Iteration iteration; @@ -67,11 +65,11 @@ public void Setup() this.messageBus = new CDPMessageBus(); this.loggerMock = new Mock>(); - var siteDirectory = new SiteDirectory() + var siteDirectory = new SiteDirectory { Domain = { - new DomainOfExpertise() + new DomainOfExpertise { ShortName = "doe", Name = "Domain Of Expertise" @@ -79,7 +77,7 @@ public void Setup() } }; - this.commonFileStore = new CommonFileStore() + this.commonFileStore = new CommonFileStore { Name = "CFS", Owner = siteDirectory.Domain.First() @@ -90,14 +88,9 @@ public void Setup() engineeringModel.CommonFileStore.Add(this.commonFileStore); engineeringModel.Iteration.Add(this.iteration); - this.assembler = new Assembler(new Uri("http://localhost:5000/"), this.messageBus); - var lazyCommonFileStore = new Lazy(this.commonFileStore); - this.assembler.Cache.TryAdd(new CacheKey(), lazyCommonFileStore); - this.permissionService.Setup(x => x.CanWrite(this.commonFileStore.ClassKind, this.commonFileStore.Container)).Returns(true); var session = new Mock(); session.Setup(x => x.PermissionService).Returns(this.permissionService.Object); - session.Setup(x => x.Assembler).Returns(this.assembler); this.sessionService.Setup(x => x.Session).Returns(session.Object); this.sessionService.Setup(x => x.GetSiteDirectory()).Returns(siteDirectory); @@ -112,22 +105,6 @@ public void Teardown() this.viewModel.Dispose(); } - [Test] - public void VerifyInitializeViewModel() - { - this.viewModel.InitializeViewModel(); - var firstRow = this.viewModel.Rows.Items.First(); - - Assert.Multiple(() => - { - Assert.That(this.viewModel.Rows.Count, Is.EqualTo(1)); - Assert.That(this.viewModel.DomainOfExpertiseSelectorViewModel.AvailableDomainsOfExpertise.Count(), Is.EqualTo(1)); - Assert.That(this.viewModel.IsPrivate, Is.EqualTo(false)); - Assert.That(firstRow.Thing, Is.EqualTo(this.commonFileStore)); - Assert.That(firstRow.CreatedOn, Is.EqualTo(this.commonFileStore.CreatedOn.ToString("dd/MM/yyyy HH:mm:ss"))); - }); - } - [Test] public async Task VerifyCommonFileStoreCreateOrEdit() { @@ -142,5 +119,21 @@ public async Task VerifyCommonFileStoreCreateOrEdit() await this.viewModel.CreateOrEditCommonFileStore(false); this.loggerMock.Verify(LogLevel.Error, x => !string.IsNullOrWhiteSpace(x.ToString()), Times.Once()); } + + [Test] + public void VerifyInitializeViewModel() + { + this.viewModel.InitializeViewModel(); + var firstRow = this.viewModel.Rows.Items.First(); + + Assert.Multiple(() => + { + Assert.That(this.viewModel.Rows.Count, Is.EqualTo(1)); + Assert.That(this.viewModel.DomainOfExpertiseSelectorViewModel.AvailableDomainsOfExpertise.Count(), Is.EqualTo(1)); + Assert.That(this.viewModel.IsPrivate, Is.EqualTo(false)); + Assert.That(firstRow.Thing, Is.EqualTo(this.commonFileStore)); + Assert.That(firstRow.CreatedOn, Is.EqualTo(this.commonFileStore.CreatedOn)); + }); + } } } diff --git a/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/FileStore/FileHandlerViewModelTestFixture.cs b/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/FileStore/FileHandlerViewModelTestFixture.cs index f3c28e89..495f77fc 100644 --- a/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/FileStore/FileHandlerViewModelTestFixture.cs +++ b/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/FileStore/FileHandlerViewModelTestFixture.cs @@ -125,13 +125,7 @@ public void TearDown() public void VerifyInitializeViewModel() { this.viewModel.InitializeViewModel(this.commonFileStore, this.iteration); - - Assert.Multiple(() => - { - Assert.That(this.viewModel.Folders, Has.Count.EqualTo(this.commonFileStore.Folder.Count + 1)); - Assert.That(this.viewModel.Folders, Contains.Item(null)); - Assert.That(this.viewModel.DomainOfExpertiseSelectorViewModel.AvailableDomainsOfExpertise.Count(), Is.EqualTo(1)); - }); + Assert.That(this.viewModel.DomainOfExpertiseSelectorViewModel.AvailableDomainsOfExpertise.Count(), Is.EqualTo(1)); } [Test] diff --git a/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/FileStore/FolderFileStructureViewModelTestFixture.cs b/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/FileStore/FolderFileStructureViewModelTestFixture.cs index f20d4ced..7b8e0433 100644 --- a/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/FileStore/FolderFileStructureViewModelTestFixture.cs +++ b/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/FileStore/FolderFileStructureViewModelTestFixture.cs @@ -1,18 +1,18 @@ // -------------------------------------------------------------------------------------------------------------------- // -// Copyright (c) 2023-2024 Starion Group S.A. +// Copyright (c) 2024 Starion Group S.A. // -// Authors: Sam Gerené, Alex Vorobiev, Alexander van Delft, Jaime Bernar, Antoine Théate, João Rua +// 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. +// 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 CDP4-COMET WEB Community Edition is free software; you can redistribute it and/or +// 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 CDP4-COMET WEB Community Edition is distributed in the hope that it will be useful, +// 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. @@ -32,7 +32,6 @@ namespace COMETwebapp.Tests.ViewModels.Components.EngineeringModel.FileStore using CDP4Web.Enumerations; - using COMET.Web.Common.Enumerations; using COMET.Web.Common.Services.SessionManagement; using COMETwebapp.ViewModels.Components.EngineeringModel.FileStore; @@ -63,11 +62,11 @@ public void Setup() this.folderHandlerViewModel = new Mock(); this.iteration = new Iteration(); - var siteDirectory = new SiteDirectory() + var siteDirectory = new SiteDirectory { Domain = { - new DomainOfExpertise() + new DomainOfExpertise { ShortName = "doe", Name = "Domain Of Expertise" @@ -75,21 +74,21 @@ public void Setup() } }; - var folder1 = new Folder() + var folder1 = new Folder { Iid = Guid.NewGuid(), Name = "folder 1" }; - var file = new File() + var file = new File { - Iid = Guid.NewGuid(), + Iid = Guid.NewGuid(), CurrentContainingFolder = folder1 }; file.FileRevision.Add(new FileRevision()); - this.commonFileStore = new CommonFileStore() + this.commonFileStore = new CommonFileStore { Name = "CFS", Folder = { folder1 }, @@ -136,6 +135,15 @@ public void VerifySessionRefresh() var rootNodeContent = this.viewModel.Structure.First().Content; Assert.That(rootNodeContent, Has.Count.EqualTo(2)); + this.messageBus.SendObjectChangeEvent(this.commonFileStore, EventKind.Updated); + this.messageBus.SendMessage(SessionServiceEvent.SessionRefreshed, this.sessionService.Object.Session); + + Assert.Multiple(() => + { + this.fileHandlerViewModel.VerifySet(x => x.Folders = It.IsAny>(), Times.Exactly(2)); + this.folderHandlerViewModel.VerifySet(x => x.Folders = It.IsAny>(), Times.Exactly(2)); + }); + this.messageBus.SendMessage(SessionServiceEvent.SessionRefreshed, this.sessionService.Object.Session); Assert.That(rootNodeContent, Has.Count.EqualTo(2)); @@ -148,9 +156,9 @@ public void VerifySessionRefresh() Assert.That(rootNodeContent.Select(x => x.Thing), Contains.Item(newFile)); Assert.That(rootNodeContent, Has.Count.EqualTo(3)); }); - + var existingFile = this.commonFileStore.File.First(); - existingFile.LockedBy = new Person() { ShortName = "locker" }; + existingFile.LockedBy = new Person { ShortName = "locker" }; this.messageBus.SendObjectChangeEvent(newFile, EventKind.Updated); this.messageBus.SendMessage(SessionServiceEvent.SessionRefreshed, this.sessionService.Object.Session); diff --git a/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/FileStore/FolderHandlerViewModelTestFixture.cs b/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/FileStore/FolderHandlerViewModelTestFixture.cs index 72415999..f5a53a3f 100644 --- a/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/FileStore/FolderHandlerViewModelTestFixture.cs +++ b/COMETwebapp.Tests/ViewModels/Components/EngineeringModel/FileStore/FolderHandlerViewModelTestFixture.cs @@ -118,13 +118,7 @@ public void TearDown() public void VerifyInitializeViewModel() { this.viewModel.InitializeViewModel(this.commonFileStore, this.iteration); - - Assert.Multiple(() => - { - Assert.That(this.viewModel.Folders, Has.Count.EqualTo(this.commonFileStore.Folder.Count + 1)); - Assert.That(this.viewModel.Folders, Contains.Item(null)); - Assert.That(this.viewModel.DomainOfExpertiseSelectorViewModel.AvailableDomainsOfExpertise.Count(), Is.EqualTo(1)); - }); + Assert.That(this.viewModel.DomainOfExpertiseSelectorViewModel.AvailableDomainsOfExpertise.Count(), Is.EqualTo(1)); } [Test] diff --git a/COMETwebapp/Components/EngineeringModel/CommonFileStoresForm.razor b/COMETwebapp/Components/EngineeringModel/CommonFileStoresForm.razor index dbd9b2a8..12dec1ed 100644 --- a/COMETwebapp/Components/EngineeringModel/CommonFileStoresForm.razor +++ b/COMETwebapp/Components/EngineeringModel/CommonFileStoresForm.razor @@ -14,24 +14,50 @@ Copyright (c) 2023-2024 Starion Group S.A. 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 COMETwebapp.Components.EngineeringModel.FileStore @inherits SelectedDataItemForm - + - - - - - - - - - + + + + + + + + + + + + + @if (!this.ShouldCreate) + { + + + + + + + } + + + 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/CommonFileStoresForm.razor.cs b/COMETwebapp/Components/EngineeringModel/CommonFileStoresForm.razor.cs index 00b38bfb..6dbc1aa2 100644 --- a/COMETwebapp/Components/EngineeringModel/CommonFileStoresForm.razor.cs +++ b/COMETwebapp/Components/EngineeringModel/CommonFileStoresForm.razor.cs @@ -42,6 +42,11 @@ public partial class CommonFileStoresForm : SelectedDataItemForm [Parameter, Required] public ICommonFileStoreTableViewModel ViewModel { get; set; } + /// + /// Gets the value to check if the folder file structure component is visible + /// + public bool IsFolderFileStructureVisible { get; private set; } + /// /// Method that is executed when there is a valid submit /// diff --git a/COMETwebapp/Components/EngineeringModel/CommonFileStoresTable.razor b/COMETwebapp/Components/EngineeringModel/CommonFileStoresTable.razor index b3f7cd5a..ba1e3a15 100644 --- a/COMETwebapp/Components/EngineeringModel/CommonFileStoresTable.razor +++ b/COMETwebapp/Components/EngineeringModel/CommonFileStoresTable.razor @@ -14,78 +14,45 @@ Copyright (c) 2023-2024 Starion Group S.A. 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 COMETwebapp.Components.EngineeringModel.FileStore @inherits SelectedDataItemBase - -
- - - - - - - - - - @{ - var row = (CommonFileStoreRowViewModel)context.DataItem; +
+ + + + + + - - } - - - + - - - - - - - - - See Folder-File Structure - - -
- + + +
- - @this.ViewModel.PopupDialog + + @(this.ViewModel.PopupDialog)
- - + +
- - - - diff --git a/COMETwebapp/Components/EngineeringModel/CommonFileStoresTable.razor.cs b/COMETwebapp/Components/EngineeringModel/CommonFileStoresTable.razor.cs index f46c8d18..82b975f1 100644 --- a/COMETwebapp/Components/EngineeringModel/CommonFileStoresTable.razor.cs +++ b/COMETwebapp/Components/EngineeringModel/CommonFileStoresTable.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,30 +28,28 @@ namespace COMETwebapp.Components.EngineeringModel using CDP4Common.EngineeringModelData; + using COMET.Web.Common.Extensions; + using COMETwebapp.Components.Common; using COMETwebapp.ViewModels.Components.EngineeringModel.CommonFileStore; using COMETwebapp.ViewModels.Components.EngineeringModel.Rows; - using DevExpress.Blazor; - using Microsoft.AspNetCore.Components; + using ReactiveUI; + /// - /// Support class for the + /// Support class for the /// public partial class CommonFileStoresTable : SelectedDataItemBase { /// /// The for this component /// - [Parameter, Required] + [Parameter] + [Required] public ICommonFileStoreTableViewModel ViewModel { get; set; } - /// - /// Gets the value to check if the folder file structure component is visible - /// - public bool IsFolderFileStructureVisible { get; private set; } - /// /// Method invoked when the component is ready to start, having received its /// initial parameters from its parent in the render tree. @@ -60,20 +58,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 = (CommonFileStoreRowViewModel)e.DataItem; - this.ViewModel.CurrentThing = dataItem == null ? new CommonFileStore() : 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))); } /// @@ -83,26 +68,29 @@ protected override void CustomizeEditThing(GridCustomizeEditModelEventArgs e) protected override void OnSelectedDataItemChanged(CommonFileStoreRowViewModel 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 /// - /// A - private async Task OnConfirmDelete() + private void OnAddThingClick() { - await this.ViewModel.OnConfirmPopupButtonClick(); - this.IsOnEditMode = false; + this.ShouldCreateThing = true; + this.IsOnEditMode = true; + this.ViewModel.CurrentThing = new CommonFileStore(); + this.InvokeAsync(this.StateHasChanged); } /// - /// Method invoked when the see folder file structure button is clicked + /// Method invoked when the deletion of a thing is confirmed /// - private void OnSeeFolderFileStructureClick() + /// A + private async Task OnDeletionConfirmed() { - this.ViewModel.LoadFileStructure(); - this.IsFolderFileStructureVisible = true; + await this.ViewModel.OnConfirmPopupButtonClick(); + this.IsOnEditMode = false; } } } diff --git a/COMETwebapp/Components/EngineeringModel/FileStore/FolderFileStructure.razor b/COMETwebapp/Components/EngineeringModel/FileStore/FolderFileStructure.razor index 08fe0f61..60bd095c 100644 --- a/COMETwebapp/Components/EngineeringModel/FileStore/FolderFileStructure.razor +++ b/COMETwebapp/Components/EngineeringModel/FileStore/FolderFileStructure.razor @@ -27,37 +27,36 @@ Copyright (c) 2023-2024 Starion Group S.A. Create File - + style="height: 40vh; width: 100%; padding-top: 5px;" + NodeClick="e => this.OnNodeClick(e.NodeInfo)"> + IconCssClass="@nameof(FileFolderNodeViewModel.IconCssClass)"/> @{ var row = (FileFolderNodeViewModel)nodeContext.DataItem; -
+
- @nodeContext.Text + @nodeContext.Text - @if (row.Thing is Folder) - { - - } -
- } + @if (row.Thing is Folder) + { + + } +
}
@@ -66,10 +65,10 @@ Copyright (c) 2023-2024 Starion Group S.A. CloseOnOutsideClick="false" Closed="@(this.OnClosedFormPopup)" Width="40%"> - + ShouldCreate="@(this.ShouldCreateFile)"/> - + \ No newline at end of file diff --git a/COMETwebapp/Components/EngineeringModel/OptionsTable.razor b/COMETwebapp/Components/EngineeringModel/OptionsTable.razor index d5d634bd..09c6e199 100644 --- a/COMETwebapp/Components/EngineeringModel/OptionsTable.razor +++ b/COMETwebapp/Components/EngineeringModel/OptionsTable.razor @@ -21,7 +21,7 @@ Copyright (c) 2023-2024 Starion Group S.A. Data="this.ViewModel.Rows.Items" ColumnResizeMode="GridColumnResizeMode.ColumnsContainer" ShowSearchBox="true" - SearchBoxNullText="Search for a measurement scale ..." + SearchBoxNullText="Search for an option ..." AllowSelectRowByClick="true" SelectionMode="GridSelectionMode.Single" SelectedDataItemChanged="@(row => this.OnSelectedDataItemChanged((OptionRowViewModel)row))" diff --git a/COMETwebapp/Components/EngineeringModel/PublicationsTable.razor b/COMETwebapp/Components/EngineeringModel/PublicationsTable.razor index b7cde51c..4281a7a9 100644 --- a/COMETwebapp/Components/EngineeringModel/PublicationsTable.razor +++ b/COMETwebapp/Components/EngineeringModel/PublicationsTable.razor @@ -54,7 +54,7 @@ Copyright (c) 2023-2024 Starion Group S.A. Data="this.ViewModel.Rows.Items.OrderByDescending(x => x.CreatedOn)" ColumnResizeMode="GridColumnResizeMode.ColumnsContainer" ShowSearchBox="true" - SearchBoxNullText="Search for an option..." + SearchBoxNullText="Search for a publication..." AllowSelectRowByClick="true" SelectionMode="GridSelectionMode.Single" SelectedDataItemChanged="@((row) => this.OnSelectedDataItemChanged((PublicationRowViewModel)row))" diff --git a/COMETwebapp/ViewModels/Components/EngineeringModel/CommonFileStore/CommonFileStoreTableViewModel.cs b/COMETwebapp/ViewModels/Components/EngineeringModel/CommonFileStore/CommonFileStoreTableViewModel.cs index db5989ba..12304ea5 100644 --- a/COMETwebapp/ViewModels/Components/EngineeringModel/CommonFileStore/CommonFileStoreTableViewModel.cs +++ b/COMETwebapp/ViewModels/Components/EngineeringModel/CommonFileStore/CommonFileStoreTableViewModel.cs @@ -94,14 +94,6 @@ public void SetCurrentIteration(Iteration iteration) this.DomainOfExpertiseSelectorViewModel.CurrentIteration = iteration; } - /// - /// Loads the file structure handled by the - /// - public void LoadFileStructure() - { - this.FolderFileStructureViewModel.InitializeViewModel(this.CurrentThing, this.CurrentIteration); - } - /// /// Creates or edits a /// @@ -109,29 +101,31 @@ public void LoadFileStructure() /// A public async Task CreateOrEditCommonFileStore(bool shouldCreate) { - this.IsLoading = true; - - var engineeringModelClone = ((EngineeringModel)this.CurrentIteration.Container).Clone(true); - var thingsToCreate = new List(); - - if (shouldCreate) + try { - engineeringModelClone.CommonFileStore.Add(this.CurrentThing); - thingsToCreate.Add(engineeringModelClone); - } + this.IsLoading = true; - thingsToCreate.Add(this.CurrentThing); + var engineeringModelClone = ((EngineeringModel)this.CurrentIteration.Container).Clone(true); + var thingsToCreate = new List(); - try - { + if (shouldCreate) + { + this.CurrentThing.CreatedOn = DateTime.UtcNow; + engineeringModelClone.CommonFileStore.Add(this.CurrentThing); + thingsToCreate.Add(engineeringModelClone); + } + + thingsToCreate.Add(this.CurrentThing); await this.SessionService.CreateOrUpdateThingsWithNotification(engineeringModelClone, thingsToCreate, this.GetNotificationDescription(shouldCreate)); } catch (Exception ex) { this.Logger.LogError(ex, "An error has occurred while creating or editing a Common File Store"); } - - this.IsLoading = false; + finally + { + this.IsLoading = false; + } } /// @@ -146,6 +140,7 @@ protected override async Task OnThingChanged() if (this.DomainOfExpertiseSelectorViewModel is not null) { await this.DomainOfExpertiseSelectorViewModel.SetSelectedDomainOfExpertiseOrReset(this.CurrentThing.Iid == Guid.Empty, this.CurrentThing.Owner); + this.FolderFileStructureViewModel.InitializeViewModel(this.CurrentThing, this.CurrentIteration); } } diff --git a/COMETwebapp/ViewModels/Components/EngineeringModel/CommonFileStore/ICommonFileStoreTableViewModel.cs b/COMETwebapp/ViewModels/Components/EngineeringModel/CommonFileStore/ICommonFileStoreTableViewModel.cs index 18fa32b3..96b717a3 100644 --- a/COMETwebapp/ViewModels/Components/EngineeringModel/CommonFileStore/ICommonFileStoreTableViewModel.cs +++ b/COMETwebapp/ViewModels/Components/EngineeringModel/CommonFileStore/ICommonFileStoreTableViewModel.cs @@ -64,10 +64,5 @@ public interface ICommonFileStoreTableViewModel : IDeletableDataItemTableViewMod /// /// The iteration to be set void SetCurrentIteration(Iteration iteration); - - /// - /// Loads the file structure handled by the - /// - void LoadFileStructure(); } } diff --git a/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FileHandler/FileHandlerViewModel.cs b/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FileHandler/FileHandlerViewModel.cs index 124d050c..655baa4e 100644 --- a/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FileHandler/FileHandlerViewModel.cs +++ b/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FileHandler/FileHandlerViewModel.cs @@ -64,11 +64,10 @@ public FileHandlerViewModel(ISessionService sessionService, ICDPMessageBus messa this.DomainOfExpertiseSelectorViewModel = new DomainOfExpertiseSelectorViewModel(sessionService, messageBus) { - OnSelectedDomainOfExpertiseChange = new EventCallbackFactory().Create(this, selectedOwner => - { - this.CurrentThing.Owner = selectedOwner; - }) + OnSelectedDomainOfExpertiseChange = new EventCallbackFactory().Create(this, selectedOwner => { this.CurrentThing.Owner = selectedOwner; }) }; + + this.InitializeSubscriptions([typeof(FileStore)]); } /// @@ -92,9 +91,9 @@ public FileHandlerViewModel(ISessionService sessionService, ICDPMessageBus messa public IEnumerable FileTypes { get; private set; } /// - /// Gets a collection of the available s + /// Gets or sets a collection of the available s /// - public IEnumerable Folders { get; private set; } + public IEnumerable Folders { get; set; } /// /// Gets or sets a collection of the file revisions to be created/edited @@ -121,10 +120,6 @@ public void InitializeViewModel(FileStore fileStore, Iteration iteration) this.CurrentFileStore = fileStore; this.DomainOfExpertiseSelectorViewModel.CurrentIteration = iteration; this.FileTypes = this.SessionService.GetSiteDirectory().AvailableReferenceDataLibraries().SelectMany(x => x.FileType); - - var folders = this.CurrentFileStore.Folder.ToList(); - folders.Add(null); - this.Folders = folders; } /// @@ -219,10 +214,14 @@ public async Task DeleteFile() /// Handles the refresh of the current /// /// A - protected override Task OnSessionRefreshed() => Task.CompletedTask; + protected override Task OnSessionRefreshed() + { + return Task.CompletedTask; + } /// - /// Update this view model properties when the has changed + /// Update this view model properties when the has + /// changed /// /// A protected override async Task OnThingChanged() diff --git a/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FileHandler/IFileHandlerViewModel.cs b/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FileHandler/IFileHandlerViewModel.cs index 0e8c70b5..aef92ea7 100644 --- a/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FileHandler/IFileHandlerViewModel.cs +++ b/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FileHandler/IFileHandlerViewModel.cs @@ -55,9 +55,9 @@ public interface IFileHandlerViewModel : IApplicationBaseViewModel bool IsLocked { get; set; } /// - /// Gets a collection of the available s + /// Gets or sets a collection of the available s /// - IEnumerable Folders { get; } + IEnumerable Folders { get; set; } /// /// Gets or sets the selected folder to create a file revision diff --git a/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FolderFileStructureViewModel.cs b/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FolderFileStructureViewModel.cs index 319673c8..957bf23b 100644 --- a/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FolderFileStructureViewModel.cs +++ b/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FolderFileStructureViewModel.cs @@ -1,26 +1,26 @@ // -------------------------------------------------------------------------------------------------------------------- -// -// 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.ViewModels.Components.EngineeringModel.FileStore { @@ -41,33 +41,33 @@ namespace COMETwebapp.ViewModels.Components.EngineeringModel.FileStore /// public class FolderFileStructureViewModel : ApplicationBaseViewModel, IFolderFileStructureViewModel { - /// - /// Gets or sets the current - /// - private FileStore CurrentFileStore { get; set; } - /// /// Initializes a new instance of the class. /// /// The - /// The - /// The - /// The - public FolderFileStructureViewModel(ISessionService sessionService, ICDPMessageBus messageBus, IFileHandlerViewModel fileHandlerViewModel, IFolderHandlerViewModel folderHandlerViewModel) + /// The + /// The + /// The + public FolderFileStructureViewModel(ISessionService sessionService, ICDPMessageBus messageBus, IFileHandlerViewModel fileHandlerViewModel, IFolderHandlerViewModel folderHandlerViewModel) : base(sessionService, messageBus) { this.FileHandlerViewModel = fileHandlerViewModel; this.FolderHandlerViewModel = folderHandlerViewModel; - this.InitializeSubscriptions([typeof(File), typeof(Folder)]); + this.InitializeSubscriptions([typeof(File), typeof(Folder), typeof(FileStore)]); } /// - /// Gets the + /// Gets or sets the current + /// + private FileStore CurrentFileStore { get; set; } + + /// + /// Gets the /// public IFileHandlerViewModel FileHandlerViewModel { get; private set; } /// - /// Gets the + /// Gets the /// public IFolderHandlerViewModel FolderHandlerViewModel { get; private set; } @@ -77,15 +77,16 @@ public FolderFileStructureViewModel(ISessionService sessionService, ICDPMessageB public List Structure { get; set; } = []; /// - /// Initializes the current + /// Initializes the current /// - /// The to be set - /// The current + /// The to be set + /// The current public void InitializeViewModel(FileStore fileStore, Iteration iteration) { this.CurrentFileStore = fileStore; this.FileHandlerViewModel.InitializeViewModel(this.CurrentFileStore, iteration); this.FolderHandlerViewModel.InitializeViewModel(this.CurrentFileStore, iteration); + this.SetFolders(this.CurrentFileStore.Folder); this.CreateStructureTree(); } @@ -114,7 +115,7 @@ protected override Task OnSessionRefreshed() var rootNode = this.Structure.First(); var flatListOfNodes = rootNode.GetFlatListOfChildrenNodes(true).ToList(); - foreach (var updatedThing in this.UpdatedThings) + foreach (var updatedThing in this.UpdatedThings.Where(x => x is File or Folder)) { var nodeToUpdate = flatListOfNodes.First(x => x.Thing?.Iid == updatedThing?.Iid); var parentNode = GetContainingFolderNodeFromList(flatListOfNodes, updatedThing); @@ -124,18 +125,25 @@ protected override Task OnSessionRefreshed() parentNode.Content.Add(nodeToUpdate); } - foreach (var nodeToDelete in this.DeletedThings.Select(deletedThing => flatListOfNodes.FirstOrDefault(x => x.Thing?.Iid == deletedThing?.Iid))) + foreach (var nodeToDelete in this.DeletedThings.Where(x => x is File or Folder).Select(deletedThing => flatListOfNodes.FirstOrDefault(x => x.Thing?.Iid == deletedThing?.Iid))) { rootNode.RemoveChildNode(nodeToDelete); } - foreach (var addedThing in this.AddedThings) + foreach (var addedThing in this.AddedThings.Where(x => x is File or Folder)) { var parentNode = GetContainingFolderNodeFromList(flatListOfNodes, addedThing); var nodeToAdd = new FileFolderNodeViewModel(addedThing); parentNode.Content.Add(nodeToAdd); } + var updatedFileStore = this.UpdatedThings.OfType().FirstOrDefault(x => x.Iid == this.CurrentFileStore?.Iid); + + if (updatedFileStore != null) + { + this.SetFolders(updatedFileStore.Folder); + } + this.ClearRecordedChanges(); this.IsLoading = false; @@ -143,7 +151,7 @@ protected override Task OnSessionRefreshed() } /// - /// Creates the structure tree, present in + /// Creates the structure tree, present in /// private void CreateStructureTree() { @@ -164,11 +172,13 @@ private void LoadFolderContent(FileFolderNodeViewModel folderNode) var nestedFiles = this.CurrentFileStore.File .Where(x => x.CurrentContainingFolder?.Iid == folderNode.Thing?.Iid) .Select(x => new FileFolderNodeViewModel(x)) + .OrderBy(x => x.Name, StringComparer.InvariantCultureIgnoreCase) .ToList(); var nestedFolders = this.CurrentFileStore.Folder .Where(x => x.ContainingFolder?.Iid == folderNode.Thing?.Iid) .Select(x => new FileFolderNodeViewModel(x)) + .OrderBy(x => x.Name, StringComparer.InvariantCultureIgnoreCase) .ToList(); folderNode.Content.AddRange(nestedFolders); @@ -180,6 +190,18 @@ private void LoadFolderContent(FileFolderNodeViewModel folderNode) } } + /// + /// Sets the collection of s with a null value appended for the contained view models that need it + /// + /// The collection of folders to set + private void SetFolders(IEnumerable folders) + { + var resultingFolders = folders.ToList(); + resultingFolders.Add(null); + this.FileHandlerViewModel.Folders = resultingFolders; + this.FolderHandlerViewModel.Folders = resultingFolders; + } + /// /// Gets the containing folder node for a given node, search in a given flat list of nodes /// diff --git a/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FolderHandler/FolderHandlerViewModel.cs b/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FolderHandler/FolderHandlerViewModel.cs index 32283360..a9039fbc 100644 --- a/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FolderHandler/FolderHandlerViewModel.cs +++ b/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FolderHandler/FolderHandlerViewModel.cs @@ -52,11 +52,10 @@ public FolderHandlerViewModel(ISessionService sessionService, ICDPMessageBus mes this.DomainOfExpertiseSelectorViewModel = new DomainOfExpertiseSelectorViewModel(sessionService, messageBus) { - OnSelectedDomainOfExpertiseChange = new EventCallbackFactory().Create(this, selectedOwner => - { - this.CurrentThing.Owner = selectedOwner; - }) + OnSelectedDomainOfExpertiseChange = new EventCallbackFactory().Create(this, selectedOwner => { this.CurrentThing.Owner = selectedOwner; }) }; + + this.InitializeSubscriptions([typeof(FileStore)]); } /// @@ -70,9 +69,9 @@ public FolderHandlerViewModel(ISessionService sessionService, ICDPMessageBus mes public IDomainOfExpertiseSelectorViewModel DomainOfExpertiseSelectorViewModel { get; private set; } /// - /// Gets a collection of the available s + /// Gets or sets a collection of the available s /// - public IEnumerable Folders { get; private set; } + public IEnumerable Folders { get; set; } /// /// Initializes the current @@ -83,10 +82,6 @@ public void InitializeViewModel(FileStore fileStore, Iteration iteration) { this.CurrentFileStore = fileStore; this.DomainOfExpertiseSelectorViewModel.CurrentIteration = iteration; - - var folders = this.CurrentFileStore.Folder.ToList(); - folders.Add(null); - this.Folders = folders; } /// @@ -121,6 +116,7 @@ public async Task CreateOrEditFolder(bool shouldCreate) if (shouldCreate) { var engineeringModel = this.CurrentFileStore.GetContainerOfType(); + this.CurrentThing.CreatedOn = DateTime.UtcNow; this.CurrentThing.Creator = engineeringModel.GetActiveParticipant(this.SessionService.Session.ActivePerson); fileStoreClone.Folder.Add(this.CurrentThing); @@ -147,10 +143,14 @@ public async Task DeleteFolder() /// Handles the refresh of the current /// /// A - protected override Task OnSessionRefreshed() => Task.CompletedTask; + protected override Task OnSessionRefreshed() + { + return Task.CompletedTask; + } /// - /// Update this view model properties when the has changed + /// Update this view model properties when the has + /// changed /// /// A protected override async Task OnThingChanged() diff --git a/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FolderHandler/IFolderHandlerViewModel.cs b/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FolderHandler/IFolderHandlerViewModel.cs index 5400a6ed..063a49e1 100644 --- a/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FolderHandler/IFolderHandlerViewModel.cs +++ b/COMETwebapp/ViewModels/Components/EngineeringModel/FileStore/FolderHandler/IFolderHandlerViewModel.cs @@ -47,9 +47,9 @@ public interface IFolderHandlerViewModel : IApplicationBaseViewModel Folder CurrentThing { get; set; } /// - /// Gets a collection of the available s + /// Gets or sets a collection of the available s /// - IEnumerable Folders { get; } + IEnumerable Folders { get; set; } /// /// Gets the diff --git a/COMETwebapp/ViewModels/Components/EngineeringModel/Rows/CommonFileStoreRowViewModel.cs b/COMETwebapp/ViewModels/Components/EngineeringModel/Rows/CommonFileStoreRowViewModel.cs index f68e0f9f..d7e3b417 100644 --- a/COMETwebapp/ViewModels/Components/EngineeringModel/Rows/CommonFileStoreRowViewModel.cs +++ b/COMETwebapp/ViewModels/Components/EngineeringModel/Rows/CommonFileStoreRowViewModel.cs @@ -38,7 +38,7 @@ public class CommonFileStoreRowViewModel : BaseDataItemRowViewModel /// The backing field for /// - private string createdOn; + private DateTime createdOn; /// /// Initializes a new instance of the class. @@ -46,13 +46,13 @@ public class CommonFileStoreRowViewModel : BaseDataItemRowViewModelThe associated public CommonFileStoreRowViewModel(CommonFileStore commonFileStore) : base(commonFileStore) { - this.CreatedOn = commonFileStore.CreatedOn.ToString("dd/MM/yyyy HH:mm:ss"); + this.CreatedOn = commonFileStore.CreatedOn; } /// /// The date and time when the was created, as a /// - public string CreatedOn + public DateTime CreatedOn { get => this.createdOn; set => this.RaiseAndSetIfChanged(ref this.createdOn, value);