Migrate to MudBlazor v7.x.x (#41)

This commit is contained in:
Thorsten Sommer 2024-07-24 15:17:45 +02:00 committed by GitHub
parent a956b55d6b
commit 5250e5d2fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 253 additions and 151 deletions

View File

@ -20,7 +20,7 @@
{ {
<MudPaper Class="pr-2 mt-3" Outlined="@true"> <MudPaper Class="pr-2 mt-3" Outlined="@true">
<MudText Typo="Typo.h6">Issues</MudText> <MudText Typo="Typo.h6">Issues</MudText>
<MudList Clickable="@true"> <MudList T="string">
@foreach (var issue in this.inputIssues) @foreach (var issue in this.inputIssues)
{ {
<MudListItem Icon="@Icons.Material.Filled.Error" IconColor="Color.Error"> <MudListItem Icon="@Icons.Material.Filled.Error" IconColor="Color.Error">

View File

@ -1,4 +1,4 @@
<MudExpansionPanel Class="border-solid border rounded-lg" IsInitiallyExpanded="@this.IsExpanded"> <MudExpansionPanel Class="border-solid border rounded-lg" Expanded="@this.IsExpanded">
<TitleContent> <TitleContent>
<div class="d-flex align-center"> <div class="d-flex align-center">
<MudIcon Icon="@this.HeaderIcon" Size="@this.IconSize" Color="@this.IconColor" class="mr-3"/> <MudIcon Icon="@this.HeaderIcon" Size="@this.IconSize" Color="@this.IconColor" class="mr-3"/>

View File

@ -1,7 +1,7 @@
<MudList Clickable="@this.Clickable" Class="@this.Classes"> <MudList T="string" ReadOnly="@(!this.Clickable)" Class="@this.Classes">
@foreach(var item in this.Items) @foreach(var item in this.Items)
{ {
<MudListItem Icon="@this.Icon" Style="display: flex; align-items: flex-start;"> <MudListItem T="string" Icon="@this.Icon" Style="display: flex; align-items: flex-start;">
<MudText Typo="Typo.body1" Style="text-align: justify; hyphens: auto;"><b>@item.Header:</b> @item.Text</MudText> <MudText Typo="Typo.body1" Style="text-align: justify; hyphens: auto;"><b>@item.Header:</b> @item.Text</MudText>
</MudListItem> </MudListItem>
} }

View File

@ -18,5 +18,5 @@ public class TreeItemData : ITreeItem
public bool Expandable { get; init; } = true; public bool Expandable { get; init; } = true;
public HashSet<ITreeItem> Children { get; init; } = []; public IReadOnlyCollection<TreeItemData<ITreeItem>> Children { get; init; } = [];
} }

View File

@ -1,6 +1,6 @@
<MudTreeView T="ITreeItem" Items="@this.treeItems" MultiSelection="@false" Hover="@true" ExpandOnClick="@true"> <MudTreeView T="ITreeItem" Items="@this.treeItems" SelectionMode="SelectionMode.SingleSelection" Hover="@true" ExpandOnClick="@true">
<ItemTemplate Context="item"> <ItemTemplate Context="item">
@switch (item) @switch (item.Value)
{ {
case TreeDivider: case TreeDivider:
<li style="min-height: 1em;"> <li style="min-height: 1em;">
@ -11,7 +11,7 @@
case TreeItemData treeItem: case TreeItemData treeItem:
@if (treeItem.Type is TreeItemType.CHAT) @if (treeItem.Type is TreeItemType.CHAT)
{ {
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item" CanExpand="@treeItem.Expandable" Items="@treeItem.Children" OnClick="() => this.LoadChat(treeItem.Path, true)"> <MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item.Value" CanExpand="@treeItem.Expandable" Items="@treeItem.Children" OnClick="() => this.LoadChat(treeItem.Path, true)">
<BodyContent> <BodyContent>
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%"> <div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
<MudText Style="justify-self: start;"> <MudText Style="justify-self: start;">
@ -44,7 +44,7 @@
} }
else if (treeItem.Type is TreeItemType.WORKSPACE) else if (treeItem.Type is TreeItemType.WORKSPACE)
{ {
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item" CanExpand="@treeItem.Expandable" Items="@treeItem.Children"> <MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item.Value" CanExpand="@treeItem.Expandable" Items="@treeItem.Children">
<BodyContent> <BodyContent>
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%"> <div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
<MudText Style="justify-self: start;">@treeItem.Text</MudText> <MudText Style="justify-self: start;">@treeItem.Text</MudText>
@ -63,7 +63,7 @@
} }
else else
{ {
<MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item" CanExpand="@treeItem.Expandable" Items="@treeItem.Children"> <MudTreeViewItem T="ITreeItem" Icon="@treeItem.Icon" Value="@item.Value" CanExpand="@treeItem.Expandable" Items="@treeItem.Children">
<BodyContent> <BodyContent>
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%"> <div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
<MudText Style="justify-self: start;">@treeItem.Text</MudText> <MudText Style="justify-self: start;">@treeItem.Text</MudText>

View File

@ -47,8 +47,8 @@ public partial class Workspaces : ComponentBase
new JsonStringEnumConverter(JsonNamingPolicy.SnakeCaseUpper), new JsonStringEnumConverter(JsonNamingPolicy.SnakeCaseUpper),
} }
}; };
private readonly HashSet<ITreeItem> treeItems = new(); private readonly List<TreeItemData<ITreeItem>> treeItems = new();
#region Overrides of ComponentBase #region Overrides of ComponentBase
@ -70,33 +70,46 @@ public partial class Workspaces : ComponentBase
private async Task LoadTreeItems() private async Task LoadTreeItems()
{ {
this.treeItems.Clear(); this.treeItems.Clear();
this.treeItems.Add(new TreeItemData this.treeItems.Add(new TreeItemData<ITreeItem>
{ {
Depth = 0,
Branch = WorkspaceBranch.WORKSPACES,
Text = "Workspaces",
Icon = Icons.Material.Filled.Folder,
Expandable = true, Expandable = true,
Path = "root", Value = new TreeItemData
Children = await this.LoadWorkspaces(), {
Depth = 0,
Branch = WorkspaceBranch.WORKSPACES,
Text = "Workspaces",
Icon = Icons.Material.Filled.Folder,
Expandable = true,
Path = "root",
Children = await this.LoadWorkspaces(),
},
}); });
this.treeItems.Add(new TreeDivider()); this.treeItems.Add(new TreeItemData<ITreeItem>
this.treeItems.Add(new TreeItemData {
Expandable = false,
Value = new TreeDivider(),
});
this.treeItems.Add(new TreeItemData<ITreeItem>
{ {
Depth = 0,
Branch = WorkspaceBranch.TEMPORARY_CHATS,
Text = "Temporary chats",
Icon = Icons.Material.Filled.Timer,
Expandable = true, Expandable = true,
Path = "temp", Value = new TreeItemData
Children = await this.LoadTemporaryChats(), {
Depth = 0,
Branch = WorkspaceBranch.TEMPORARY_CHATS,
Text = "Temporary chats",
Icon = Icons.Material.Filled.Timer,
Expandable = true,
Path = "temp",
Children = await this.LoadTemporaryChats(),
},
}); });
} }
private async Task<HashSet<ITreeItem>> LoadTemporaryChats() private async Task<IReadOnlyCollection<TreeItemData<ITreeItem>>> LoadTemporaryChats()
{ {
var tempChildren = new HashSet<ITreeItem>(); var tempChildren = new List<TreeItemData<ITreeItem>>();
// //
// Search for workspace folders in the data directory: // Search for workspace folders in the data directory:
@ -115,15 +128,19 @@ public partial class Workspaces : ComponentBase
var chatNamePath = Path.Join(tempChatDirPath, "name"); var chatNamePath = Path.Join(tempChatDirPath, "name");
var chatName = await File.ReadAllTextAsync(chatNamePath, Encoding.UTF8); var chatName = await File.ReadAllTextAsync(chatNamePath, Encoding.UTF8);
tempChildren.Add(new TreeItemData tempChildren.Add(new TreeItemData<ITreeItem>
{ {
Type = TreeItemType.CHAT,
Depth = 1,
Branch = WorkspaceBranch.TEMPORARY_CHATS,
Text = chatName,
Icon = Icons.Material.Filled.Timer,
Expandable = false, Expandable = false,
Path = tempChatDirPath, Value = new TreeItemData
{
Type = TreeItemType.CHAT,
Depth = 1,
Branch = WorkspaceBranch.TEMPORARY_CHATS,
Text = chatName,
Icon = Icons.Material.Filled.Timer,
Expandable = false,
Path = tempChatDirPath,
},
}); });
} }
@ -140,9 +157,9 @@ public partial class Workspaces : ComponentBase
return await File.ReadAllTextAsync(workspaceNamePath, Encoding.UTF8); return await File.ReadAllTextAsync(workspaceNamePath, Encoding.UTF8);
} }
private async Task<HashSet<ITreeItem>> LoadWorkspaces() private async Task<IReadOnlyCollection<TreeItemData<ITreeItem>>> LoadWorkspaces()
{ {
var workspaces = new HashSet<ITreeItem>(); var workspaces = new List<TreeItemData<ITreeItem>>();
// //
// Search for workspace folders in the data directory: // Search for workspace folders in the data directory:
@ -161,26 +178,34 @@ public partial class Workspaces : ComponentBase
var workspaceNamePath = Path.Join(workspaceDirPath, "name"); var workspaceNamePath = Path.Join(workspaceDirPath, "name");
var workspaceName = await File.ReadAllTextAsync(workspaceNamePath, Encoding.UTF8); var workspaceName = await File.ReadAllTextAsync(workspaceNamePath, Encoding.UTF8);
workspaces.Add(new TreeItemData workspaces.Add(new TreeItemData<ITreeItem>
{ {
Type = TreeItemType.WORKSPACE,
Depth = 1,
Branch = WorkspaceBranch.WORKSPACES,
Text = workspaceName,
Icon = Icons.Material.Filled.Description,
Expandable = true, Expandable = true,
Path = workspaceDirPath, Value = new TreeItemData
Children = await this.LoadWorkspaceChats(workspaceDirPath), {
Type = TreeItemType.WORKSPACE,
Depth = 1,
Branch = WorkspaceBranch.WORKSPACES,
Text = workspaceName,
Icon = Icons.Material.Filled.Description,
Expandable = true,
Path = workspaceDirPath,
Children = await this.LoadWorkspaceChats(workspaceDirPath),
},
}); });
} }
workspaces.Add(new TreeButton(WorkspaceBranch.WORKSPACES, 1, "Add workspace",Icons.Material.Filled.LibraryAdd, this.AddWorkspace)); workspaces.Add(new TreeItemData<ITreeItem>
{
Expandable = false,
Value = new TreeButton(WorkspaceBranch.WORKSPACES, 1, "Add workspace",Icons.Material.Filled.LibraryAdd, this.AddWorkspace),
});
return workspaces; return workspaces;
} }
private async Task<HashSet<ITreeItem>> LoadWorkspaceChats(string workspacePath) private async Task<IReadOnlyCollection<TreeItemData<ITreeItem>>> LoadWorkspaceChats(string workspacePath)
{ {
var workspaceChats = new HashSet<ITreeItem>(); var workspaceChats = new List<TreeItemData<ITreeItem>>();
// Enumerate the workspace directory: // Enumerate the workspace directory:
foreach (var chatPath in Directory.EnumerateDirectories(workspacePath)) foreach (var chatPath in Directory.EnumerateDirectories(workspacePath))
@ -189,19 +214,28 @@ public partial class Workspaces : ComponentBase
var chatNamePath = Path.Join(chatPath, "name"); var chatNamePath = Path.Join(chatPath, "name");
var chatName = await File.ReadAllTextAsync(chatNamePath, Encoding.UTF8); var chatName = await File.ReadAllTextAsync(chatNamePath, Encoding.UTF8);
workspaceChats.Add(new TreeItemData workspaceChats.Add(new TreeItemData<ITreeItem>
{ {
Type = TreeItemType.CHAT,
Depth = 2,
Branch = WorkspaceBranch.WORKSPACES,
Text = chatName,
Icon = Icons.Material.Filled.Chat,
Expandable = false, Expandable = false,
Path = chatPath, Value = new TreeItemData
{
Type = TreeItemType.CHAT,
Depth = 2,
Branch = WorkspaceBranch.WORKSPACES,
Text = chatName,
Icon = Icons.Material.Filled.Chat,
Expandable = false,
Path = chatPath,
},
}); });
} }
workspaceChats.Add(new TreeButton(WorkspaceBranch.WORKSPACES, 2, "Add chat",Icons.Material.Filled.AddComment, () => this.AddChat(workspacePath))); workspaceChats.Add(new TreeItemData<ITreeItem>
{
Expandable = false,
Value = new TreeButton(WorkspaceBranch.WORKSPACES, 2, "Add chat",Icons.Material.Filled.AddComment, () => this.AddChat(workspacePath)),
});
return workspaceChats; return workspaceChats;
} }
@ -247,7 +281,7 @@ public partial class Workspaces : ComponentBase
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Load Chat", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Load Chat", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return null; return null;
} }
@ -294,7 +328,7 @@ public partial class Workspaces : ComponentBase
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Chat", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Chat", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
} }
@ -331,7 +365,7 @@ public partial class Workspaces : ComponentBase
var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>("Rename Chat", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>("Rename Chat", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
chat.Name = (dialogResult.Data as string)!; chat.Name = (dialogResult.Data as string)!;
@ -356,7 +390,7 @@ public partial class Workspaces : ComponentBase
var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>("Rename Workspace", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>("Rename Workspace", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
var alteredWorkspaceName = (dialogResult.Data as string)!; var alteredWorkspaceName = (dialogResult.Data as string)!;
@ -377,7 +411,7 @@ public partial class Workspaces : ComponentBase
var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>("Add Workspace", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<SingleInputDialog>("Add Workspace", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
var workspaceId = Guid.NewGuid(); var workspaceId = Guid.NewGuid();
@ -408,7 +442,7 @@ public partial class Workspaces : ComponentBase
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Workspace", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Workspace", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
Directory.Delete(workspacePath, true); Directory.Delete(workspacePath, true);
@ -430,7 +464,7 @@ public partial class Workspaces : ComponentBase
var dialogReference = await this.DialogService.ShowAsync<WorkspaceSelectionDialog>("Move Chat to Workspace", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<WorkspaceSelectionDialog>("Move Chat to Workspace", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
var workspaceId = dialogResult.Data is Guid id ? id : default; var workspaceId = dialogResult.Data is Guid id ? id : default;
@ -475,7 +509,7 @@ public partial class Workspaces : ComponentBase
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Create Chat", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Create Chat", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
} }

View File

@ -1,4 +1,5 @@
using AIStudio.Settings; using AIStudio.Settings;
using AIStudio.Tools;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
@ -23,7 +24,12 @@ public partial class ConfigurationBase : ComponentBase
public string OptionHelp { get; set; } = string.Empty; public string OptionHelp { get; set; } = string.Empty;
[Inject] [Inject]
public SettingsManager SettingsManager { get; init; } = null!; protected SettingsManager SettingsManager { get; init; } = null!;
[Inject]
protected MessageBus MessageBus { get; init; } = null!;
protected const string MARGIN_CLASS = "mb-6"; protected const string MARGIN_CLASS = "mb-6";
protected async Task InformAboutChange() => await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
} }

View File

@ -35,5 +35,6 @@ public partial class ConfigurationOption : ConfigurationBase
{ {
this.StateUpdate(updatedState); this.StateUpdate(updatedState);
await this.SettingsManager.StoreSettings(); await this.SettingsManager.StoreSettings();
await this.InformAboutChange();
} }
} }

View File

@ -30,6 +30,7 @@ public partial class ConfigurationSelect<T> : ConfigurationBase
{ {
this.SelectionUpdate(updatedValue); this.SelectionUpdate(updatedValue);
await this.SettingsManager.StoreSettings(); await this.SettingsManager.StoreSettings();
await this.InformAboutChange();
} }
private static string GetClass => $"{MARGIN_CLASS} rounded-lg"; private static string GetClass => $"{MARGIN_CLASS} rounded-lg";

View File

@ -47,4 +47,12 @@ public static class ConfigurationSelectDataFactory
yield return new("Delete temporary chats older than 180 days", WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_180_DAYS); yield return new("Delete temporary chats older than 180 days", WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_180_DAYS);
yield return new("Delete temporary chats older than 1 year", WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_365_DAYS); yield return new("Delete temporary chats older than 1 year", WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_365_DAYS);
} }
public static IEnumerable<ConfigurationSelectData<NavBehavior>> GetNavBehaviorData()
{
yield return new("Navigation expands on mouse hover", NavBehavior.EXPAND_ON_HOVER);
yield return new("Navigation never expands, but there are tooltips", NavBehavior.NEVER_EXPAND_USE_TOOLTIPS);
yield return new("Navigation never expands, no tooltips", NavBehavior.NEVER_EXPAND_NO_TOOLTIPS);
yield return new("Always expand navigation", NavBehavior.ALWAYS_EXPAND);
}
} }

