mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2025-02-05 14:49:06 +00:00
Migrate to MudBlazor v7.x.x (#41)
This commit is contained in:
parent
a956b55d6b
commit
5250e5d2fb
@ -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">
|
||||||
|
@ -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"/>
|
||||||
|
@ -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>
|
||||||
}
|
}
|
||||||
|
@ -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; } = [];
|
||||||
}
|
}
|
@ -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>
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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";
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
3
app/MindWork AI Studio/Components/Layout/NavBarItem.cs
Normal file
3
app/MindWork AI Studio/Components/Layout/NavBarItem.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace AIStudio.Components.Layout;
|
||||||
|
|
||||||
|
public record NavBarItem(string Name, string Icon, Color IconColor, string Path, bool MatchAll);
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
@ -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
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
using AIStudio.Provider;
|
|
||||||
using AIStudio.Tools;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
namespace AIStudio.Components.Pages.TextSummarizer;
|
namespace AIStudio.Components.Pages.TextSummarizer;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
using AIStudio.Provider;
|
|
||||||
using AIStudio.Tools;
|
using AIStudio.Tools;
|
||||||
|
|
||||||
namespace AIStudio.Components.Pages.Translator;
|
namespace AIStudio.Components.Pages.Translator;
|
||||||
|
@ -7,4 +7,5 @@
|
|||||||
|
|
||||||
<MudThemeProvider />
|
<MudThemeProvider />
|
||||||
<MudDialogProvider />
|
<MudDialogProvider />
|
||||||
|
<MudPopoverProvider />
|
||||||
<MudSnackbarProvider />
|
<MudSnackbarProvider />
|
@ -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>
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
9
app/MindWork AI Studio/Settings/NavBehavior.cs
Normal file
9
app/MindWork AI Studio/Settings/NavBehavior.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace AIStudio.Settings;
|
||||||
|
|
||||||
|
public enum NavBehavior
|
||||||
|
{
|
||||||
|
EXPAND_ON_HOVER,
|
||||||
|
NEVER_EXPAND_USE_TOOLTIPS,
|
||||||
|
NEVER_EXPAND_NO_TOOLTIPS,
|
||||||
|
ALWAYS_EXPAND,
|
||||||
|
}
|
@ -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>
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user