Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Globalization;
using Aspire.Dashboard.Components.Resize;
using Aspire.Dashboard.Model;
using Aspire.Dashboard.Utils;
using Microsoft.AspNetCore.Components;
using Microsoft.FluentUI.AspNetCore.Components;
using Microsoft.JSInterop;
Expand Down Expand Up @@ -86,7 +85,7 @@ protected override async Task OnParametersSetAsync()
{
if (RememberOrientation)
{
var orientationResult = await LocalStore.SafeGetAsync<Orientation>(GetOrientationStorageKey());
var orientationResult = await LocalStore.GetUnprotectedAsync<Orientation>(GetOrientationStorageKey());
if (orientationResult.Success)
{
Orientation = orientationResult.Value;
Expand All @@ -95,10 +94,11 @@ protected override async Task OnParametersSetAsync()

if (RememberSize)
{
var panel1FractionResult = await LocalStore.SafeGetAsync<float>(GetSizeStorageKey());
var panel1FractionResult = await LocalStore.GetUnprotectedAsync<float>(GetSizeStorageKey());
if (panel1FractionResult.Success)
{
SetPanelSizes(panel1FractionResult.Value);
var fraction = Math.Clamp(panel1FractionResult.Value, 0, 1);
SetPanelSizes(fraction);
}
}
}
Expand Down Expand Up @@ -128,16 +128,16 @@ private async Task HandleToggleOrientation()

if (RememberOrientation)
{
await LocalStore.SetAsync(GetOrientationStorageKey(), Orientation);
await LocalStore.SetUnprotectedAsync(GetOrientationStorageKey(), Orientation);
}

if (RememberSize)
{
var panel1FractionResult = await LocalStore.SafeGetAsync<float>(GetSizeStorageKey());
var panel1FractionResult = await LocalStore.GetUnprotectedAsync<float>(GetSizeStorageKey());
if (panel1FractionResult.Success)
{
SetPanelSizes(panel1FractionResult.Value);

var fraction = Math.Clamp(panel1FractionResult.Value, 0, 1);
SetPanelSizes(fraction);
}
else
{
Expand Down Expand Up @@ -170,7 +170,7 @@ private async Task HandleSplitterResize(SplitterResizedEventArgs args)

private async Task SaveSizeToStorage(float panel1Fraction)
{
await LocalStore.SetAsync(GetSizeStorageKey(), panel1Fraction);
await LocalStore.SetUnprotectedAsync(GetSizeStorageKey(), panel1Fraction);
}

private void ResetPanelSizes()
Expand Down Expand Up @@ -293,13 +293,13 @@ static void GetPanelSizes(
private string GetSizeStorageKey()
{
var viewKey = ViewKey ?? NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
return $"SplitterSize_{Orientation}_{viewKey}";
return $"Aspire_SplitterSize_{Orientation}_{viewKey}";
}

private string GetOrientationStorageKey()
{
var viewKey = ViewKey ?? NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
return $"SplitterOrientation_{viewKey}";
return $"Aspire_SplitterOrientation_{viewKey}";
}

public void Dispose()
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Dashboard/Components/Pages/ConsoleLogs.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public sealed partial class ConsoleLogs : ComponentBase, IAsyncDisposable, IPage
public ConsoleLogsViewModel PageViewModel { get; set; } = null!;

public string BasePath => DashboardUrls.ConsoleLogBasePath;
public string SessionStorageKey => "ConsoleLogs_PageState";
public string SessionStorageKey => "Aspire_ConsoleLogs_PageState";

protected override async Task OnInitializedAsync()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Dashboard/Components/Pages/Metrics.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public partial class Metrics : IDisposable, IPageWithSessionAndUrlState<Metrics.
private Subscription? _metricsSubscription;

public string BasePath => DashboardUrls.MetricsBasePath;
public string SessionStorageKey => "Metrics_PageState";
public string SessionStorageKey => "Aspire_Metrics_PageState";
public MetricsViewModel PageViewModel { get; set; } = null!;

[Parameter]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public partial class StructuredLogs : IPageWithSessionAndUrlState<StructuredLogs
private GridColumnManager _manager = null!;

public string BasePath => DashboardUrls.StructuredLogsBasePath;
public string SessionStorageKey => "StructuredLogs_PageState";
public string SessionStorageKey => "Aspire_StructuredLogs_PageState";
public StructuredLogsPageViewModel PageViewModel { get; set; } = null!;

[Inject]
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Dashboard/Components/Pages/Traces.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public partial class Traces : IPageWithSessionAndUrlState<TracesPageViewModel, T
private AspirePageContentLayout? _contentLayout;
private GridColumnManager _manager = null!;

public string SessionStorageKey => "Traces_PageState";
public string SessionStorageKey => "Aspire_Traces_PageState";
public string BasePath => DashboardUrls.TracesBasePath;
public TracesPageViewModel PageViewModel { get; set; } = null!;

Expand Down
11 changes: 10 additions & 1 deletion src/Aspire.Dashboard/Model/BrowserStorage/ILocalStorage.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Aspire.Dashboard.Model.BrowserStorage;

public interface ILocalStorage : IBrowserStorage
{
/// <summary>
/// Get unprotected data from local storage. This must only be used with non-sensitive data.
/// </summary>
Task<StorageResult<T>> GetUnprotectedAsync<T>(string key);

/// <summary>
/// Set unprotected data to local storage. This must only be used with non-sensitive data.
/// </summary>
Task SetUnprotectedAsync<T>(string key, T value);
}
51 changes: 49 additions & 2 deletions src/Aspire.Dashboard/Model/BrowserStorage/LocalBrowserStorage.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,60 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Text.Json;
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
using Microsoft.JSInterop;

namespace Aspire.Dashboard.Model.BrowserStorage;

public class LocalBrowserStorage : BrowserStorageBase, ILocalStorage
{
public LocalBrowserStorage(ProtectedLocalStorage protectedLocalStorage) : base(protectedLocalStorage)
private static readonly JsonSerializerOptions s_options = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
};

private readonly IJSRuntime _jsRuntime;
private readonly ILogger<LocalBrowserStorage> _logger;

public LocalBrowserStorage(IJSRuntime jsRuntime, ProtectedLocalStorage protectedLocalStorage, ILogger<LocalBrowserStorage> logger) : base(protectedLocalStorage)
{
_jsRuntime = jsRuntime;
_logger = logger;
}

public async Task<StorageResult<T>> GetUnprotectedAsync<T>(string key)
{
var json = await GetJsonAsync(key).ConfigureAwait(false);

if (json == null)
{
return new StorageResult<T>(false, default);
}

try
{
return new StorageResult<T>(true, JsonSerializer.Deserialize<T>(json, s_options));
}
catch (Exception ex)
{
_logger.LogWarning(ex, $"Error when reading '{key}' as {typeof(T).Name} from local browser storage.");

return new StorageResult<T>(false, default);
}
}

public async Task SetUnprotectedAsync<T>(string key, T value)
{
var json = JsonSerializer.Serialize(value, s_options);

await SetJsonAsync(key, json).ConfigureAwait(false);
}

private ValueTask SetJsonAsync(string key, string json)
=> _jsRuntime.InvokeVoidAsync("localStorage.setItem", key, json);

private ValueTask<string?> GetJsonAsync(string key)
=> _jsRuntime.InvokeAsync<string?>("localStorage.getItem", key);
Comment on lines +55 to +59
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two methods return ValueTask. I'm not sure how often these would return completed tasks, but perhaps we also use value tasks on the new methods on ILocalStorage.

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
Expand Down
29 changes: 0 additions & 29 deletions src/Aspire.Dashboard/Utils/IBrowserStorageExtensions.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,21 @@ public sealed class TestLocalStorage : ILocalStorage
{
public Task<StorageResult<T>> GetAsync<T>(string key)
{
return Task.FromResult<StorageResult<T>>(new StorageResult<T>(Success: false, Value: default));
return Task.FromResult(new StorageResult<T>(Success: false, Value: default));
}

public Task<StorageResult<T>> GetUnprotectedAsync<T>(string key)
{
return Task.FromResult(new StorageResult<T>(Success: false, Value: default));
}

public Task SetAsync<T>(string key, T value)
{
return Task.CompletedTask;
}

public Task SetUnprotectedAsync<T>(string key, T value)
{
return Task.CompletedTask;
}
}
Loading