This commit is contained in:
Peer Schütt 2025-07-22 05:55:26 +00:00 committed by GitHub
commit 8bf3556ecb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 264 additions and 91 deletions

View File

@ -6,10 +6,10 @@
<MudStack Row="true" AlignItems="AlignItems.Center" Class="mb-2 mr-3" StretchItems="StretchItems.Start">
<MudText Typo="Typo.h3">
@(this.Title)
@this.Title
</MudText>
<MudIconButton Variant="Variant.Text" Icon="@Icons.Material.Filled.Settings" OnClick="() => this.OpenSettingsDialog()"/>
<MudIconButton Variant="Variant.Text" Icon="@Icons.Material.Filled.Settings" OnClick="@(async () => await this.OpenSettingsDialog())"/>
</MudStack>
<InnerScrolling>
@ -26,13 +26,13 @@
</CascadingValue>
<MudStack Row="true" AlignItems="AlignItems.Center" StretchItems="StretchItems.Start" Class="mb-3">
<MudButton Disabled="@this.SubmitDisabled" Variant="Variant.Filled" OnClick="async () => await this.Start()" Style="@this.SubmitButtonStyle">
<MudButton Disabled="@this.SubmitDisabled" Variant="Variant.Filled" OnClick="@(async () => await this.Start())" Style="@this.SubmitButtonStyle">
@this.SubmitText
</MudButton>
@if (this.isProcessing && this.cancellationTokenSource is not null)
{
<MudTooltip Text="@TB("Stop generation")">
<MudIconButton Variant="Variant.Filled" Icon="@Icons.Material.Filled.Stop" Color="Color.Error" OnClick="() => this.CancelStreaming()"/>
<MudIconButton Variant="Variant.Filled" Icon="@Icons.Material.Filled.Stop" Color="Color.Error" OnClick="@(async () => await this.CancelStreaming())"/>
</MudTooltip>
}
</MudStack>
@ -80,7 +80,7 @@
<MudMenu AnchorOrigin="Origin.TopLeft" TransformOrigin="Origin.BottomLeft" StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="@TB("Send to ...")" Variant="Variant.Filled" Style="@this.GetSendToColor()" Class="rounded">
@foreach (var assistant in Enum.GetValues<Components>().Where(n => n.AllowSendTo()).OrderBy(n => n.Name().Length))
{
<MudMenuItem OnClick="() => this.SendToAssistant(assistant, new())">
<MudMenuItem OnClick="@(async () => await this.SendToAssistant(assistant, new()))">
@assistant.Name()
</MudMenuItem>
}
@ -94,14 +94,14 @@
{
case ButtonData buttonData when !string.IsNullOrWhiteSpace(buttonData.Tooltip):
<MudTooltip Text="@buttonData.Tooltip">
<MudButton Variant="Variant.Filled" Color="@buttonData.Color" Disabled="@buttonData.DisabledAction()" StartIcon="@GetButtonIcon(buttonData.Icon)" OnClick="async () => await buttonData.AsyncAction()">
<MudButton Variant="Variant.Filled" Color="@buttonData.Color" Disabled="@buttonData.DisabledAction()" StartIcon="@GetButtonIcon(buttonData.Icon)" OnClick="@(async () => await buttonData.AsyncAction())">
@buttonData.Text
</MudButton>
</MudTooltip>
break;
case ButtonData buttonData:
<MudButton Variant="Variant.Filled" Color="@buttonData.Color" Disabled="@buttonData.DisabledAction()" StartIcon="@GetButtonIcon(buttonData.Icon)" OnClick="async () => await buttonData.AsyncAction()">
<MudButton Variant="Variant.Filled" Color="@buttonData.Color" Disabled="@buttonData.DisabledAction()" StartIcon="@GetButtonIcon(buttonData.Icon)" OnClick="@(async () => await buttonData.AsyncAction())">
@buttonData.Text
</MudButton>
break;
@ -110,7 +110,7 @@
<MudMenu AnchorOrigin="Origin.TopLeft" TransformOrigin="Origin.BottomLeft" StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="@TB("Send to ...")" Variant="Variant.Filled" Style="@this.GetSendToColor()" Class="rounded">
@foreach (var assistant in Enum.GetValues<Components>().Where(n => n.AllowSendTo()).OrderBy(n => n.Name().Length))
{
<MudMenuItem OnClick="() => this.SendToAssistant(assistant, sendToButton)">
<MudMenuItem OnClick="@(async () => await this.SendToAssistant(assistant, sendToButton))">
@assistant.Name()
</MudMenuItem>
}
@ -121,14 +121,14 @@
@if (this.ShowCopyResult)
{
<MudButton Variant="Variant.Filled" StartIcon="@Icons.Material.Filled.ContentCopy" OnClick="() => this.CopyToClipboard()">
<MudButton Variant="Variant.Filled" StartIcon="@Icons.Material.Filled.ContentCopy" OnClick="@(async () => await this.CopyToClipboard())">
@TB("Copy result")
</MudButton>
}
@if (this.ShowReset)
{
<MudButton Variant="Variant.Filled" Style="@this.GetResetColor()" StartIcon="@Icons.Material.Filled.Refresh" OnClick="() => this.InnerResetForm()">
<MudButton Variant="Variant.Filled" Style="@this.GetResetColor()" StartIcon="@Icons.Material.Filled.Refresh" OnClick="@(async () => await this.InnerResetForm())">
@TB("Reset")
</MudButton>
}

View File

@ -1450,6 +1450,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIDENCEINFO::T3243388657"] = "Confiden
-- Shows and hides the confidence card with information about the selected LLM provider.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIDENCEINFO::T847071819"] = "Shows and hides the confidence card with information about the selected LLM provider."
-- This feature is managed by your organization and has therefore been disabled.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONBASE::T1416426626"] = "This feature is managed by your organization and has therefore been disabled."
-- Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMINCONFIDENCESELECTION::T2526727283"] = "Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level."

View File

@ -1 +1,23 @@
@inherits MSGComponentBase
@inherits MSGComponentBase
@if (this.Body is not null)
{
@if (!this.Disabled() && this.IsLocked())
{
<MudField Label="@this.Label" Variant="@this.Variant" Underline="false" HelperText="@this.OptionHelp" Class="@this.Classes" InnerPadding="false">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.FlexStart" Wrap="Wrap.NoWrap" StretchItems="this.StretchItems">
@* MudTooltip.RootStyle is set as a workaround for issue -> https://github.com/MudBlazor/MudBlazor/issues/10882 *@
<MudTooltip Text="@TB("This feature is managed by your organization and has therefore been disabled.")" Arrow="true" Placement="Placement.Right" RootStyle="display:inline-flex;">
<MudIcon Icon="@Icons.Material.Filled.Lock" Color="Color.Error" Size="Size.Small" Class="mr-1"/>
</MudTooltip>
@this.Body
</MudStack>
</MudField>
}
else
{
<MudField Label="@this.Label" Variant="@this.Variant" Underline="false" HelperText="@this.OptionHelp" Class="@this.Classes" InnerPadding="false">
@this.Body
</MudField>
}
}

View File

@ -5,7 +5,7 @@ namespace AIStudio.Components;
/// <summary>
/// A base class for configuration options.
/// </summary>
public partial class ConfigurationBase : MSGComponentBase
public abstract partial class ConfigurationBase : MSGComponentBase
{
/// <summary>
/// The description of the option, i.e., the name. Should be
@ -26,7 +26,42 @@ public partial class ConfigurationBase : MSGComponentBase
[Parameter]
public Func<bool> Disabled { get; set; } = () => false;
protected const string MARGIN_CLASS = "mb-6";
/// <summary>
/// Is the option locked by a configuration plugin?
/// </summary>
[Parameter]
public Func<bool> IsLocked { get; set; } = () => false;
/// <summary>
/// Should the option be stretched to fill the available space?
/// </summary>
protected abstract bool Stretch { get; }
/// <summary>
/// The CSS class to apply to the component.
/// </summary>
protected virtual string GetClassForBase => string.Empty;
/// <summary>
/// The visual variant of the option.
/// </summary>
protected virtual Variant Variant => Variant.Text;
/// <summary>
/// The label to display for the option.
/// </summary>
protected virtual string Label => string.Empty;
private StretchItems StretchItems => this.Stretch ? StretchItems.End : StretchItems.None;
protected bool IsDisabled => this.Disabled() || this.IsLocked();
private string Classes => $"{this.GetClassForBase} {MARGIN_CLASS}";
private protected virtual RenderFragment? Body => null;
private const string MARGIN_CLASS = "mb-6";
protected static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new();
#region Overrides of ComponentBase
@ -39,7 +74,9 @@ public partial class ConfigurationBase : MSGComponentBase
}
#endregion
private string TB(string fallbackEN) => this.T(fallbackEN, typeof(ConfigurationBase).Namespace, nameof(ConfigurationBase));
protected async Task InformAboutChange() => await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
#region Overrides of MSGComponentBase

View File

@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
namespace AIStudio.Components;
public abstract class ConfigurationBaseCore : ConfigurationBase
{
private protected sealed override RenderFragment Body => this.BuildRenderTree;
// Allow content to be provided by a .razor file but without
// overriding the content of the base class
protected new virtual void BuildRenderTree(RenderTreeBuilder builder)
{
}
}

View File

@ -1,3 +1,3 @@
@using AIStudio.Settings
@inherits MSGComponentBase
<ConfigurationSelect Disabled="@this.Disabled" OptionDescription="@T("Select a minimum confidence level")" SelectedValue="@this.FilteredSelectedValue" Data="@ConfigurationSelectDataFactory.GetConfidenceLevelsData(this.SettingsManager, this.RestrictToGlobalMinimumConfidence)" SelectionUpdate="@this.SelectionUpdate" OptionHelp="@T("Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level.")"/>
<ConfigurationSelect IsLocked="this.IsLocked" Disabled="this.Disabled" OptionDescription="@T("Select a minimum confidence level")" SelectedValue="@this.FilteredSelectedValue" Data="@ConfigurationSelectDataFactory.GetConfidenceLevelsData(this.SettingsManager, this.RestrictToGlobalMinimumConfidence)" SelectionUpdate="@this.SelectionUpdate" OptionHelp="@T("Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level.")"/>

View File

@ -18,17 +18,17 @@ public partial class ConfigurationMinConfidenceSelection : MSGComponentBase
[Parameter]
public Action<ConfidenceLevel> SelectionUpdate { get; set; } = _ => { };
/// <summary>
/// Is the selection component disabled?
/// </summary>
[Parameter]
public Func<bool> Disabled { get; set; } = () => false;
/// <summary>
/// Boolean value indicating whether the selection is restricted to a global minimum confidence level.
/// </summary>
[Parameter]
public bool RestrictToGlobalMinimumConfidence { get; set; }
[Parameter]
public Func<bool> Disabled { get; set; } = () => false;
[Parameter]
public Func<bool> IsLocked { get; set; } = () => false;
private ConfidenceLevel FilteredSelectedValue()
{

View File

@ -1,4 +1,4 @@
@inherits ConfigurationBase
@inherits ConfigurationBaseCore
@typeparam TData
<MudSelectExtended
@ -7,12 +7,10 @@
MultiSelectionTextFunc="@this.GetMultiSelectionText"
SelectedValues="@this.SelectedValues()"
Strict="@true"
Disabled="@this.Disabled()"
Disabled="@this.IsDisabled"
Margin="Margin.Dense"
Label="@this.OptionDescription"
Class="@GetClass"
Variant="Variant.Outlined"
HelperText="@this.OptionHelp"
Class="rounded-lg"
Underline="false"
SelectedValuesChanged="@this.OptionChanged">
@foreach (var data in this.Data)
{

View File

@ -8,7 +8,7 @@ namespace AIStudio.Components;
/// Configuration component for selecting many values from a list.
/// </summary>
/// <typeparam name="TData">The type of the value to select.</typeparam>
public partial class ConfigurationMultiSelect<TData> : ConfigurationBase
public partial class ConfigurationMultiSelect<TData> : ConfigurationBaseCore
{
/// <summary>
/// The data to select from.
@ -28,6 +28,17 @@ public partial class ConfigurationMultiSelect<TData> : ConfigurationBase
[Parameter]
public Action<HashSet<TData>> SelectionUpdate { get; set; } = _ => { };
#region Overrides of ConfigurationBase
/// <inheritdoc />
protected override bool Stretch => true;
protected override Variant Variant => Variant.Outlined;
protected override string Label => this.OptionDescription;
#endregion
private async Task OptionChanged(IEnumerable<TData?>? updatedValues)
{
if(updatedValues is null)
@ -39,8 +50,6 @@ public partial class ConfigurationMultiSelect<TData> : ConfigurationBase
await this.InformAboutChange();
}
private static string GetClass => $"{MARGIN_CLASS} rounded-lg";
private string GetMultiSelectionText(List<TData?>? selectedValues)
{
if(selectedValues is null || selectedValues.Count == 0)

View File

@ -1,7 +1,5 @@
@inherits ConfigurationBase
@inherits ConfigurationBaseCore
<MudField Disabled="@this.Disabled()" Label="@this.OptionDescription" Variant="Variant.Outlined" HelperText="@this.OptionHelp" Class="@MARGIN_CLASS">
<MudSwitch T="bool" Disabled="@this.Disabled()" Value="@this.State()" ValueChanged="@this.OptionChanged" Color="Color.Primary">
@(this.State() ? this.LabelOn : this.LabelOff)
</MudSwitch>
</MudField>
<MudSwitch T="bool" Disabled="@this.IsDisabled" Value="@this.State()" ValueChanged="@this.OptionChanged" Color="Color.Primary">
@(this.State() ? this.LabelOn : this.LabelOff)
</MudSwitch>

View File

@ -5,7 +5,7 @@ namespace AIStudio.Components;
/// <summary>
/// Configuration component for any boolean option.
/// </summary>
public partial class ConfigurationOption : ConfigurationBase
public partial class ConfigurationOption : ConfigurationBaseCore
{
/// <summary>
/// Text to display when the option is true.
@ -31,6 +31,19 @@ public partial class ConfigurationOption : ConfigurationBase
[Parameter]
public Action<bool> StateUpdate { get; set; } = _ => { };
#region Overrides of ConfigurationBase
/// <inheritdoc />
protected override bool Stretch => true;
/// <inheritdoc />
protected override Variant Variant => Variant.Outlined;
/// <inheritdoc />
protected override string Label => this.OptionDescription;
#endregion
private async Task OptionChanged(bool updatedState)
{
this.StateUpdate(updatedState);

View File

@ -1,2 +1,2 @@
@inherits MSGComponentBase
<ConfigurationSelect OptionDescription="@T("Preselected provider")" Disabled="@this.Disabled" OptionHelp="@this.HelpText()" Data="@this.FilteredData()" SelectedValue="@this.SelectedValue" SelectionUpdate="@this.SelectionUpdate"/>
<ConfigurationSelect IsLocked="@this.IsLocked" OptionDescription="@T("Preselected provider")" Disabled="@(() => this.Disabled())" OptionHelp="@this.HelpText()" Data="@this.FilteredData()" SelectedValue="@this.SelectedValue" SelectionUpdate="@this.SelectionUpdate"/>

View File

@ -20,27 +20,17 @@ public partial class ConfigurationProviderSelection : MSGComponentBase
[Parameter]
public IEnumerable<ConfigurationSelectData<string>> Data { get; set; } = new List<ConfigurationSelectData<string>>();
/// <summary>
/// Is the selection component disabled?
/// </summary>
[Parameter]
public Func<bool> Disabled { get; set; } = () => false;
[Parameter]
public Func<string> HelpText { get; set; } = () => TB("Select a provider that is preselected.");
[Parameter]
public Tools.Components Component { get; set; } = Tools.Components.NONE;
#region Overrides of ComponentBase
protected override async Task OnParametersSetAsync()
{
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
await base.OnParametersSetAsync();
}
#endregion
[Parameter]
public Func<bool> Disabled { get; set; } = () => false;
[Parameter]
public Func<bool> IsLocked { get; set; } = () => false;
[SuppressMessage("Usage", "MWAIS0001:Direct access to `Providers` is not allowed")]
private IEnumerable<ConfigurationSelectData<string>> FilteredData()

View File

@ -1,7 +1,7 @@
@inherits ConfigurationBase
@typeparam T
@inherits ConfigurationBaseCore
@typeparam TConfig
<MudSelect T="T" Value="@this.SelectedValue()" Strict="@true" ShrinkLabel="@true" Disabled="@this.Disabled()" Margin="Margin.Dense" Label="@this.OptionDescription" Class="@GetClass" Variant="Variant.Outlined" HelperText="@this.OptionHelp" ValueChanged="@this.OptionChanged">
<MudSelect T="TConfig" Value="@this.SelectedValue()" Strict="@true" ShrinkLabel="@true" Disabled="@this.IsDisabled" Margin="Margin.Dense" Class="rounded-lg mb-0" Underline="false" ValueChanged="@this.OptionChanged">
@foreach (var data in this.Data)
{
<MudSelectItem Value="@data.Value">

View File

@ -7,33 +7,43 @@ namespace AIStudio.Components;
/// <summary>
/// Configuration component for selecting a value from a list.
/// </summary>
/// <typeparam name="T">The type of the value to select.</typeparam>
public partial class ConfigurationSelect<T> : ConfigurationBase
/// <typeparam name="TConfig">The type of the value to select.</typeparam>
public partial class ConfigurationSelect<TConfig> : ConfigurationBaseCore
{
/// <summary>
/// The data to select from.
/// </summary>
[Parameter]
public IEnumerable<ConfigurationSelectData<T>> Data { get; set; } = [];
public IEnumerable<ConfigurationSelectData<TConfig>> Data { get; set; } = [];
/// <summary>
/// The selected value.
/// </summary>
[Parameter]
public Func<T> SelectedValue { get; set; } = () => default!;
public Func<TConfig> SelectedValue { get; set; } = () => default!;
/// <summary>
/// An action that is called when the selection changes.
/// </summary>
[Parameter]
public Action<T> SelectionUpdate { get; set; } = _ => { };
public Action<TConfig> SelectionUpdate { get; set; } = _ => { };
private async Task OptionChanged(T updatedValue)
#region Overrides of ConfigurationBase
/// <inheritdoc />
protected override bool Stretch => true;
/// <inheritdoc />
protected override string Label => this.OptionDescription;
protected override Variant Variant => Variant.Outlined;
#endregion
private async Task OptionChanged(TConfig updatedValue)
{
this.SelectionUpdate(updatedValue);
await this.SettingsManager.StoreSettings();
await this.InformAboutChange();
}
private static string GetClass => $"{MARGIN_CLASS} rounded-lg";
}

View File

@ -1,8 +1,6 @@
@typeparam T
@inherits ConfigurationBase
@inherits ConfigurationBaseCore
<MudField Label="@this.OptionDescription" Variant="Variant.Outlined" Class="mb-3" Disabled="@this.Disabled()">
<MudSlider T="@T" Size="Size.Medium" Value="@this.Value()" ValueChanged="@this.OptionChanged" Min="@this.Min" Max="@this.Max" Step="@this.Step" Immediate="@true" Disabled="@this.Disabled()">
@this.Value() @this.Unit
</MudSlider>
</MudField>
<MudSlider T="@T" Size="Size.Medium" Value="@this.Value()" ValueChanged="@this.OptionChanged" Min="@this.Min" Max="@this.Max" Step="@this.Step" Immediate="@true" Disabled="@this.IsDisabled" Class="mb-1">
@this.Value() @this.Unit
</MudSlider>

View File

@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Components;
namespace AIStudio.Components;
public partial class ConfigurationSlider<T> : ConfigurationBase where T : struct, INumber<T>
public partial class ConfigurationSlider<T> : ConfigurationBaseCore where T : struct, INumber<T>
{
/// <summary>
/// The minimum value for the slider.
@ -42,6 +42,18 @@ public partial class ConfigurationSlider<T> : ConfigurationBase where T : struct
[Parameter]
public Action<T> ValueUpdate { get; set; } = _ => { };
#region Overrides of ConfigurationBase
/// <inheritdoc />
protected override bool Stretch => true;
/// <inheritdoc />
protected override Variant Variant => Variant.Outlined;
protected override string Label => this.OptionDescription;
#endregion
#region Overrides of ComponentBase
protected override async Task OnInitializedAsync()

View File

@ -1,12 +1,10 @@
@inherits ConfigurationBase
@inherits ConfigurationBaseCore
<MudTextField
T="string"
Text="@this.Text()"
TextChanged="@this.InternalUpdate"
Label="@this.OptionDescription"
Disabled="@this.Disabled()"
Class="@MARGIN_CLASS"
Disabled="@this.IsDisabled"
Adornment="Adornment.Start"
AdornmentIcon="@this.Icon"
AdornmentColor="@this.IconColor"
@ -15,5 +13,5 @@
AutoGrow="@this.AutoGrow"
MaxLines="@this.GetMaxLines"
Immediate="@true"
Variant="Variant.Outlined"
Underline="false"
/>

View File

@ -4,7 +4,7 @@ using Timer = System.Timers.Timer;
namespace AIStudio.Components;
public partial class ConfigurationText : ConfigurationBase
public partial class ConfigurationText : ConfigurationBaseCore
{
/// <summary>
/// The text used for the textfield.
@ -43,10 +43,21 @@ public partial class ConfigurationText : ConfigurationBase
public int MaxLines { get; set; } = 12;
private string internalText = string.Empty;
private Timer timer = new(TimeSpan.FromMilliseconds(500))
private readonly Timer timer = new(TimeSpan.FromMilliseconds(500))
{
AutoReset = false
};
#region Overrides of ConfigurationBase
/// <inheritdoc />
protected override bool Stretch => true;
protected override Variant Variant => Variant.Outlined;
protected override string Label => this.OptionDescription;
#endregion
#region Overrides of ConfigurationBase
@ -56,8 +67,6 @@ public partial class ConfigurationText : ConfigurationBase
await base.OnInitializedAsync();
}
#region Overrides of ComponentBase
protected override async Task OnParametersSetAsync()
{
this.internalText = this.Text();
@ -66,8 +75,6 @@ public partial class ConfigurationText : ConfigurationBase
#endregion
#endregion
private bool AutoGrow => this.NumLines > 1;
private int GetMaxLines => this.AutoGrow ? this.MaxLines : 1;

View File

@ -0,0 +1,5 @@
@inherits ConfigurationBaseCore
<MudButton Variant="Variant.Filled" Color="@Color.Primary" StartIcon="@this.Icon" Disabled="@this.IsDisabled" OnClick="@(async () => await this.ClickAsync())">
@this.Text
</MudButton>

View File

@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Components;
namespace AIStudio.Components;
public partial class LockableButton : ConfigurationBaseCore
{
[Parameter]
public string Icon { get; set; } = Icons.Material.Filled.Info;
[Parameter]
public Func<Task> OnClickAsync { get; set; } = () => Task.CompletedTask;
[Parameter]
public Action OnClick { get; set; } = () => { };
[Parameter]
public string Text { get; set; } = string.Empty;
[Parameter]
public string Class { get; set; } = string.Empty;
#region Overrides of ConfigurationBase
/// <inheritdoc />
protected override bool Stretch => false;
protected override string GetClassForBase => this.Class;
#endregion
private async Task ClickAsync()
{
if (this.IsLocked() || this.Disabled())
return;
await this.OnClickAsync();
this.OnClick();
}
}

View File

@ -13,7 +13,7 @@
<ConfigurationSelect OptionDescription="@T("Color theme")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.PreferredTheme)" Data="@ConfigurationSelectDataFactory.GetThemesData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.PreferredTheme = selectedValue)" OptionHelp="@T("Choose the color theme that best suits for you.")"/>
<ConfigurationOption OptionDescription="@T("Save energy?")" LabelOn="@T("Energy saving is enabled")" LabelOff="@T("Energy saving is disabled")" State="@(() => this.SettingsManager.ConfigurationData.App.IsSavingEnergy)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.App.IsSavingEnergy = updatedState)" OptionHelp="@T("When enabled, streamed content from the AI is updated once every third second. When disabled, streamed content will be updated as soon as it is available.")"/>
<ConfigurationOption OptionDescription="@T("Enable spellchecking?")" LabelOn="@T("Spellchecking is enabled")" LabelOff="@T("Spellchecking is disabled")" State="@(() => this.SettingsManager.ConfigurationData.App.EnableSpellchecking)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.App.EnableSpellchecking = updatedState)" OptionHelp="@T("When enabled, spellchecking will be active in all input fields. Depending on your operating system, errors may not be visually highlighted, but right-clicking may still offer possible corrections.")"/>
<ConfigurationSelect OptionDescription="@T("Check for updates")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.UpdateBehavior)" Data="@ConfigurationSelectDataFactory.GetUpdateBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UpdateBehavior = selectedValue)" OptionHelp="@T("How often should we check for app updates?")" Disabled="() => this.SettingsLocker.IsLocked<DataApp>(x => x.UpdateBehavior)"/>
<ConfigurationSelect OptionDescription="@T("Check for updates")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.UpdateBehavior)" Data="@ConfigurationSelectDataFactory.GetUpdateBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UpdateBehavior = selectedValue)" OptionHelp="@T("How often should we check for app updates?")" IsLocked="() => this.SettingsLocker.IsLocked<DataApp>(x => x.UpdateBehavior)"/>
<ConfigurationSelect OptionDescription="@T("Navigation bar behavior")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.NavigationBehavior)" Data="@ConfigurationSelectDataFactory.GetNavBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.NavigationBehavior = selectedValue)" OptionHelp="@T("Select the desired behavior for the navigation bar.")"/>
<ConfigurationSelect OptionDescription="@T("Preview feature visibility")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.PreviewVisibility)" Data="@ConfigurationSelectDataFactory.GetPreviewVisibility()" SelectionUpdate="@this.UpdatePreviewFeatures" OptionHelp="@T("Do you want to show preview features in the app?")"/>

View File

@ -74,10 +74,8 @@
@T("No providers configured yet.")
</MudText>
}
<MudButton Variant="Variant.Filled" Color="@Color.Primary" StartIcon="@Icons.Material.Filled.AddRoad" Class="mt-3 mb-6" OnClick="@this.AddLLMProvider">
@T("Add Provider")
</MudButton>
<LockableButton Text="@T("Add Provider")" IsLocked="@(() => !this.SettingsManager.ConfigurationData.App.AllowUserToAddProvider)" Icon="@Icons.Material.Filled.AddRoad" OnClickAsync="@this.AddLLMProvider" Class="mt-3" />
<MudText Typo="Typo.h4" Class="mb-3">
@T("LLM Provider Confidence")

View File

@ -64,4 +64,8 @@ CONFIG["SETTINGS"] = {}
-- Configure the update behavior:
-- Allowed values are: NO_CHECK, ONCE_STARTUP, HOURLY, DAILY, WEEKLY
-- CONFIG["SETTINGS"]["DataApp.UpdateBehavior"] = "NO_CHECK"
-- CONFIG["SETTINGS"]["DataApp.UpdateBehavior"] = "NO_CHECK"
-- Configure the user permission to add providers:
-- Allowed values are: true, false
-- CONFIG["SETTINGS"]["DataApp.AllowUserToAddProvider"] = false

View File

@ -1452,6 +1452,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIDENCEINFO::T3243388657"] = "Vertraue
-- Shows and hides the confidence card with information about the selected LLM provider.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIDENCEINFO::T847071819"] = "Zeigt oder verbirgt die Vertrauenskarte mit Informationen über den ausgewählten LLM-Anbieter."
-- This feature is managed by your organization and has therefore been disabled.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONBASE::T1416426626"] = "Diese Funktion wird von Ihrer Organisation verwaltet und wurde daher deaktiviert."
-- Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMINCONFIDENCESELECTION::T2526727283"] = "Wählen Sie das minimale Vertrauensniveau, das alle LLM-Anbieter erfüllen müssen. So stellen Sie sicher, dass nur vertrauenswürdige Anbieter verwendet werden. Anbieter, die dieses Niveau unterschreiten, können nicht verwendet werden."

View File

@ -1452,6 +1452,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIDENCEINFO::T3243388657"] = "Confiden
-- Shows and hides the confidence card with information about the selected LLM provider.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIDENCEINFO::T847071819"] = "Shows and hides the confidence card with information about the selected LLM provider."
-- This feature is managed by your organization and has therefore been disabled.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONBASE::T1416426626"] = "This feature is managed by your organization and has therefore been disabled."
-- Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMINCONFIDENCESELECTION::T2526727283"] = "Choose the minimum confidence level that all LLM providers must meet. This way, you can ensure that only trustworthy providers are used. You cannot use any provider that falls below this level."

View File

@ -58,9 +58,13 @@ public sealed class DataApp
/// </summary>
public string PreselectedProfile { get; set; } = string.Empty;
/// <summary>
/// Should we preselect a chat template for the entire app?
/// </summary>
public string PreselectedChatTemplate { get; set; } = string.Empty;
/// <summary>
/// Should the user be allowed to add providers?
/// </summary>
public bool AllowUserToAddProvider { get; set; } = true;
}

View File

@ -53,6 +53,12 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT
SETTINGS_LOCKER.Register<DataApp>(x => x.UpdateBehavior, this.Id);
SETTINGS_MANAGER.ConfigurationData.App.UpdateBehavior = updateBehavior;
}
if (settingsTable.TryGetValue(SettingsManager.ToSettingName<DataApp>(x => x.AllowUserToAddProvider), out var dontAllowUserToAddProviderValue) && dontAllowUserToAddProviderValue.TryRead<bool>(out var dontAllowUserToAddProviderEntry))
{
SETTINGS_LOCKER.Register<DataApp>(x => x.AllowUserToAddProvider, this.Id);
SETTINGS_MANAGER.ConfigurationData.App.AllowUserToAddProvider = dontAllowUserToAddProviderEntry;
}
//
// Configured providers

View File

@ -1,3 +1,4 @@
# v0.9.50, build 225 (2025-07-xx xx:xx UTC)
- Added an option for chat templates to predefine a user input.
- Added the ability to create chat templates from existing chats.
- Added the ability to create chat templates from existing chats.
- Added an enterprise IT configuration option to prevent manual addition of LLM providers in managed environments.