Skip to content

Commit

Permalink
Added layout saving and loading feature to the Shell. (#805)
Browse files Browse the repository at this point in the history
* Added layout saving and loading feature to the Shell
  • Loading branch information
fhubi authored Nov 5, 2024
1 parent fd8a498 commit 1e7db9e
Show file tree
Hide file tree
Showing 15 changed files with 357 additions and 237 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,38 @@

namespace MorganStanley.ComposeUI.LayoutPersistence;

public class FileLayoutPersistence<T> : ILayoutPersistence<T>
public class FileLayoutPersistence : ILayoutPersistence<string>
{
private readonly string _basePath;
private readonly ILayoutSerializer<T> _serializer;
private readonly SemaphoreSlim _semaphore = new(1,1);

public FileLayoutPersistence(string basePath, ILayoutSerializer<T> serializer)
public FileLayoutPersistence(string basePath)
{
_basePath = NormalizeFilePath(basePath);
_serializer = serializer;

if (!Directory.Exists(_basePath))
{
Directory.CreateDirectory(_basePath);
}
}

public async Task SaveLayoutAsync(string layoutName, T layoutData, CancellationToken cancellationToken = default)
public async Task SaveLayoutAsync(string layoutName, string layoutData, CancellationToken cancellationToken = default)
{
var filePath = GetFilePath(layoutName);

await _semaphore.WaitAsync(cancellationToken);

try
{
var serializedData = await _serializer.SerializeAsync(layoutData, cancellationToken);
await File.WriteAllTextAsync(filePath, serializedData, cancellationToken);
await File.WriteAllTextAsync(filePath, layoutData, cancellationToken);
}
finally
{
_semaphore.Release();
}
}

public async Task<T?> LoadLayoutAsync(string layoutName, CancellationToken cancellationToken = default)
public async Task<string?> LoadLayoutAsync(string layoutName, CancellationToken cancellationToken = default)
{
var filePath = GetFilePath(layoutName);

Expand All @@ -63,8 +60,7 @@ public async Task SaveLayoutAsync(string layoutName, T layoutData, CancellationT

try
{
var serializedData = await File.ReadAllTextAsync(filePath, cancellationToken);
return await _serializer.DeserializeAsync(serializedData, cancellationToken);
return await File.ReadAllTextAsync(filePath, cancellationToken);
}
finally
{
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@
* and limitations under the License.
*/

using System.Text.Json;
using FluentAssertions;
using MorganStanley.ComposeUI.LayoutPersistence.Serializers;

namespace MorganStanley.ComposeUI.LayoutPersistence.Tests;

public class FileLayoutPersistenceTests : IDisposable
{
private readonly string _testDirectory = "test_layouts";
private readonly FileLayoutPersistence<LayoutData> _persistence;
private readonly FileLayoutPersistence _persistence;

public FileLayoutPersistenceTests()
{
_persistence = new FileLayoutPersistence<LayoutData>($"file://{_testDirectory}", new JsonLayoutSerializer<LayoutData>());
_persistence = new FileLayoutPersistence($"file://{_testDirectory}");
}

[Fact]
Expand All @@ -38,9 +38,10 @@ public async Task SaveLayout_ShouldCreateFile()
}
};

var serializedLayout = JsonSerializer.Serialize(layoutData);
var layoutName = "TestLayout";

await _persistence.SaveLayoutAsync(layoutName, layoutData);
await _persistence.SaveLayoutAsync(layoutName, serializedLayout);
var filePath = Path.Combine(_testDirectory, "TestLayout.layout");

File.Exists(filePath).Should().BeTrue();
Expand All @@ -57,12 +58,13 @@ public async Task LoadLayout_ShouldReturnCorrectContent()
}
};

var serializedLayout = JsonSerializer.Serialize(layoutData);
var layoutName = "TestLayout";

await _persistence.SaveLayoutAsync(layoutName, layoutData);
await _persistence.SaveLayoutAsync(layoutName, serializedLayout);
var loadedData = await _persistence.LoadLayoutAsync(layoutName);

loadedData.Should().Be(layoutData);
loadedData.Should().Be(serializedLayout);
}

[Fact]
Expand All @@ -76,9 +78,10 @@ public async Task SaveLayout_WithInvalidLayoutName_ShouldThrowArgumentException(
}
};