View File

@ -1,36 +1,32 @@
@inherits LayoutComponentBase @using AIStudio.Settings
@inherits LayoutComponentBase
<MudPaper Height="calc(100vh);" Elevation="0"> <MudPaper Height="calc(100vh);" Elevation="0">
<MudLayout> <MudLayout>
@if (!this.performingUpdate) @if (!this.performingUpdate)
{ {
<MudDrawerContainer Class="mud-height-full absolute"> <MudDrawerContainer Class="mud-height-full absolute">
<MudDrawer Elevation="0" Variant="@DrawerVariant.Mini" OpenMiniOnHover="@true" Color="Color.Default"> <MudDrawer @bind-Open="@this.navBarOpen" MiniWidth="@NAVBAR_COLLAPSED_WIDTH" Width="@NAVBAR_EXPANDED_WIDTH" Elevation="1" Fixed="@true" Variant="@DrawerVariant.Mini" OpenMiniOnHover="@(this.SettingsManager.ConfigurationData.NavigationBehavior is NavBehavior.EXPAND_ON_HOVER)" Color="Color.Default">
<MudNavMenu> <MudNavMenu>
<MudTooltip Text="Home" Placement="Placement.Right"> @foreach (var navBarItem in NAV_ITEMS)
<MudNavLink Href="/" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">Home</MudNavLink> {
</MudTooltip> if (this.SettingsManager.ConfigurationData.NavigationBehavior is NavBehavior.NEVER_EXPAND_USE_TOOLTIPS)
<MudTooltip Text="Chat" Placement="Placement.Right"> {
<MudNavLink Href="/chat" Icon="@Icons.Material.Filled.Chat">Chat</MudNavLink> <MudTooltip Text="@navBarItem.Name" Placement="Placement.Right">
</MudTooltip> <MudNavLink Href="@navBarItem.Path" Match="@(navBarItem.MatchAll ? NavLinkMatch.All : NavLinkMatch.Prefix)" Icon="@navBarItem.Icon" IconColor="@navBarItem.IconColor">@navBarItem.Name</MudNavLink>
<MudTooltip Text="Assistants" Placement="Placement.Right"> </MudTooltip>
<MudNavLink Href="/assistants" Icon="@Icons.Material.Filled.Apps">Assistants</MudNavLink> }
</MudTooltip> else
<MudTooltip Text="Supporters" Placement="Placement.Right"> {
<MudNavLink Href="/supporters" Icon="@Icons.Material.Filled.Favorite" IconColor="Color.Error">Supporters</MudNavLink> <MudNavLink Href="@navBarItem.Path" Match="@(navBarItem.MatchAll ? NavLinkMatch.All : NavLinkMatch.Prefix)" Icon="@navBarItem.Icon" IconColor="@navBarItem.IconColor">@navBarItem.Name</MudNavLink>
</MudTooltip> }
<MudTooltip Text="About" Placement="Placement.Right"> }
<MudNavLink Href="/about" Icon="@Icons.Material.Filled.Info">About</MudNavLink>
</MudTooltip>
<MudTooltip Text="Settings" Placement="Placement.Right">
<MudNavLink Href="/settings" Icon="@Icons.Material.Filled.Settings">Settings</MudNavLink>
</MudTooltip>
</MudNavMenu> </MudNavMenu>
</MudDrawer> </MudDrawer>
</MudDrawerContainer> </MudDrawerContainer>
} }
<MudMainContent Class="mud-height-full pt-1"> <MudMainContent Class="mud-height-full pt-1" Style="@this.PaddingLeft">
<MudContainer Fixed="@true" Class="mud-height-full" Style="margin-left: 5em; width: calc(100% - 5em);"> <MudContainer Fixed="@true" Class="mud-height-full" Style="margin-left: 5em; width: calc(100% - 5em);">
@if (!this.performingUpdate && this.IsUpdateAlertVisible) @if (!this.performingUpdate && this.IsUpdateAlertVisible)
{ {

View File

@ -34,12 +34,30 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
public string AdditionalHeight { get; private set; } = "0em"; public string AdditionalHeight { get; private set; } = "0em";
private string PaddingLeft => this.navBarOpen ? $"padding-left: {NAVBAR_EXPANDED_WIDTH_INT - NAVBAR_COLLAPSED_WIDTH_INT}em;" : "padding-left: 0em;";
private const int NAVBAR_COLLAPSED_WIDTH_INT = 4;
private const int NAVBAR_EXPANDED_WIDTH_INT = 10;
private static readonly string NAVBAR_COLLAPSED_WIDTH = $"{NAVBAR_COLLAPSED_WIDTH_INT}em";
private static readonly string NAVBAR_EXPANDED_WIDTH = $"{NAVBAR_EXPANDED_WIDTH_INT}em";
private bool navBarOpen;
private bool isUpdateAvailable; private bool isUpdateAvailable;
private bool performingUpdate; private bool performingUpdate;
private bool userDismissedUpdate; private bool userDismissedUpdate;
private string updateToVersion = string.Empty; private string updateToVersion = string.Empty;
private UpdateResponse? currentUpdateResponse; private UpdateResponse? currentUpdateResponse;
private static readonly IReadOnlyCollection<NavBarItem> NAV_ITEMS = new List<NavBarItem>
{
new("Home", Icons.Material.Filled.Home, Color.Default, "/", true),
new("Chat", Icons.Material.Filled.Chat, Color.Default, "/chat", false),
new("Assistants", Icons.Material.Filled.Apps, Color.Default ,"/assistants", false),
new("Supporters", Icons.Material.Filled.Favorite, Color.Error ,"/supporters", false),
new("About", Icons.Material.Filled.Info, Color.Default ,"/about", false),
new("Settings", Icons.Material.Filled.Settings, Color.Default ,"/settings", false),
};
#region Overrides of ComponentBase #region Overrides of ComponentBase
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
@ -63,12 +81,16 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
// Register this component with the message bus: // Register this component with the message bus:
this.MessageBus.RegisterComponent(this); this.MessageBus.RegisterComponent(this);
this.MessageBus.ApplyFilters(this, [], [ Event.UPDATE_AVAILABLE, Event.USER_SEARCH_FOR_UPDATE ]); this.MessageBus.ApplyFilters(this, [], [ Event.UPDATE_AVAILABLE, Event.USER_SEARCH_FOR_UPDATE, Event.CONFIGURATION_CHANGED ]);
// Set the js runtime for the update service: // Set the js runtime for the update service:
UpdateService.SetBlazorDependencies(this.JsRuntime, this.Snackbar); UpdateService.SetBlazorDependencies(this.JsRuntime, this.Snackbar);
TemporaryChatService.Initialize(); TemporaryChatService.Initialize();
// Should the navigation bar be open by default?
if(this.SettingsManager.ConfigurationData.NavigationBehavior is NavBehavior.ALWAYS_EXPAND)
this.navBarOpen = true;
await base.OnInitializedAsync(); await base.OnInitializedAsync();
} }
@ -96,6 +118,15 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
} }
break; break;
case Event.CONFIGURATION_CHANGED:
if(this.SettingsManager.ConfigurationData.NavigationBehavior is NavBehavior.ALWAYS_EXPAND)
this.navBarOpen = true;
else
this.navBarOpen = false;
this.StateHasChanged();
break;
} }
} }
@ -105,7 +136,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
} }
#endregion #endregion
private async Task DismissUpdate() private async Task DismissUpdate()
{ {
this.userDismissedUpdate = true; this.userDismissedUpdate = true;
@ -151,7 +182,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
var dialogReference = await this.DialogService.ShowAsync<UpdateDialog>("Update", dialogParameters, DialogOptions.FULLSCREEN_NO_HEADER); var dialogReference = await this.DialogService.ShowAsync<UpdateDialog>("Update", dialogParameters, DialogOptions.FULLSCREEN_NO_HEADER);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
this.performingUpdate = true; this.performingUpdate = true;
@ -170,7 +201,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Leave Chat Page", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Leave Chat Page", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
{ {
context.PreventNavigation(); context.PreventNavigation();
return; return;

View File

@ -0,0 +1,3 @@
namespace AIStudio.Components.Layout;
public record NavBarItem(string Name, string Icon, Color IconColor, string Path, bool MatchAll);

View File

@ -9,14 +9,14 @@
<MudText> <MudText>
The following list shows the versions of the MindWork AI Studio, the used compilers, build time, etc.: The following list shows the versions of the MindWork AI Studio, the used compilers, build time, etc.:
</MudText> </MudText>
<MudList Clickable="@true"> <MudList T="string">
<MudListItem Icon="@Icons.Material.Outlined.Chat" Text="@VersionApp"/> <MudListItem T="string" Icon="@Icons.Material.Outlined.Chat" Text="@VersionApp"/>
<MudListItem Icon="@Icons.Material.Outlined.Timer" Text="@BuildTime"/> <MudListItem T="string" Icon="@Icons.Material.Outlined.Timer" Text="@BuildTime"/>
<MudListItem Icon="@Icons.Material.Outlined.Build" Text="@VersionDotnetSdk"/> <MudListItem T="string" Icon="@Icons.Material.Outlined.Build" Text="@VersionDotnetSdk"/>
<MudListItem Icon="@Icons.Material.Outlined.Memory" Text="@VersionDotnetRuntime"/> <MudListItem T="string" Icon="@Icons.Material.Outlined.Memory" Text="@VersionDotnetRuntime"/>
<MudListItem Icon="@Icons.Material.Outlined.Build" Text="@VersionRust"/> <MudListItem T="string" Icon="@Icons.Material.Outlined.Build" Text="@VersionRust"/>
<MudListItem Icon="@Icons.Material.Outlined.Widgets" Text="@MudBlazorVersion"/> <MudListItem T="string" Icon="@Icons.Material.Outlined.Widgets" Text="@MudBlazorVersion"/>
<MudListItem Icon="@Icons.Material.Outlined.Memory" Text="@TauriVersion"/> <MudListItem T="string" Icon="@Icons.Material.Outlined.Memory" Text="@TauriVersion"/>
</MudList> </MudList>
<MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.Update" OnClick="() => this.CheckForUpdate()"> <MudButton Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.Update" OnClick="() => this.CheckForUpdate()">
Check for updates Check for updates

View File

@ -235,7 +235,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Chat", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Chat", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
} }
@ -297,7 +297,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable
var confirmationDialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Unsaved Changes", confirmationDialogParameters, DialogOptions.FULLSCREEN); var confirmationDialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Unsaved Changes", confirmationDialogParameters, DialogOptions.FULLSCREEN);
var confirmationDialogResult = await confirmationDialogReference.Result; var confirmationDialogResult = await confirmationDialogReference.Result;
if (confirmationDialogResult.Canceled) if (confirmationDialogResult is null || confirmationDialogResult.Canceled)
return; return;
} }
@ -310,7 +310,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable
var dialogReference = await this.DialogService.ShowAsync<WorkspaceSelectionDialog>("Move Chat to Workspace", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<WorkspaceSelectionDialog>("Move Chat to Workspace", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
var workspaceId = dialogResult.Data is Guid id ? id : default; var workspaceId = dialogResult.Data is Guid id ? id : default;

View File

@ -1,5 +1,3 @@
using AIStudio.Provider;
namespace AIStudio.Components.Pages.IconFinder; namespace AIStudio.Components.Pages.IconFinder;
public partial class AssistantIconFinder : AssistantBaseCore public partial class AssistantIconFinder : AssistantBaseCore

View File

@ -73,5 +73,6 @@
<ConfigurationSelect OptionDescription="Check for updates" SelectedValue="@(() => this.SettingsManager.ConfigurationData.UpdateBehavior)" Data="@ConfigurationSelectDataFactory.GetUpdateBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.UpdateBehavior = selectedValue)" OptionHelp="How often should we check for app updates?"/> <ConfigurationSelect OptionDescription="Check for updates" SelectedValue="@(() => this.SettingsManager.ConfigurationData.UpdateBehavior)" Data="@ConfigurationSelectDataFactory.GetUpdateBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.UpdateBehavior = selectedValue)" OptionHelp="How often should we check for app updates?"/>
<ConfigurationSelect OptionDescription="Workspace behavior" SelectedValue="@(() => this.SettingsManager.ConfigurationData.WorkspaceStorageBehavior)" Data="@ConfigurationSelectDataFactory.GetWorkspaceStorageBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.WorkspaceStorageBehavior = selectedValue)" OptionHelp="Should we store your chats?"/> <ConfigurationSelect OptionDescription="Workspace behavior" SelectedValue="@(() => this.SettingsManager.ConfigurationData.WorkspaceStorageBehavior)" Data="@ConfigurationSelectDataFactory.GetWorkspaceStorageBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.WorkspaceStorageBehavior = selectedValue)" OptionHelp="Should we store your chats?"/>
<ConfigurationSelect OptionDescription="Workspace maintenance" SelectedValue="@(() => this.SettingsManager.ConfigurationData.WorkspaceStorageTemporaryMaintenancePolicy)" Data="@ConfigurationSelectDataFactory.GetWorkspaceStorageTemporaryMaintenancePolicyData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.WorkspaceStorageTemporaryMaintenancePolicy = selectedValue)" OptionHelp="If and when should we delete your temporary chats?"/> <ConfigurationSelect OptionDescription="Workspace maintenance" SelectedValue="@(() => this.SettingsManager.ConfigurationData.WorkspaceStorageTemporaryMaintenancePolicy)" Data="@ConfigurationSelectDataFactory.GetWorkspaceStorageTemporaryMaintenancePolicyData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.WorkspaceStorageTemporaryMaintenancePolicy = selectedValue)" OptionHelp="If and when should we delete your temporary chats?"/>
<ConfigurationSelect OptionDescription="Navigation bar behavior" SelectedValue="@(() => this.SettingsManager.ConfigurationData.NavigationBehavior)" Data="@ConfigurationSelectDataFactory.GetNavBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.NavigationBehavior = selectedValue)" OptionHelp="Select the desired behavior for the navigation bar."/>
</MudPaper> </MudPaper>
</InnerScrolling> </InnerScrolling>

View File

@ -1,6 +1,8 @@
using AIStudio.Components.CommonDialogs; using AIStudio.Components.CommonDialogs;
using AIStudio.Provider; using AIStudio.Provider;
using AIStudio.Settings; using AIStudio.Settings;
using AIStudio.Tools;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using DialogOptions = AIStudio.Components.CommonDialogs.DialogOptions; using DialogOptions = AIStudio.Components.CommonDialogs.DialogOptions;
@ -19,6 +21,9 @@ public partial class Settings : ComponentBase
[Inject] [Inject]
public IJSRuntime JsRuntime { get; init; } = null!; public IJSRuntime JsRuntime { get; init; } = null!;
[Inject]
protected MessageBus MessageBus { get; init; } = null!;
#region Provider related #region Provider related
@ -31,14 +36,15 @@ public partial class Settings : ComponentBase
var dialogReference = await this.DialogService.ShowAsync<ProviderDialog>("Add Provider", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<ProviderDialog>("Add Provider", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
var addedProvider = (AIStudio.Settings.Provider)dialogResult.Data; var addedProvider = (AIStudio.Settings.Provider)dialogResult.Data!;
addedProvider = addedProvider with { Num = this.SettingsManager.ConfigurationData.NextProviderNum++ }; addedProvider = addedProvider with { Num = this.SettingsManager.ConfigurationData.NextProviderNum++ };
this.SettingsManager.ConfigurationData.Providers.Add(addedProvider); this.SettingsManager.ConfigurationData.Providers.Add(addedProvider);
await this.SettingsManager.StoreSettings(); await this.SettingsManager.StoreSettings();
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
} }
private async Task EditProvider(AIStudio.Settings.Provider provider) private async Task EditProvider(AIStudio.Settings.Provider provider)
@ -58,10 +64,10 @@ public partial class Settings : ComponentBase
var dialogReference = await this.DialogService.ShowAsync<ProviderDialog>("Edit Provider", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<ProviderDialog>("Edit Provider", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
var editedProvider = (AIStudio.Settings.Provider)dialogResult.Data; var editedProvider = (AIStudio.Settings.Provider)dialogResult.Data!;
// Set the provider number if it's not set. This is important for providers // Set the provider number if it's not set. This is important for providers
// added before we started saving the provider number. // added before we started saving the provider number.
@ -70,6 +76,7 @@ public partial class Settings : ComponentBase
this.SettingsManager.ConfigurationData.Providers[this.SettingsManager.ConfigurationData.Providers.IndexOf(provider)] = editedProvider; this.SettingsManager.ConfigurationData.Providers[this.SettingsManager.ConfigurationData.Providers.IndexOf(provider)] = editedProvider;
await this.SettingsManager.StoreSettings(); await this.SettingsManager.StoreSettings();
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
} }
private async Task DeleteProvider(AIStudio.Settings.Provider provider) private async Task DeleteProvider(AIStudio.Settings.Provider provider)
@ -81,7 +88,7 @@ public partial class Settings : ComponentBase
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Provider", dialogParameters, DialogOptions.FULLSCREEN); var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>("Delete Provider", dialogParameters, DialogOptions.FULLSCREEN);
var dialogResult = await dialogReference.Result; var dialogResult = await dialogReference.Result;
if (dialogResult.Canceled) if (dialogResult is null || dialogResult.Canceled)
return; return;
var providerInstance = provider.CreateProvider(); var providerInstance = provider.CreateProvider();
@ -91,6 +98,8 @@ public partial class Settings : ComponentBase
this.SettingsManager.ConfigurationData.Providers.Remove(provider); this.SettingsManager.ConfigurationData.Providers.Remove(provider);
await this.SettingsManager.StoreSettings(); await this.SettingsManager.StoreSettings();
} }
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
} }
private string GetProviderDashboardURL(Providers provider) => provider switch private string GetProviderDashboardURL(Providers provider) => provider switch

