Added more dialogs & components

This commit is contained in:
Thorsten Sommer 2025-04-27 12:27:10 +02:00
parent ae0cb4c363
commit 8896a3c13d
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108
14 changed files with 137 additions and 138 deletions

View File

@ -1,9 +1,9 @@
@using AIStudio.Settings @using AIStudio.Settings
@inherits MSGComponentBase
@if (this.SelectionMode is DataSourceSelectionMode.SELECTION_MODE) @if (this.SelectionMode is DataSourceSelectionMode.SELECTION_MODE)
{ {
<div class="d-flex"> <div class="d-flex">
<MudTooltip Text="Select the data you want to use here." Placement="Placement.Top"> <MudTooltip Text="@T("Select the data you want to use here.")" Placement="Placement.Top">
@if (this.PopoverTriggerMode is PopoverTriggerMode.ICON) @if (this.PopoverTriggerMode is PopoverTriggerMode.ICON)
{ {
<MudIconButton Icon="@Icons.Material.Filled.Source" Class="@this.PopoverButtonClasses" OnClick="@(() => this.ToggleDataSourceSelection())"/> <MudIconButton Icon="@Icons.Material.Filled.Source" Class="@this.PopoverButtonClasses" OnClick="@(() => this.ToggleDataSourceSelection())"/>
@ -11,7 +11,7 @@
else else
{ {
<MudButton Variant="Variant.Filled" StartIcon="@Icons.Material.Filled.Source" Class="@this.PopoverButtonClasses" OnClick="@(() => this.ToggleDataSourceSelection())"> <MudButton Variant="Variant.Filled" StartIcon="@Icons.Material.Filled.Source" Class="@this.PopoverButtonClasses" OnClick="@(() => this.ToggleDataSourceSelection())">
Select data @T("Select data")
</MudButton> </MudButton>
} }
</MudTooltip> </MudTooltip>
@ -22,9 +22,11 @@
<CardHeaderContent> <CardHeaderContent>
<PreviewPrototype/> <PreviewPrototype/>
<MudStack Row="true" AlignItems="AlignItems.Center"> <MudStack Row="true" AlignItems="AlignItems.Center">
<MudText Typo="Typo.h5">Data Source Selection</MudText> <MudText Typo="Typo.h5">
@T("Data Source Selection")
</MudText>
<MudSpacer/> <MudSpacer/>
<MudTooltip Text="Manage your data sources" Placement="Placement.Top"> <MudTooltip Text="@T("Manage your data sources")" Placement="Placement.Top">
<MudIconButton Variant="Variant.Filled" Icon="@Icons.Material.Filled.Settings" OnClick="@this.OpenSettingsDialog"/> <MudIconButton Variant="Variant.Filled" Icon="@Icons.Material.Filled.Settings" OnClick="@this.OpenSettingsDialog"/>
</MudTooltip> </MudTooltip>
</MudStack> </MudStack>
@ -40,57 +42,52 @@
else if (this.SettingsManager.ConfigurationData.DataSources.Count == 0) else if (this.SettingsManager.ConfigurationData.DataSources.Count == 0)
{ {
<MudJustifiedText Typo="Typo.body1" Class="mb-3"> <MudJustifiedText Typo="Typo.body1" Class="mb-3">
You haven't configured any data sources. To grant the AI access to your data, you need to @T("You haven't configured any data sources. To grant the AI access to your data, you need to add such a source. However, if you wish to use data from your device, you first have to set up a so-called embedding. This embedding is necessary so the AI can effectively search your data, find and retrieve the correct information required for each task. In addition to local data, you can also incorporate your company's data. To do so, your company must provide the data through an ERI (External Retrieval Interface).")
add such a source. However, if you wish to use data from your device, you first have to set up
a so-called embedding. This embedding is necessary so the AI can effectively search your data,
find and retrieve the correct information required for each task. In addition to local data,
you can also incorporate your company's data. To do so, your company must provide the data through
an ERI (External Retrieval Interface).
</MudJustifiedText> </MudJustifiedText>
<MudStack StretchItems="StretchItems.None" AlignItems="AlignItems.Start"> <MudStack StretchItems="StretchItems.None" AlignItems="AlignItems.Start">
<MudButton Variant="Variant.Filled" OnClick="this.OpenSettingsDialog" StartIcon="@Icons.Material.Filled.Settings"> <MudButton Variant="Variant.Filled" OnClick="this.OpenSettingsDialog" StartIcon="@Icons.Material.Filled.Settings">
Manage Data Sources @T("Manage Data Sources")
</MudButton> </MudButton>
<MudButton Variant="Variant.Filled" Href="https://mindworkai.org/#eri---external-retrieval-interface" Target="_blank" StartIcon="@Icons.Material.Filled.Settings"> <MudButton Variant="Variant.Filled" Href="https://mindworkai.org/#eri---external-retrieval-interface" Target="_blank" StartIcon="@Icons.Material.Filled.Settings">
Read more about ERI @T("Read more about ERI")
</MudButton> </MudButton>
</MudStack> </MudStack>
} }
else if (this.showDataSourceSelection) else if (this.showDataSourceSelection)
{ {
<MudTextSwitch Label="Are data sources enabled?" Value="@this.areDataSourcesEnabled" LabelOn="Yes, I want to use data sources." LabelOff="No, I don't want to use data sources." ValueChanged="@this.EnabledChanged"/> <MudTextSwitch Label="Are data sources enabled?" Value="@this.areDataSourcesEnabled" LabelOn="@T("Yes, I want to use data sources.")" LabelOff="@T("No, I don't want to use data sources.")" ValueChanged="@this.EnabledChanged"/>
@if (this.areDataSourcesEnabled) @if (this.areDataSourcesEnabled)
{ {
<MudTextSwitch Label="AI-based data source selection" Value="@this.aiBasedSourceSelection" LabelOn="Yes, let the AI decide which data sources are needed." LabelOff="No, I manually decide which data source to use." ValueChanged="@this.AutoModeChanged"/> <MudTextSwitch Label="@T("AI-based data source selection")" Value="@this.aiBasedSourceSelection" LabelOn="@T("Yes, let the AI decide which data sources are needed.")" LabelOff="@T("No, I manually decide which data source to use.")" ValueChanged="@this.AutoModeChanged"/>
@if (this.SettingsManager.ConfigurationData.AgentRetrievalContextValidation.EnableRetrievalContextValidation) @if (this.SettingsManager.ConfigurationData.AgentRetrievalContextValidation.EnableRetrievalContextValidation)
{ {
<MudTextSwitch Label="AI-based data validation" Value="@this.aiBasedValidation" LabelOn="Yes, let the AI validate & filter the retrieved data." LabelOff="No, use all data retrieved from the data sources." ValueChanged="@this.ValidationModeChanged"/> <MudTextSwitch Label="@T("AI-based data validation")" Value="@this.aiBasedValidation" LabelOn="@T("Yes, let the AI validate & filter the retrieved data.")" LabelOff="@T("No, use all data retrieved from the data sources.")" ValueChanged="@this.ValidationModeChanged"/>
} }
@switch (this.aiBasedSourceSelection) @switch (this.aiBasedSourceSelection)
{ {
case true when this.availableDataSources.Count == 0: case true when this.availableDataSources.Count == 0:
<MudText Typo="Typo.body1" Class="mb-3"> <MudText Typo="Typo.body1" Class="mb-3">
Your data sources cannot be used with the LLM provider you selected due to data privacy, or they are currently unavailable. @T("Your data sources cannot be used with the LLM provider you selected due to data privacy, or they are currently unavailable.")
</MudText> </MudText>
break; break;
case true when this.DataSourcesAISelected.Count == 0: case true when this.DataSourcesAISelected.Count == 0:
<MudText Typo="Typo.body1" Class="mb-3"> <MudText Typo="Typo.body1" Class="mb-3">
The AI evaluates each of your inputs to determine whether and which data sources are necessary. Currently, the AI has not selected any source. @T("The AI evaluates each of your inputs to determine whether and which data sources are necessary. Currently, the AI has not selected any source.")
</MudText> </MudText>
break; break;
case false when this.availableDataSources.Count == 0: case false when this.availableDataSources.Count == 0:
<MudText Typo="Typo.body1" Class="mb-3"> <MudText Typo="Typo.body1" Class="mb-3">
Your data sources cannot be used with the LLM provider you selected due to data privacy, or they are currently unavailable. @T("Your data sources cannot be used with the LLM provider you selected due to data privacy, or they are currently unavailable.")
</MudText> </MudText>
break; break;
case false: case false:
<MudField Label="Available Data Sources" Variant="Variant.Outlined" Class="mb-3" Disabled="@this.aiBasedSourceSelection"> <MudField Label="@T("Available Data Sources")" Variant="Variant.Outlined" Class="mb-3" Disabled="@this.aiBasedSourceSelection">
<MudList T="IDataSource" SelectionMode="@this.GetListSelectionMode()" @bind-SelectedValues:get="@this.selectedDataSources" @bind-SelectedValues:set="@(x => this.SelectionChanged(x))" Style="max-height: 14em;"> <MudList T="IDataSource" SelectionMode="@this.GetListSelectionMode()" @bind-SelectedValues:get="@this.selectedDataSources" @bind-SelectedValues:set="@(x => this.SelectionChanged(x))" Style="max-height: 14em;">
@foreach (var source in this.availableDataSources) @foreach (var source in this.availableDataSources)
{ {
@ -104,7 +101,7 @@
case true: case true:
<MudExpansionPanels MultiExpansion="@false" Class="mt-3" Style="max-height: 14em;"> <MudExpansionPanels MultiExpansion="@false" Class="mt-3" Style="max-height: 14em;">
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.TouchApp" HeaderText="Available Data Sources"> <ExpansionPanel HeaderIcon="@Icons.Material.Filled.TouchApp" HeaderText="@T("Available Data Sources")">
<MudList T="IDataSource" SelectionMode="MudBlazor.SelectionMode.SingleSelection" SelectedValues="@this.selectedDataSources" Style="max-height: 14em;"> <MudList T="IDataSource" SelectionMode="MudBlazor.SelectionMode.SingleSelection" SelectedValues="@this.selectedDataSources" Style="max-height: 14em;">
@foreach (var source in this.availableDataSources) @foreach (var source in this.availableDataSources)
{ {
@ -114,7 +111,7 @@
} }
</MudList> </MudList>
</ExpansionPanel> </ExpansionPanel>
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Filter" HeaderText="AI-Selected Data Sources"> <ExpansionPanel HeaderIcon="@Icons.Material.Filled.Filter" HeaderText="@T("AI-Selected Data Sources")">
<MudList T="DataSourceAgentSelected" SelectionMode="MudBlazor.SelectionMode.MultiSelection" ReadOnly="@true" SelectedValues="@this.GetSelectedDataSourcesWithAI()" Style="max-height: 14em;"> <MudList T="DataSourceAgentSelected" SelectionMode="MudBlazor.SelectionMode.MultiSelection" ReadOnly="@true" SelectedValues="@this.GetSelectedDataSourcesWithAI()" Style="max-height: 14em;">
@foreach (var source in this.DataSourcesAISelected) @foreach (var source in this.DataSourcesAISelected)
{ {
@ -141,7 +138,7 @@
</MudCardContent> </MudCardContent>
<MudCardActions> <MudCardActions>
<MudButton Variant="Variant.Filled" OnClick="@(() => this.HideDataSourceSelection())"> <MudButton Variant="Variant.Filled" OnClick="@(() => this.HideDataSourceSelection())">
Close @T("Close")
</MudButton> </MudButton>
</MudCardActions> </MudCardActions>
</MudCard> </MudCard>
@ -152,7 +149,9 @@ else if (this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE)
{ {
<MudPaper Class="pa-3 mb-8 mt-3 border-dashed border rounded-lg"> <MudPaper Class="pa-3 mb-8 mt-3 border-dashed border rounded-lg">
<PreviewPrototype/> <PreviewPrototype/>
<MudText Typo="Typo.h5">Data Source Selection</MudText> <MudText Typo="Typo.h5">
@T("Data Source Selection")
</MudText>
@if (!string.IsNullOrWhiteSpace(this.ConfigurationHeaderMessage)) @if (!string.IsNullOrWhiteSpace(this.ConfigurationHeaderMessage))
{ {
@ -161,12 +160,12 @@ else if (this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE)
</MudText> </MudText>
} }
<MudTextSwitch Label="Are data sources enabled?" Value="@this.areDataSourcesEnabled" LabelOn="Yes, I want to use data sources." LabelOff="No, I don't want to use data sources." ValueChanged="@this.EnabledChanged"/> <MudTextSwitch Label="@T("Are data sources enabled?")" Value="@this.areDataSourcesEnabled" LabelOn="@T("Yes, I want to use data sources.")" LabelOff="@T("No, I don't want to use data sources.")" ValueChanged="@this.EnabledChanged"/>
@if (this.areDataSourcesEnabled) @if (this.areDataSourcesEnabled)
{ {
<MudTextSwitch Label="AI-based data source selection" Value="@this.aiBasedSourceSelection" LabelOn="Yes, let the AI decide which data sources are needed." LabelOff="No, I manually decide which data source to use." ValueChanged="@this.AutoModeChanged"/> <MudTextSwitch Label="@T("AI-based data source selection")" Value="@this.aiBasedSourceSelection" LabelOn="@T("Yes, let the AI decide which data sources are needed.")" LabelOff="@T("No, I manually decide which data source to use.")" ValueChanged="@this.AutoModeChanged"/>
<MudTextSwitch Label="AI-based data validation" Value="@this.aiBasedValidation" LabelOn="Yes, let the AI validate & filter the retrieved data." LabelOff="No, use all data retrieved from the data sources." ValueChanged="@this.ValidationModeChanged"/> <MudTextSwitch Label="@T("AI-based data validation")" Value="@this.aiBasedValidation" LabelOn="@T("Yes, let the AI validate & filter the retrieved data.")" LabelOff="@T("No, use all data retrieved from the data sources.")" ValueChanged="@this.ValidationModeChanged"/>
<MudField Label="Available Data Sources" Variant="Variant.Outlined" Class="mb-3" Disabled="@this.aiBasedSourceSelection"> <MudField Label="@T("Available Data Sources")" Variant="Variant.Outlined" Class="mb-3" Disabled="@this.aiBasedSourceSelection">
<MudList T="IDataSource" SelectionMode="@this.GetListSelectionMode()" @bind-SelectedValues:get="@this.selectedDataSources" @bind-SelectedValues:set="@(x => this.SelectionChanged(x))"> <MudList T="IDataSource" SelectionMode="@this.GetListSelectionMode()" @bind-SelectedValues:get="@this.selectedDataSources" @bind-SelectedValues:set="@(x => this.SelectionChanged(x))">
@foreach (var source in this.availableDataSources) @foreach (var source in this.availableDataSources)
{ {

View File

@ -9,7 +9,7 @@ using DialogOptions = AIStudio.Dialogs.DialogOptions;
namespace AIStudio.Components; namespace AIStudio.Components;
public partial class DataSourceSelection : ComponentBase, IMessageBusReceiver, IDisposable public partial class DataSourceSelection : MSGComponentBase
{ {
[Parameter] [Parameter]
public DataSourceSelectionMode SelectionMode { get; set; } = DataSourceSelectionMode.SELECTION_MODE; public DataSourceSelectionMode SelectionMode { get; set; } = DataSourceSelectionMode.SELECTION_MODE;
@ -38,12 +38,6 @@ public partial class DataSourceSelection : ComponentBase, IMessageBusReceiver, I
[Parameter] [Parameter]
public bool AutoSaveAppSettings { get; set; } public bool AutoSaveAppSettings { get; set; }
[Inject]
private SettingsManager SettingsManager { get; init; } = null!;
[Inject]
private MessageBus MessageBus { get; init; } = null!;
[Inject] [Inject]
private DataSourceService DataSourceService { get; init; } = null!; private DataSourceService DataSourceService { get; init; } = null!;
@ -63,8 +57,7 @@ public partial class DataSourceSelection : ComponentBase, IMessageBusReceiver, I
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
this.MessageBus.RegisterComponent(this); this.ApplyFilters([], [ Event.RAG_AUTO_DATA_SOURCES_SELECTED ]);
this.MessageBus.ApplyFilters(this, [], [ Event.COLOR_THEME_CHANGED, Event.RAG_AUTO_DATA_SOURCES_SELECTED ]);
// //
// Load the settings: // Load the settings:
@ -253,19 +246,12 @@ public partial class DataSourceSelection : ComponentBase, IMessageBusReceiver, I
private void HideDataSourceSelection() => this.showDataSourceSelection = false; private void HideDataSourceSelection() => this.showDataSourceSelection = false;
#region Implementation of IMessageBusReceiver #region Overrides of MSGComponentBase
public string ComponentName => nameof(ConfidenceInfo); protected override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
public Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data)
{ {
switch (triggeredEvent) switch (triggeredEvent)
{ {
case Event.COLOR_THEME_CHANGED:
this.showDataSourceSelection = false;
this.StateHasChanged();
break;
case Event.RAG_AUTO_DATA_SOURCES_SELECTED: case Event.RAG_AUTO_DATA_SOURCES_SELECTED:
if(data is IReadOnlyList<DataSourceAgentSelected> aiSelectedDataSources) if(data is IReadOnlyList<DataSourceAgentSelected> aiSelectedDataSources)
this.DataSourcesAISelected = aiSelectedDataSources; this.DataSourcesAISelected = aiSelectedDataSources;
@ -277,19 +263,5 @@ public partial class DataSourceSelection : ComponentBase, IMessageBusReceiver, I
return Task.CompletedTask; return Task.CompletedTask;
} }
public Task<TResult?> ProcessMessageWithResult<TPayload, TResult>(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data)
{
return Task.FromResult<TResult?>(default);
}
#endregion
#region Implementation of IDisposable
public void Dispose()
{
this.MessageBus.Unregister(this);
}
#endregion #endregion
} }

View File

@ -1,9 +1,16 @@
@inherits MSGComponentBase
<MudDialog> <MudDialog>
<DialogContent> <DialogContent>
<MudText Typo="Typo.body1">@this.Message</MudText> <MudText Typo="Typo.body1">
@this.Message
</MudText>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">No</MudButton> <MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
<MudButton OnClick="@this.Confirm" Variant="Variant.Filled" Color="Color.Error">Yes</MudButton> @T("No")
</MudButton>
<MudButton OnClick="@this.Confirm" Variant="Variant.Filled" Color="Color.Error">
@T("Yes")
</MudButton>
</DialogActions> </DialogActions>
</MudDialog> </MudDialog>

View File

@ -1,3 +1,5 @@
using AIStudio.Components;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
namespace AIStudio.Dialogs; namespace AIStudio.Dialogs;
@ -5,7 +7,7 @@ namespace AIStudio.Dialogs;
/// <summary> /// <summary>
/// A confirmation dialog that can be used to ask the user for confirmation. /// A confirmation dialog that can be used to ask the user for confirmation.
/// </summary> /// </summary>
public partial class ConfirmDialog : ComponentBase public partial class ConfirmDialog : MSGComponentBase
{ {
[CascadingParameter] [CascadingParameter]
private IMudDialogInstance MudDialog { get; set; } = null!; private IMudDialogInstance MudDialog { get; set; } = null!;

View File

@ -1,29 +1,23 @@
@inherits MSGComponentBase
<MudDialog> <MudDialog>
<DialogContent> <DialogContent>
<MudJustifiedText Typo="Typo.body1" Class="mb-3"> <MudJustifiedText Typo="Typo.body1" Class="mb-3">
Store personal data about yourself in various profiles so that the AIs know your personal context. @T("Store personal data about yourself in various profiles so that the AIs know your personal context. This saves you from having to explain your context each time, for example, in every chat. When you have different roles, you can create a profile for each role.")
This saves you from having to explain your context each time, for example, in every chat. When you
have different roles, you can create a profile for each role.
</MudJustifiedText> </MudJustifiedText>
<MudJustifiedText Typo="Typo.body1" Class="mb-3"> <MudJustifiedText Typo="Typo.body1" Class="mb-3">
Are you a project manager in a research facility? You might want to create a profile for your project @T("Are you a project manager in a research facility? You might want to create a profile for your project management activities, one for your scientific work, and a profile for when you need to write program code. In these profiles, you can record how much experience you have or which methods you like or dislike using. Later, you can choose when and where you want to use each profile.")
management activities, one for your scientific work, and a profile for when you need to write program
code. In these profiles, you can record how much experience you have or which methods you like or
dislike using. Later, you can choose when and where you want to use each profile.
</MudJustifiedText> </MudJustifiedText>
<MudJustifiedText Typo="Typo.body1" Class="mb-3"> <MudJustifiedText Typo="Typo.body1" Class="mb-3">
The name of the profile is mandatory. Each profile must have a unique name. Whether you provide @T("The name of the profile is mandatory. Each profile must have a unique name. Whether you provide information about yourself or only fill out the actions is up to you. Only one of these pieces is required.")
information about yourself or only fill out the actions is up to you. Only one of these pieces
is required.
</MudJustifiedText> </MudJustifiedText>
<MudForm @ref="@this.form" @bind-IsValid="@this.dataIsValid" @bind-Errors="@this.dataIssues"> <MudForm @ref="@this.form" @bind-IsValid="@this.dataIsValid" @bind-Errors="@this.dataIssues">
@* ReSharper disable once CSharpWarnings::CS8974 *@ @* ReSharper disable once CSharpWarnings::CS8974 *@
<MudTextField <MudTextField
T="string" T="string"
@bind-Text="@this.DataName" @bind-Text="@this.DataName"
Label="Profile Name" Label="@T("Profile Name")"
Class="mb-3" Class="mb-3"
Immediate="@true" Immediate="@true"
MaxLength="40" MaxLength="40"
@ -43,7 +37,7 @@
AdornmentIcon="@Icons.Material.Filled.ListAlt" AdornmentIcon="@Icons.Material.Filled.ListAlt"
Adornment="Adornment.Start" Adornment="Adornment.Start"
Immediate="@true" Immediate="@true"
Label="What should the AI know about you?" Label="@T("What should the AI know about you?")"
Variant="Variant.Outlined" Variant="Variant.Outlined"
Lines="6" Lines="6"
AutoGrow="@true" AutoGrow="@true"
@ -52,7 +46,7 @@
Counter="444" Counter="444"
Class="mb-3" Class="mb-3"
UserAttributes="@SPELLCHECK_ATTRIBUTES" UserAttributes="@SPELLCHECK_ATTRIBUTES"
HelperText="Tell the AI something about yourself. What is your profession? How experienced are you in this profession? Which technologies do you like?" HelperText="@T("Tell the AI something about yourself. What is your profession? How experienced are you in this profession? Which technologies do you like?")"
/> />
<MudTextField <MudTextField
@ -62,7 +56,7 @@
AdornmentIcon="@Icons.Material.Filled.ListAlt" AdornmentIcon="@Icons.Material.Filled.ListAlt"
Adornment="Adornment.Start" Adornment="Adornment.Start"
Immediate="@true" Immediate="@true"
Label="What should the AI do for you?" Label="@T("What should the AI do for you?")"
Variant="Variant.Outlined" Variant="Variant.Outlined"
Lines="6" Lines="6"
AutoGrow="@true" AutoGrow="@true"
@ -71,22 +65,24 @@
Counter="256" Counter="256"
Class="mb-3" Class="mb-3"
UserAttributes="@SPELLCHECK_ATTRIBUTES" UserAttributes="@SPELLCHECK_ATTRIBUTES"
HelperText="Tell the AI what you want it to do for you. What are your goals or are you trying to achieve? Like having the AI address you informally." HelperText="@T("Tell the AI what you want it to do for you. What are your goals or are you trying to achieve? Like having the AI address you informally.")"
/> />
</MudForm> </MudForm>
<Issues IssuesData="@this.dataIssues"/> <Issues IssuesData="@this.dataIssues"/>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">Cancel</MudButton> <MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
@T("Cancel")
</MudButton>
<MudButton OnClick="@this.Store" Variant="Variant.Filled" Color="Color.Primary"> <MudButton OnClick="@this.Store" Variant="Variant.Filled" Color="Color.Primary">
@if(this.IsEditing) @if(this.IsEditing)
{ {
@:Update @T("Update")
} }
else else
{ {
@:Add @T("Add")
} }
</MudButton> </MudButton>
</DialogActions> </DialogActions>

View File

@ -1,10 +1,11 @@
using AIStudio.Components;
using AIStudio.Settings; using AIStudio.Settings;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
namespace AIStudio.Dialogs; namespace AIStudio.Dialogs;
public partial class ProfileDialog : ComponentBase public partial class ProfileDialog : MSGComponentBase
{ {
[CascadingParameter] [CascadingParameter]
private IMudDialogInstance MudDialog { get; set; } = null!; private IMudDialogInstance MudDialog { get; set; } = null!;
@ -45,9 +46,6 @@ public partial class ProfileDialog : ComponentBase
[Parameter] [Parameter]
public bool IsEditing { get; init; } public bool IsEditing { get; init; }
[Inject]
private SettingsManager SettingsManager { get; init; } = null!;
[Inject] [Inject]
private ILogger<ProviderDialog> Logger { get; init; } = null!; private ILogger<ProviderDialog> Logger { get; init; } = null!;
@ -129,10 +127,10 @@ public partial class ProfileDialog : ComponentBase
private string? ValidateNeedToKnow(string text) private string? ValidateNeedToKnow(string text)
{ {
if (string.IsNullOrWhiteSpace(this.DataNeedToKnow) && string.IsNullOrWhiteSpace(this.DataActions)) if (string.IsNullOrWhiteSpace(this.DataNeedToKnow) && string.IsNullOrWhiteSpace(this.DataActions))
return "Please enter what the LLM should know about you and/or what actions it should take."; return T("Please enter what the LLM should know about you and/or what actions it should take.");
if(text.Length > 444) if(text.Length > 444)
return "The text must not exceed 444 characters."; return T("The text must not exceed 444 characters.");
return null; return null;
} }
@ -140,10 +138,10 @@ public partial class ProfileDialog : ComponentBase
private string? ValidateActions(string text) private string? ValidateActions(string text)
{ {
if (string.IsNullOrWhiteSpace(this.DataNeedToKnow) && string.IsNullOrWhiteSpace(this.DataActions)) if (string.IsNullOrWhiteSpace(this.DataNeedToKnow) && string.IsNullOrWhiteSpace(this.DataActions))
return "Please enter what the LLM should know about you and/or what actions it should take."; return T("Please enter what the LLM should know about you and/or what actions it should take.");
if(text.Length > 256) if(text.Length > 256)
return "The text must not exceed 256 characters."; return T("The text must not exceed 256 characters.");
return null; return null;
} }
@ -151,15 +149,15 @@ public partial class ProfileDialog : ComponentBase
private string? ValidateName(string name) private string? ValidateName(string name)
{ {
if (string.IsNullOrWhiteSpace(name)) if (string.IsNullOrWhiteSpace(name))
return "Please enter a profile name."; return T("Please enter a profile name.");
if (name.Length > 40) if (name.Length > 40)
return "The profile name must not exceed 40 characters."; return T("The profile name must not exceed 40 characters.");
// The instance name must be unique: // The instance name must be unique:
var lowerName = name.ToLowerInvariant(); var lowerName = name.ToLowerInvariant();
if (lowerName != this.dataEditingPreviousName && this.UsedNames.Contains(lowerName)) if (lowerName != this.dataEditingPreviousName && this.UsedNames.Contains(lowerName))
return "The profile name must be unique; the chosen name is already in use."; return T("The profile name must be unique; the chosen name is already in use.");
return null; return null;
} }

View File

@ -1,13 +1,13 @@
@using AIStudio.Provider @using AIStudio.Provider
@using AIStudio.Provider.HuggingFace @using AIStudio.Provider.HuggingFace
@using AIStudio.Provider.SelfHosted @using AIStudio.Provider.SelfHosted
@inherits MSGComponentBase
<MudDialog> <MudDialog>
<DialogContent> <DialogContent>
<MudForm @ref="@this.form" @bind-IsValid="@this.dataIsValid" @bind-Errors="@this.dataIssues"> <MudForm @ref="@this.form" @bind-IsValid="@this.dataIsValid" @bind-Errors="@this.dataIssues">
<MudStack Row="@true" AlignItems="AlignItems.Center"> <MudStack Row="@true" AlignItems="AlignItems.Center">
@* ReSharper disable once CSharpWarnings::CS8974 *@ @* ReSharper disable once CSharpWarnings::CS8974 *@
<MudSelect @bind-Value="@this.DataLLMProvider" Label="Provider" Class="mb-3" OpenIcon="@Icons.Material.Filled.AccountBalance" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.providerValidation.ValidatingProvider"> <MudSelect @bind-Value="@this.DataLLMProvider" Label="@T("Provider")" Class="mb-3" OpenIcon="@Icons.Material.Filled.AccountBalance" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.providerValidation.ValidatingProvider">
@foreach (LLMProviders provider in Enum.GetValues(typeof(LLMProviders))) @foreach (LLMProviders provider in Enum.GetValues(typeof(LLMProviders)))
{ {
<MudSelectItem Value="@provider"> <MudSelectItem Value="@provider">
@ -15,7 +15,9 @@
</MudSelectItem> </MudSelectItem>
} }
</MudSelect> </MudSelect>
<MudButton Disabled="@(!this.DataLLMProvider.ShowRegisterButton())" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.OpenInBrowser" Href="@this.DataLLMProvider.GetCreationURL()" Target="_blank">Create account</MudButton> <MudButton Disabled="@(!this.DataLLMProvider.ShowRegisterButton())" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.OpenInBrowser" Href="@this.DataLLMProvider.GetCreationURL()" Target="_blank">
@T("Create account")
</MudButton>
</MudStack> </MudStack>
@if (this.DataLLMProvider.IsAPIKeyNeeded(this.DataHost)) @if (this.DataLLMProvider.IsAPIKeyNeeded(this.DataHost))
@ -39,7 +41,7 @@
<MudTextField <MudTextField
T="string" T="string"
@bind-Text="@this.DataHostname" @bind-Text="@this.DataHostname"
Label="Hostname" Label="@T("Hostname")"
Class="mb-3" Class="mb-3"
Adornment="Adornment.Start" Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Dns" AdornmentIcon="@Icons.Material.Filled.Dns"
@ -50,7 +52,7 @@
@if (this.DataLLMProvider.IsHostNeeded()) @if (this.DataLLMProvider.IsHostNeeded())
{ {
<MudSelect @bind-Value="@this.DataHost" Label="Host" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.providerValidation.ValidatingHost"> <MudSelect @bind-Value="@this.DataHost" Label="@T("Host")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.providerValidation.ValidatingHost">
@foreach (Host host in Enum.GetValues(typeof(Host))) @foreach (Host host in Enum.GetValues(typeof(Host)))
{ {
<MudSelectItem Value="@host"> <MudSelectItem Value="@host">
@ -62,7 +64,7 @@
@if (this.DataLLMProvider.IsHFInstanceProviderNeeded()) @if (this.DataLLMProvider.IsHFInstanceProviderNeeded())
{ {
<MudSelect @bind-Value="@this.HFInferenceProviderId" Label="Hugging Face Inference Provider" Class="mb-3" OpenIcon="@Icons.Material.Filled.Dns" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.providerValidation.ValidatingHFInstanceProvider"> <MudSelect @bind-Value="@this.HFInferenceProviderId" Label="@T("Hugging Face Inference Provider")" Class="mb-3" OpenIcon="@Icons.Material.Filled.Dns" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.providerValidation.ValidatingHFInstanceProvider">
@foreach (HFInferenceProvider inferenceProvider in Enum.GetValues(typeof(HFInferenceProvider))) @foreach (HFInferenceProvider inferenceProvider in Enum.GetValues(typeof(HFInferenceProvider)))
{ {
<MudSelectItem Value="@inferenceProvider"> <MudSelectItem Value="@inferenceProvider">
@ -71,7 +73,9 @@
} }
</MudSelect> </MudSelect>
@* ReSharper disable Asp.Entity *@ @* ReSharper disable Asp.Entity *@
<MudJustifiedText Class="mb-3"> Please double-check if your model name matches the curl specifications provided by the inference provider. If it doesn't, you might get a <b>Not Found</b> error when trying to use the model. Here's a <MudLink Href="https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct?inference_api=true&inference_provider=novita&language=sh" Target="_blank">curl example</MudLink>.</MudJustifiedText> <MudJustifiedText Class="mb-3">
Please double-check if your model name matches the curl specifications provided by the inference provider. If it doesn't, you might get a <b>Not Found</b> error when trying to use the model. Here's a <MudLink Href="https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct?inference_api=true&inference_provider=novita&language=sh" Target="_blank">curl example</MudLink>.
</MudJustifiedText>
@* ReSharper restore Asp.Entity *@ @* ReSharper restore Asp.Entity *@
} }
@ -80,12 +84,12 @@
@if (this.DataLLMProvider.IsLLMModelProvidedManually()) @if (this.DataLLMProvider.IsLLMModelProvidedManually())
{ {
<MudButton Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.OpenInBrowser" Href="@this.DataLLMProvider.GetModelsOverviewURL(this.HFInferenceProviderId)" Target="_blank"> <MudButton Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.OpenInBrowser" Href="@this.DataLLMProvider.GetModelsOverviewURL(this.HFInferenceProviderId)" Target="_blank">
Show available models @T("Show available models")
</MudButton> </MudButton>
<MudTextField <MudTextField
T="string" T="string"
@bind-Text="@this.dataManuallyModel" @bind-Text="@this.dataManuallyModel"
Label="Model" Label="@T("Model")"
Adornment="Adornment.Start" Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.FaceRetouchingNatural" AdornmentIcon="@Icons.Material.Filled.FaceRetouchingNatural"
AdornmentColor="Color.Info" AdornmentColor="Color.Info"
@ -96,12 +100,12 @@
else else
{ {
<MudButton Disabled="@(!this.DataLLMProvider.CanLoadModels(this.DataHost, this.dataAPIKey))" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Refresh" OnClick="this.ReloadModels"> <MudButton Disabled="@(!this.DataLLMProvider.CanLoadModels(this.DataHost, this.dataAPIKey))" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Refresh" OnClick="this.ReloadModels">
Load models @T("Load models")
</MudButton> </MudButton>
@if(this.availableModels.Count is 0) @if(this.availableModels.Count is 0)
{ {
<MudText Typo="Typo.body1"> <MudText Typo="Typo.body1">
No models loaded or available. @T("No models loaded or available.")
</MudText> </MudText>
} }
else else
@ -111,7 +115,9 @@
Adornment="Adornment.Start" Validation="@this.providerValidation.ValidatingModel"> Adornment="Adornment.Start" Validation="@this.providerValidation.ValidatingModel">
@foreach (var model in this.availableModels) @foreach (var model in this.availableModels)
{ {
<MudSelectItem Value="@model">@model</MudSelectItem> <MudSelectItem Value="@model">
@model
</MudSelectItem>
} }
</MudSelect> </MudSelect>
} }
@ -123,7 +129,7 @@
<MudTextField <MudTextField
T="string" T="string"
@bind-Text="@this.DataInstanceName" @bind-Text="@this.DataInstanceName"
Label="Instance Name" Label="@T("Instance Name")"
Class="mb-3" Class="mb-3"
MaxLength="40" MaxLength="40"
Counter="40" Counter="40"
@ -139,15 +145,17 @@
<Issues IssuesData="@this.dataIssues"/> <Issues IssuesData="@this.dataIssues"/>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">Cancel</MudButton> <MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
@T("Cancel")
</MudButton>
<MudButton OnClick="@this.Store" Variant="Variant.Filled" Color="Color.Primary"> <MudButton OnClick="@this.Store" Variant="Variant.Filled" Color="Color.Primary">
@if(this.IsEditing) @if(this.IsEditing)
{ {
@:Update @T("Update")
} }
else else
{ {
@:Add @T("Add")
} }
</MudButton> </MudButton>
</DialogActions> </DialogActions>

View File

@ -1,6 +1,6 @@
using AIStudio.Components;
using AIStudio.Provider; using AIStudio.Provider;
using AIStudio.Provider.HuggingFace; using AIStudio.Provider.HuggingFace;
using AIStudio.Settings;
using AIStudio.Tools.Services; using AIStudio.Tools.Services;
using AIStudio.Tools.Validation; using AIStudio.Tools.Validation;
@ -13,7 +13,7 @@ namespace AIStudio.Dialogs;
/// <summary> /// <summary>
/// The provider settings dialog. /// The provider settings dialog.
/// </summary> /// </summary>
public partial class ProviderDialog : ComponentBase, ISecretId public partial class ProviderDialog : MSGComponentBase, ISecretId
{ {
[CascadingParameter] [CascadingParameter]
private IMudDialogInstance MudDialog { get; set; } = null!; private IMudDialogInstance MudDialog { get; set; } = null!;
@ -78,9 +78,6 @@ public partial class ProviderDialog : ComponentBase, ISecretId
[Parameter] [Parameter]
public bool IsEditing { get; init; } public bool IsEditing { get; init; }
[Inject]
private SettingsManager SettingsManager { get; init; } = null!;
[Inject] [Inject]
private ILogger<ProviderDialog> Logger { get; init; } = null!; private ILogger<ProviderDialog> Logger { get; init; } = null!;
@ -182,7 +179,7 @@ public partial class ProviderDialog : ComponentBase, ISecretId
this.dataAPIKey = string.Empty; this.dataAPIKey = string.Empty;
if (this.DataLLMProvider is not LLMProviders.SELF_HOSTED) if (this.DataLLMProvider is not LLMProviders.SELF_HOSTED)
{ {
this.dataAPIKeyStorageIssue = $"Failed to load the API key from the operating system. The message was: {requestedSecret.Issue}. You might ignore this message and provide the API key again."; this.dataAPIKeyStorageIssue = string.Format(T("Failed to load the API key from the operating system. The message was: {0}. You might ignore this message and provide the API key again."), requestedSecret.Issue);
await this.form.Validate(); await this.form.Validate();
} }
} }
@ -232,7 +229,7 @@ public partial class ProviderDialog : ComponentBase, ISecretId
var storeResponse = await this.RustService.SetAPIKey(this, this.dataAPIKey); var storeResponse = await this.RustService.SetAPIKey(this, this.dataAPIKey);
if (!storeResponse.Success) if (!storeResponse.Success)
{ {
this.dataAPIKeyStorageIssue = $"Failed to store the API key in the operating system. The message was: {storeResponse.Issue}. Please try again."; this.dataAPIKeyStorageIssue = string.Format(T("Failed to store the API key in the operating system. The message was: {0}. Please try again."), storeResponse.Issue);
await this.form.Validate(); await this.form.Validate();
return; return;
} }
@ -244,7 +241,7 @@ public partial class ProviderDialog : ComponentBase, ISecretId
private string? ValidateManuallyModel(string manuallyModel) private string? ValidateManuallyModel(string manuallyModel)
{ {
if ((this.DataLLMProvider is LLMProviders.FIREWORKS or LLMProviders.HUGGINGFACE) && string.IsNullOrWhiteSpace(manuallyModel)) if ((this.DataLLMProvider is LLMProviders.FIREWORKS or LLMProviders.HUGGINGFACE) && string.IsNullOrWhiteSpace(manuallyModel))
return "Please enter a model name."; return T("Please enter a model name.");
return null; return null;
} }
@ -269,7 +266,7 @@ public partial class ProviderDialog : ComponentBase, ISecretId
private string APIKeyText => this.DataLLMProvider switch private string APIKeyText => this.DataLLMProvider switch
{ {
LLMProviders.SELF_HOSTED => "(Optional) API Key", LLMProviders.SELF_HOSTED => T("(Optional) API Key"),
_ => "API Key", _ => T("API Key"),
}; };
} }

View File

@ -1,10 +1,17 @@
@inherits MSGComponentBase
<MudDialog> <MudDialog>
<DialogContent> <DialogContent>
<MudText Typo="Typo.body1">@this.Message</MudText> <MudText Typo="Typo.body1">
<MudTextField T="string" @bind-Text="@this.UserInput" Variant="Variant.Outlined" AutoGrow="@false" Lines="1" Label="Chat name" AutoFocus="@true" UserAttributes="@USER_INPUT_ATTRIBUTES"/> @this.Message
</MudText>
<MudTextField T="string" @bind-Text="@this.UserInput" Variant="Variant.Outlined" AutoGrow="@false" Lines="1" Label="@T("Chat name")" AutoFocus="@true" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">Cancel</MudButton> <MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
<MudButton OnClick="@this.Confirm" Variant="Variant.Filled" Color="@this.ConfirmColor">@this.ConfirmText</MudButton> @T("Cancel")
</MudButton>
<MudButton OnClick="@this.Confirm" Variant="Variant.Filled" Color="@this.ConfirmColor">
@this.ConfirmText
</MudButton>
</DialogActions> </DialogActions>
</MudDialog> </MudDialog>

View File

@ -1,10 +1,10 @@
using AIStudio.Settings; using AIStudio.Components;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
namespace AIStudio.Dialogs; namespace AIStudio.Dialogs;
public partial class SingleInputDialog : ComponentBase public partial class SingleInputDialog : MSGComponentBase
{ {
[CascadingParameter] [CascadingParameter]
private IMudDialogInstance MudDialog { get; set; } = null!; private IMudDialogInstance MudDialog { get; set; } = null!;
@ -21,9 +21,6 @@ public partial class SingleInputDialog : ComponentBase
[Parameter] [Parameter]
public Color ConfirmColor { get; set; } = Color.Error; public Color ConfirmColor { get; set; } = Color.Error;
[Inject]
private SettingsManager SettingsManager { get; set; } = null!;
private static readonly Dictionary<string, object?> USER_INPUT_ATTRIBUTES = new(); private static readonly Dictionary<string, object?> USER_INPUT_ATTRIBUTES = new();
#region Overrides of ComponentBase #region Overrides of ComponentBase

View File

@ -1,13 +1,18 @@
@inherits MSGComponentBase
<MudDialog> <MudDialog>
<DialogContent> <DialogContent>
<MudText Typo="Typo.h4" Class="d-inline-flex align-center"> <MudText Typo="Typo.h4" Class="d-inline-flex align-center">
<MudIcon Icon="@Icons.Material.Filled.Update" Size="Size.Large" Class="mr-3"/> <MudIcon Icon="@Icons.Material.Filled.Update" Size="Size.Large" Class="mr-3"/>
Update from v@(META_DATA.Version) to v@(this.UpdateResponse.NewVersion) @this.HeaderText
</MudText> </MudText>
<MudMarkdown Value="@this.UpdateResponse.Changelog" OverrideHeaderTypo="@Markdown.OverrideHeaderTypo"/> <MudMarkdown Value="@this.UpdateResponse.Changelog" OverrideHeaderTypo="@Markdown.OverrideHeaderTypo"/>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">Install later</MudButton> <MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
<MudButton OnClick="@this.Confirm" Variant="Variant.Filled" Color="Color.Info">Install now</MudButton> @T("Install later")
</MudButton>
<MudButton OnClick="@this.Confirm" Variant="Variant.Filled" Color="Color.Info">
@T("Install now")
</MudButton>
</DialogActions> </DialogActions>
</MudDialog> </MudDialog>

View File

@ -1,5 +1,6 @@
using System.Reflection; using System.Reflection;
using AIStudio.Components;
using AIStudio.Tools.Metadata; using AIStudio.Tools.Metadata;
using AIStudio.Tools.Rust; using AIStudio.Tools.Rust;
@ -10,7 +11,7 @@ namespace AIStudio.Dialogs;
/// <summary> /// <summary>
/// The update dialog that is used to inform the user about an available update. /// The update dialog that is used to inform the user about an available update.
/// </summary> /// </summary>
public partial class UpdateDialog : ComponentBase public partial class UpdateDialog : MSGComponentBase
{ {
private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly(); private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly();
private static readonly MetaDataAttribute META_DATA = ASSEMBLY.GetCustomAttribute<MetaDataAttribute>()!; private static readonly MetaDataAttribute META_DATA = ASSEMBLY.GetCustomAttribute<MetaDataAttribute>()!;
@ -21,6 +22,8 @@ public partial class UpdateDialog : ComponentBase
[Parameter] [Parameter]
public UpdateResponse UpdateResponse { get; set; } public UpdateResponse UpdateResponse { get; set; }
private string HeaderText => string.Format(T("Update from v{0} to v{1}"), META_DATA.Version, this.UpdateResponse.NewVersion);
private void Cancel() => this.MudDialog.Cancel(); private void Cancel() => this.MudDialog.Cancel();
private void Confirm() => this.MudDialog.Close(DialogResult.Ok(true)); private void Confirm() => this.MudDialog.Close(DialogResult.Ok(true));

View File

@ -1,6 +1,9 @@
@inherits MSGComponentBase
<MudDialog> <MudDialog>
<DialogContent> <DialogContent>
<MudText Typo="Typo.body1">@this.Message</MudText> <MudText Typo="Typo.body1">
@this.Message
</MudText>
<MudList T="Guid" @bind-SelectedValue="@this.selectedWorkspace"> <MudList T="Guid" @bind-SelectedValue="@this.selectedWorkspace">
@foreach (var (workspaceName, workspaceId) in this.workspaces) @foreach (var (workspaceName, workspaceId) in this.workspaces)
{ {
@ -9,7 +12,11 @@
</MudList> </MudList>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<MudButton OnClick="@this.Cancel" Variant="Variant.Filled">Cancel</MudButton> <MudButton OnClick="@this.Cancel" Variant="Variant.Filled">
<MudButton OnClick="@this.Confirm" Variant="Variant.Filled" Color="Color.Info">@this.ConfirmText</MudButton> @T("Cancel")
</MudButton>
<MudButton OnClick="@this.Confirm" Variant="Variant.Filled" Color="Color.Info">
@this.ConfirmText
</MudButton>
</DialogActions> </DialogActions>
</MudDialog> </MudDialog>

View File

@ -1,12 +1,13 @@
using System.Text; using System.Text;
using AIStudio.Components;
using AIStudio.Settings; using AIStudio.Settings;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
namespace AIStudio.Dialogs; namespace AIStudio.Dialogs;
public partial class WorkspaceSelectionDialog : ComponentBase public partial class WorkspaceSelectionDialog : MSGComponentBase
{ {
[CascadingParameter] [CascadingParameter]
private IMudDialogInstance MudDialog { get; set; } = null!; private IMudDialogInstance MudDialog { get; set; } = null!;