var serializedLayout = JsonSerializer.Serialize(layoutData);
var layoutName = "../TestLayout";

Func<Task> act = async () => await _persistence.SaveLayoutAsync(layoutName, layoutData);
Func<Task> act = async () => await _persistence.SaveLayoutAsync(layoutName, serializedLayout);
await act.Should().ThrowAsync<ArgumentException>()
.WithMessage("Invalid layoutName argument. File cannot be saved outside of the base directory. *");
}
Expand Down

This file was deleted.

This file was deleted.

7 changes: 7 additions & 0 deletions src/shell/dotnet/Shell.sln
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_", "_", "{1944F009-EA2D-4D
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MorganStanley.ComposeUI.Messaging.Abstractions", "..\..\messaging\dotnet\src\Abstractions\MorganStanley.ComposeUI.Messaging.Abstractions.csproj", "{F90449AE-B26E-42E0-873B-4F0CAE6FCD98}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MorganStanley.ComposeUI.LayoutPersistence", "..\..\layout-persistence\dotnet\src\MorganStanley.ComposeUI.LayoutPersistence\MorganStanley.ComposeUI.LayoutPersistence.csproj", "{DF5677FE-614D-4BD1-A645-119FBA6F3C34}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -114,6 +116,10 @@ Global
{F90449AE-B26E-42E0-873B-4F0CAE6FCD98}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F90449AE-B26E-42E0-873B-4F0CAE6FCD98}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F90449AE-B26E-42E0-873B-4F0CAE6FCD98}.Release|Any CPU.Build.0 = Release|Any CPU
{DF5677FE-614D-4BD1-A645-119FBA6F3C34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DF5677FE-614D-4BD1-A645-119FBA6F3C34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF5677FE-614D-4BD1-A645-119FBA6F3C34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DF5677FE-614D-4BD1-A645-119FBA6F3C34}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -133,6 +139,7 @@ Global
{B7A04459-C612-447F-9245-75DFAF23C31D} = {DA1A43C4-F758-47E2-870A-7E5BBB946671}
{56F41D4A-5A4C-4F41-86CA-1B003992F083} = {DA1A43C4-F758-47E2-870A-7E5BBB946671}
{F90449AE-B26E-42E0-873B-4F0CAE6FCD98} = {E7A2C581-4BF4-47A5-8A11-59B2DEBADCA7}
{DF5677FE-614D-4BD1-A645-119FBA6F3C34} = {E7A2C581-4BF4-47A5-8A11-59B2DEBADCA7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4C901E6C-4B9A-48C2-AB16-461040DC57B4}
Expand Down
4 changes: 4 additions & 0 deletions src/shell/dotnet/Shell/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
using Microsoft.Extensions.Logging.Abstractions;
using MorganStanley.ComposeUI.Fdc3.AppDirectory;
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.DependencyInjection;
using MorganStanley.ComposeUI.LayoutPersistence;
using MorganStanley.ComposeUI.LayoutPersistence.Abstractions;
using MorganStanley.ComposeUI.Messaging;
using MorganStanley.ComposeUI.ModuleLoader;
using MorganStanley.ComposeUI.Shell.Abstractions;
Expand Down Expand Up @@ -150,6 +152,8 @@ private void ConfigureServices(HostBuilderContext context, IServiceCollection se

services.Configure<LoggerFactoryOptions>(context.Configuration.GetSection("Logging"));

services.AddSingleton<ILayoutPersistence<string>>(new FileLayoutPersistence(".\\layouts"));

ConfigureMessageRouter();

ConfigureModules();
Expand Down
Loading

0 comments on commit 1e7db9e

Please sign in to comment.