View File

@ -1,4 +1,3 @@
using AIStudio.Provider;
using AIStudio.Tools; using AIStudio.Tools;
namespace AIStudio.Components.Pages.TextSummarizer; namespace AIStudio.Components.Pages.TextSummarizer;

View File

@ -1,4 +1,3 @@
using AIStudio.Provider;
using AIStudio.Tools; using AIStudio.Tools;
namespace AIStudio.Components.Pages.Translator; namespace AIStudio.Components.Pages.Translator;

View File

@ -7,4 +7,5 @@
<MudThemeProvider /> <MudThemeProvider />
<MudDialogProvider /> <MudDialogProvider />
<MudPopoverProvider />
<MudSnackbarProvider /> <MudSnackbarProvider />

View File

@ -45,8 +45,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.6" /> <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.7" />
<PackageReference Include="MudBlazor" Version="6.20.0" /> <PackageReference Include="MudBlazor" Version="7.4.0" />
<PackageReference Include="MudBlazor.Markdown" Version="1.0.2" /> <PackageReference Include="MudBlazor.Markdown" Version="1.0.2" />
</ItemGroup> </ItemGroup>

View File

@ -51,4 +51,9 @@ public sealed class Data
/// The chat storage maintenance behavior. /// The chat storage maintenance behavior.
/// </summary> /// </summary>
public WorkspaceStorageTemporaryMaintenancePolicy WorkspaceStorageTemporaryMaintenancePolicy { get; set; } = WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_90_DAYS; public WorkspaceStorageTemporaryMaintenancePolicy WorkspaceStorageTemporaryMaintenancePolicy { get; set; } = WorkspaceStorageTemporaryMaintenancePolicy.DELETE_OLDER_THAN_90_DAYS;
/// <summary>
/// The navigation behavior.
/// </summary>
public NavBehavior NavigationBehavior { get; set; } = NavBehavior.EXPAND_ON_HOVER;
} }

View File

@ -0,0 +1,9 @@
namespace AIStudio.Settings;
public enum NavBehavior
{
EXPAND_ON_HOVER,
NEVER_EXPAND_USE_TOOLTIPS,
NEVER_EXPAND_NO_TOOLTIPS,
ALWAYS_EXPAND,
}

View File

@ -79,10 +79,10 @@
{ {
<MudPaper Class="pa-2 mt-3"> <MudPaper Class="pa-2 mt-3">
<MudText Typo="Typo.h6">Issues</MudText> <MudText Typo="Typo.h6">Issues</MudText>
<MudList Clickable="@true"> <MudList T="string">
@foreach (var issue in this.dataIssues) @foreach (var issue in this.dataIssues)
{ {
<MudListItem Icon="@Icons.Material.Filled.Error" IconColor="Color.Error"> <MudListItem T="string" Icon="@Icons.Material.Filled.Error" IconColor="Color.Error">
@issue @issue
</MudListItem> </MudListItem>
} }

View File

@ -6,6 +6,7 @@ public enum Event
// Common events: // Common events:
STATE_HAS_CHANGED, STATE_HAS_CHANGED,
CONFIGURATION_CHANGED,
// Update events: // Update events:
USER_SEARCH_FOR_UPDATE, USER_SEARCH_FOR_UPDATE,

View File

@ -4,9 +4,9 @@
"net8.0": { "net8.0": {
"Microsoft.Extensions.FileProviders.Embedded": { "Microsoft.Extensions.FileProviders.Embedded": {
"type": "Direct", "type": "Direct",
"requested": "[8.0.6, )", "requested": "[8.0.7, )",
"resolved": "8.0.6", "resolved": "8.0.7",
"contentHash": "hQlf5+YxiUbKdpaPBf/zdMGItnWF8ai9ToPjeZ6gnxT10V4RGDKvChl5MSdc838+2SRHLAC0cdJwG0+L7dqR0g==", "contentHash": "ABsn0T09b5lzVNbOcuRc10+kNZkO+RGtZWfzqVay0Ah+/ouhEvG7JrXc+9+7zFgoPuH4E4N6+uWfTp+pJqMeGw==",
"dependencies": { "dependencies": {
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0" "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0"
} }
@ -19,13 +19,13 @@
}, },
"MudBlazor": { "MudBlazor": {
"type": "Direct", "type": "Direct",
"requested": "[6.20.0, )", "requested": "[7.4.0, )",
"resolved": "6.20.0", "resolved": "7.4.0",
"contentHash": "2MqW/E1OLszSqDhW06rpRTN4OpIRJU0iVzeiZLPzymckrKJH1Hg09St+O3kaEnsbXRcjcdM9iE5cSKzCgxvySQ==", "contentHash": "dm8ZD6OhyI6icE3Si0V3BJvwPZp8fEspPFq4/iQXU8/i7L39/ny2bPgQqPnQmIojppd9cR/H4RdsaBlSLe6rIw==",
"dependencies": { "dependencies": {
"Microsoft.AspNetCore.Components": "8.0.3", "Microsoft.AspNetCore.Components": "8.0.6",
"Microsoft.AspNetCore.Components.Web": "8.0.3", "Microsoft.AspNetCore.Components.Web": "8.0.6",
"Microsoft.Extensions.Localization": "8.0.3" "Microsoft.Extensions.Localization": "8.0.6"
} }
}, },
"MudBlazor.Markdown": { "MudBlazor.Markdown": {
@ -45,53 +45,53 @@
}, },
"Microsoft.AspNetCore.Authorization": { "Microsoft.AspNetCore.Authorization": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.3", "resolved": "8.0.6",
"contentHash": "9Nic17acgZbysUlhGc+TEd9F8jI01kC6+V31sC7/xI5v2OSWGL8NhdYaB/Iu4KnDRoQEolg6qvepGsVfeYpIYA==", "contentHash": "H1CSbD7UeSPsrJSUpvbms6SqWMa5y8ch4Rw+gyHh2uztOEb20fTP2r0AUnStn1Q9WYghikiDO5wzkgV+n6KC2Q==",
"dependencies": { "dependencies": {
"Microsoft.AspNetCore.Metadata": "8.0.3", "Microsoft.AspNetCore.Metadata": "8.0.6",
"Microsoft.Extensions.Logging.Abstractions": "8.0.1", "Microsoft.Extensions.Logging.Abstractions": "8.0.1",
"Microsoft.Extensions.Options": "8.0.2" "Microsoft.Extensions.Options": "8.0.2"
} }
}, },
"Microsoft.AspNetCore.Components": { "Microsoft.AspNetCore.Components": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.3", "resolved": "8.0.6",
"contentHash": "q1Da8sfxG+B+BSYpc/3RKNEdzGcLbDTXkTUqekY65kXMMVCTqTAQ0Zs4csmB7FNVTFSjwaw1dGMFD0bQ+erlBw==", "contentHash": "Je2l+rd5i8gB+ZWsN5wBHOsnyAh81h6+a5vNq6rjfQhM2ZYxH+BVsmanCYa+F8BFy6rmd+ZL61SEiNaAyAOgtg==",
"dependencies": { "dependencies": {
"Microsoft.AspNetCore.Authorization": "8.0.3", "Microsoft.AspNetCore.Authorization": "8.0.6",
"Microsoft.AspNetCore.Components.Analyzers": "8.0.3" "Microsoft.AspNetCore.Components.Analyzers": "8.0.6"
} }
}, },
"Microsoft.AspNetCore.Components.Analyzers": { "Microsoft.AspNetCore.Components.Analyzers": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.3", "resolved": "8.0.6",
"contentHash": "iERLuYM+YFI/K1jkinr1YeAkJYHUcijPiPCKgmgs2ZhJLqiIVJRT08vUtIsfhiFtGiI5MIzK0R1BZHyS3yAQng==" "contentHash": "SEL0CN1jJdJkCDwRox3kSY1ffMnahlOCDJZYrYWfQ6ftjqRuuiPtwyvI3VIeVHLcpT3VP1AXww8wzKDK3oeFxg=="
}, },
"Microsoft.AspNetCore.Components.Forms": { "Microsoft.AspNetCore.Components.Forms": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.3", "resolved": "8.0.6",
"contentHash": "OxY5NDmePnn6FMb+Fum57YL7LCHk3u2Wg0qSln3uZSayo+oIxYuoGnqH2dUMp1P5vOPfq17NKCIIEbxfU2dirQ==", "contentHash": "49wIE1ns3ZGDU4NPMcKCSTC716IxujUeaynsUyflM5Qmb2WlF6M6m4pMcJ6UET1Ixmn027nZjMEc8J7pU4BLBg==",
"dependencies": { "dependencies": {
"Microsoft.AspNetCore.Components": "8.0.3" "Microsoft.AspNetCore.Components": "8.0.6"
} }
}, },
"Microsoft.AspNetCore.Components.Web": { "Microsoft.AspNetCore.Components.Web": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.3", "resolved": "8.0.6",
"contentHash": "bHWJiz/JhjptK3iYzha0Rm73chjFcbMAOD9DdDq2tn1rp4rQa/K7O/zdnZpSYAT3nI33Q0aY6ts6t0PUVu5hCA==", "contentHash": "xxYlTpcTEWsxaWUscDLN32mM32ysslLFtNQBS6wJOxaKJ9LCvusXDyBVEKL2DPbB8PZdereNvyrVr0deHkuOEw==",
"dependencies": { "dependencies": {
"Microsoft.AspNetCore.Components": "8.0.3", "Microsoft.AspNetCore.Components": "8.0.6",
"Microsoft.AspNetCore.Components.Forms": "8.0.3", "Microsoft.AspNetCore.Components.Forms": "8.0.6",
"Microsoft.Extensions.DependencyInjection": "8.0.0", "Microsoft.Extensions.DependencyInjection": "8.0.0",
"Microsoft.Extensions.Primitives": "8.0.0", "Microsoft.Extensions.Primitives": "8.0.0",
"Microsoft.JSInterop": "8.0.3", "Microsoft.JSInterop": "8.0.6",
"System.IO.Pipelines": "8.0.0" "System.IO.Pipelines": "8.0.0"
} }
}, },
"Microsoft.AspNetCore.Metadata": { "Microsoft.AspNetCore.Metadata": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.3", "resolved": "8.0.6",
"contentHash": "MAdmICjtSckGDutLRMydRI0pvBcGw/WoC4UC+hZ999idVW96l5iJlhyrtakgYkF5Rp0ekNVNWA+onP2gJZUkpw==" "contentHash": "3e7S/kz1MGds8zDA8SfQiutqifyVcULs5P/8Bxpes0WIkJRMGkU/l+XlMllj9KrDfCGwHW8bgjRy/zxfoILgfg=="
}, },
"Microsoft.Extensions.DependencyInjection": { "Microsoft.Extensions.DependencyInjection": {
"type": "Transitive", "type": "Transitive",
@ -116,19 +116,19 @@
}, },
"Microsoft.Extensions.Localization": { "Microsoft.Extensions.Localization": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.3", "resolved": "8.0.6",
"contentHash": "EjHnIiEwNq9xl8S36hf0nj64IF3DTQ1l5PVK8Vo+QocYKDKpDPONHNJC8env0DPwod7T5oA1HYLLo2mdSTCgrQ==", "contentHash": "EXcSpQE6E80Qutej0ZShz1oRWBFocDzir/R3Gd1jAqZ5SnPpSr1Ep/tH5ha0cRXY22cWVuOb7I9rM32Ew+ju7g==",
"dependencies": { "dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1", "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1",
"Microsoft.Extensions.Localization.Abstractions": "8.0.3", "Microsoft.Extensions.Localization.Abstractions": "8.0.6",
"Microsoft.Extensions.Logging.Abstractions": "8.0.1", "Microsoft.Extensions.Logging.Abstractions": "8.0.1",
"Microsoft.Extensions.Options": "8.0.2" "Microsoft.Extensions.Options": "8.0.2"
} }
}, },
"Microsoft.Extensions.Localization.Abstractions": { "Microsoft.Extensions.Localization.Abstractions": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.3", "resolved": "8.0.6",
"contentHash": "k/kUPm1FQBxcs9/vsM1eF4qIOg2Sovqh/+KUGHur5Mc0Y3OFGuoz9ktBX7LA0gPz53SZhW3W3oaSaMFFcjgM6Q==" "contentHash": "oQdKQ4xlb+Qa4t1gWGj58cocLdWZynP+wLExIAxozh2SrvffEzTvTGI2IbRx4mBNgg9jbbyoPE8nNOwJ1Thddg=="
}, },
"Microsoft.Extensions.Logging.Abstractions": { "Microsoft.Extensions.Logging.Abstractions": {
"type": "Transitive", "type": "Transitive",
@ -154,8 +154,8 @@
}, },
"Microsoft.JSInterop": { "Microsoft.JSInterop": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.3", "resolved": "8.0.6",
"contentHash": "Oi21Fa7KubCzafwXb2IOdSGg24+/ylYGwrJgAYdWmgXBj04Oj/1b8vr9hrcoFKjQ6K18ryHYh35ZO/CCIEhuzg==" "contentHash": "E1djWS3d41fcd++7sGlbYhOHde5Pb0oBpOcNvUbn+1ga/yCvsjzUfbd/tDRg1qacNKS0iwKWYOIqTZxJnh99dQ=="
}, },
"System.IO.Pipelines": { "System.IO.Pipelines": {
"type": "Transitive", "type": "Transitive",
@ -163,6 +163,6 @@
"contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA==" "contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA=="
} }
}, },
"net8.0/osx-x64": {} "net8.0/osx-arm64": {}
} }
} }