Upgraded to MudBlazor 9 (#1137)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-10-31 10:48:20 +01:00
1 parent e0337a99bc
commit aeba1fbccc
625 files changed
+399 -873

No files matched your search

+1 -1
View File
@@ -35,7 +35,7 @@ Key structure:
- **Sending content on** - Content which leaves one place for another, such as the result of an assistant sent to another assistant or a text sent into the chat, travels as a `TextLaunchPayload` through `AssistantLaunchService`, together with the restrictions of where it was written (`ChatRestrictions`, see `ChatThread.CaptureRestrictions`). Never hand over a bare string: the destination would let any provider or tool see content which its source kept from them. Build the payload with `AssistantLaunchService.CreateTextPayloadAsync`, which filters what an AI wrote for prompt injections before it reaches the next model as a message of the user. An assistant which allows sending to it overrides `AssistantBase.ApplyTextLaunchPayload`, and `SendToReceiverTests` checks that every one does; the restrictions themselves are applied centrally in `AssistantBase`. - **Sending content on** - Content which leaves one place for another, such as the result of an assistant sent to another assistant or a text sent into the chat, travels as a `TextLaunchPayload` through `AssistantLaunchService`, together with the restrictions of where it was written (`ChatRestrictions`, see `ChatThread.CaptureRestrictions`). Never hand over a bare string: the destination would let any provider or tool see content which its source kept from them. Build the payload with `AssistantLaunchService.CreateTextPayloadAsync`, which filters what an AI wrote for prompt injections before it reaches the next model as a message of the user. An assistant which allows sending to it overrides `AssistantBase.ApplyTextLaunchPayload`, and `SendToReceiverTests` checks that every one does; the restrictions themselves are applied centrally in `AssistantBase`.
- **JSON in model answers** - Read the JSON part of a model answer with `ModelAnswerJson`, never with a scanner of your own. It skips the prose and code fences around the JSON but checks nothing, so broken JSON reaches the deserializer unchanged and its message can go back to the model. - **JSON in model answers** - Read the JSON part of a model answer with `ModelAnswerJson`, never with a scanner of your own. It skips the prose and code fences around the JSON but checks nothing, so broken JSON reaches the deserializer unchanged and its message can go back to the model.
- **Long menus** - MudBlazor keeps a `MudSelect` inside the window by itself, but never a `MudMenu`: a menu taller than the window runs past its edge, and its lower entries cannot be reached. Give every `MudMenu` whose entries come from data, such as the assistants or the profiles, `MaxHeight="@MenuDefaults.MAX_HEIGHT"`, so that it scrolls. - **Long menus** - MudBlazor keeps a `MudSelect` inside the window by itself, but never a `MudMenu`: a menu taller than the window runs past its edge, and its lower entries cannot be reached. Give every `MudMenu` whose entries come from data, such as the assistants or the profiles, `MaxHeight="@MenuDefaults.MAX_HEIGHT"`, so that it scrolls.
- **Growing popovers** - MudBlazor places an open popover only when it opens, when the window changes, and when its component renders again. Content which unfolds later, such as a `MudCollapse` or an `ExpansionPanel` inside a `MudPopover`, would therefore grow out of the window. `wwwroot/app.js` places every open popover again whenever its size changes, so such content needs no code of its own. This relies on `window.mudpopoverHelper.placePopoverByNode`, which is internal to MudBlazor: check that it still exists with every new MudBlazor version. - **Growing popovers** - Since version 9, MudBlazor places an open popover again whenever its content changes size. Content which unfolds later, such as a `MudCollapse` or an `ExpansionPanel` inside a `MudPopover`, therefore stays inside the window and needs no code of its own.
- **Encryption** - Initialized before Rust service is marked ready - **Encryption** - Initialized before Rust service is marked ready
- **Debug environment** - Reads `startup.env` file with IPC credentials - **Debug environment** - Reads `startup.env` file with IPC credentials
- **Static files and the browser cache** - When the developer starts the app from Rider, the embedded browser of Tauri keeps the static files under `wwwroot/`, such as `app.css` or a script, in its cache. The app then still shows the old file, and a change seems not to work. Whenever you changed such a file, tell the developer to clear that cache through the developer tools of the embedded browser before testing. Users of a release are not affected. - **Static files and the browser cache** - When the developer starts the app from Rider, the embedded browser of Tauri keeps the static files under `wwwroot/`, such as `app.css` or a script, in its cache. The app then still shows the old file, and a change seems not to work. Whenever you changed such a file, tell the developer to clear that cache through the developer tools of the embedded browser before testing. Users of a release are not affected.
+22 -11
View File
@@ -8,6 +8,12 @@ namespace Build.Commands;
public sealed class UpdateWebAssetsCommand public sealed class UpdateWebAssetsCommand
{ {
/// <summary>
/// The pre-compressed copies and the source maps of the web assets. The app serves its web assets
/// from the files embedded into it and uses neither, so they would only enlarge it.
/// </summary>
private static readonly HashSet<string> SKIPPED_EXTENSIONS = new(StringComparer.OrdinalIgnoreCase) { ".br", ".gz", ".map" };
[Command("update-web", Description = "Update web assets")] [Command("update-web", Description = "Update web assets")]
public void UpdateWebAssets() public void UpdateWebAssets()
{ {
@@ -29,27 +35,32 @@ public sealed class UpdateWebAssetsCommand
return; return;
} }
//
// The destination also holds files of our own, such as the code editor. Hence, we replace
// only the folder of each package, so that files a package no longer ships disappear:
//
var destinationPath = Path.Join(cwd, "wwwroot", "system"); var destinationPath = Path.Join(cwd, "wwwroot", "system");
if(Directory.Exists(destinationPath))
Directory.Delete(destinationPath, true);
Directory.CreateDirectory(destinationPath);
var sourcePaths = Directory.EnumerateFiles(contentPath, "*", SearchOption.AllDirectories);
var counter = 0; var counter = 0;
foreach(var sourcePath in sourcePaths) foreach (var packagePath in Directory.EnumerateDirectories(contentPath))
{ {
var packageDestinationPath = Path.Join(destinationPath, Path.GetFileName(packagePath));
if (Directory.Exists(packageDestinationPath))
Directory.Delete(packageDestinationPath, true);
foreach (var sourcePath in Directory.EnumerateFiles(packagePath, "*", SearchOption.AllDirectories))
{
if (SKIPPED_EXTENSIONS.Contains(Path.GetExtension(sourcePath)))
continue;
counter++; counter++;
var relativePath = sourcePath var targetPath = Path.Join(packageDestinationPath, Path.GetRelativePath(packagePath, sourcePath));
.Replace(contentPath, "")
.TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
var targetPath = Path.Join(cwd, "wwwroot", "system", relativePath);
var targetDirectory = Path.GetDirectoryName(targetPath); var targetDirectory = Path.GetDirectoryName(targetPath);
if (targetDirectory != null) if (targetDirectory != null)
Directory.CreateDirectory(targetDirectory); Directory.CreateDirectory(targetDirectory);
File.Copy(sourcePath, targetPath, true); File.Copy(sourcePath, targetPath, true);
} }
}
Console.WriteLine($" {counter:###,###} web assets updated successfully."); Console.WriteLine($" {counter:###,###} web assets updated successfully.");
Console.WriteLine(); Console.WriteLine();
@@ -168,8 +168,8 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private string inputContent = string.Empty; private string inputContent = string.Empty;
private string inputDuration = string.Empty; private string inputDuration = string.Empty;
private string inputStartTime = string.Empty; private string inputStartTime = string.Empty;
private IEnumerable<string> selectedFoci = new HashSet<string>(); private IReadOnlyCollection<string> selectedFoci = new HashSet<string>();
private IEnumerable<string> justBriefly = new HashSet<string>(); private IReadOnlyCollection<string> justBriefly = new HashSet<string>();
private string inputObjective = string.Empty; private string inputObjective = string.Empty;
private string inputModerator = string.Empty; private string inputModerator = string.Empty;
private CommonLanguages selectedTargetLanguage; private CommonLanguages selectedTargetLanguage;
@@ -411,7 +411,7 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
private async Task CreateAgenda() private async Task CreateAgenda()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -307,8 +307,8 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
{ {
// Reset the validation when not editing and on the first render. // Reset the validation when not editing and on the first render.
// We don't want to show validation errors when the user opens the dialog. // We don't want to show validation errors when the user opens the dialog.
if(firstRender) if(firstRender && this.Form is not null)
this.Form?.ResetValidation(); await this.Form.ResetValidationAsync();
if (this.pendingRenderedAssistantSessionSnapshot is { } snapshot) if (this.pendingRenderedAssistantSessionSnapshot is { } snapshot)
{ {
@@ -434,7 +434,7 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
private async Task ReportProviderIssueAsync() private async Task ReportProviderIssueAsync()
{ {
if (this.Form is not null) if (this.Form is not null)
await this.Form.Validate(); await this.Form.ValidateAsync();
if (this.ValidatingProvider(this.ProviderSettings) is { } issue && !this.InputIssues.Contains(issue)) if (this.ValidatingProvider(this.ProviderSettings) is { } issue && !this.InputIssues.Contains(issue))
this.AddInputIssue(issue); this.AddInputIssue(issue);
@@ -962,9 +962,12 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
this.InputIsValid = false; this.InputIsValid = false;
this.InputIssues = []; this.InputIssues = [];
this.Form?.ResetValidation(); if (this.Form is not null)
await this.Form.ResetValidationAsync();
await this.RefreshAssistantUIAsync(); await this.RefreshAssistantUIAsync();
this.Form?.ResetValidation(); if (this.Form is not null)
await this.Form.ResetValidationAsync();
} }
private string GetResetColor() => this.SettingsManager.IsDarkMode switch private string GetResetColor() => this.SettingsManager.IsDarkMode switch
@@ -21,7 +21,7 @@
<div class="mt-6"> <div class="mt-6">
<FilePatternSelection> <FilePatternSelection>
<AllowedContent> <AllowedContent>
<MudTextField T="string" @bind-Text="@this.filePatterns" Validation="@this.ValidateFilePatterns" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("Files to include")" AdornmentIcon="@Icons.Material.Filled.Restore" Adornment="Adornment.End" OnAdornmentClick="@this.RestoreDefaultFilePatterns" AdornmentAriaLabel="@T("Restore default patterns")" Lines="1" AutoGrow="@true" MaxLines="@FilePatternSelection.MAX_FIELD_LINES" Class="pattern-text-field" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.filePatterns" Validation="@this.ValidateFilePatterns" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("Files to include")" AdornmentIcon="@Icons.Material.Filled.Restore" Adornment="Adornment.End" OnAdornmentClick="@this.RestoreDefaultFilePatterns" AdornmentAriaLabel="@T("Restore default patterns")" Lines="1" Sizing="InputSizing.Auto" MaxLines="@FilePatternSelection.MAX_FIELD_LINES" Class="pattern-text-field" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
</AllowedContent> </AllowedContent>
</FilePatternSelection> </FilePatternSelection>
</div> </div>
@@ -75,7 +75,7 @@
{ {
<ReadFileContent Text="@T("Load prompt from file")" @bind-FileContent="@this.freePrompt" EnableDragDrop="true" Disabled="@this.isProcessingBatch"/> <ReadFileContent Text="@T("Load prompt from file")" @bind-FileContent="@this.freePrompt" EnableDragDrop="true" Disabled="@this.isProcessingBatch"/>
<MudTextField T="string" @bind-Text="@this.freePrompt" Validation="@this.ValidateFreePrompt" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("What should the AI do with each document?")" HelperText="@T("These instructions are applied to every single document of the batch run.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" AutoGrow="@true" MaxLines="26" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.freePrompt" Validation="@this.ValidateFreePrompt" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("What should the AI do with each document?")" HelperText="@T("These instructions are applied to every single document of the batch run.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" Sizing="InputSizing.Auto" MaxLines="26" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<ToolSelectionField Component="@this.Component" SelectedToolIds="@this.SelectedToolIds" SelectedToolIdsChanged="@this.SelectedToolIdsChanged" Disabled="@this.isProcessingBatch" Label="@T("Tools for this batch run")" Help="@T("The AI may use these tools while working on each document. Every tool has to meet the confidence requirements of the selected provider, so a tool may stay unavailable even when it is selected here.")"/> <ToolSelectionField Component="@this.Component" SelectedToolIds="@this.SelectedToolIds" SelectedToolIdsChanged="@this.SelectedToolIdsChanged" Disabled="@this.isProcessingBatch" Label="@T("Tools for this batch run")" Help="@T("The AI may use these tools while working on each document. Every tool has to meet the confidence requirements of the selected provider, so a tool may stay unavailable even when it is selected here.")"/>
} }
@@ -129,7 +129,7 @@ public partial class AssistantBatchProcessing
/// <returns>The output folder and the documents, or <c>null</c> when the run must not start.</returns> /// <returns>The output folder and the documents, or <c>null</c> when the run must not start.</returns>
private async Task<(string ResolvedOutputDirectory, IReadOnlyList<string> Files)?> PrepareRunAsync() private async Task<(string ResolvedOutputDirectory, IReadOnlyList<string> Files)?> PrepareRunAsync()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
// //
// The exclusion list sits in the expert settings, which are folded away by default. Unfold // The exclusion list sits in the expert settings, which are folded away by default. Unfold
@@ -151,7 +151,7 @@ public partial class BiasOfTheDayAssistant : AssistantBaseCore<SettingsDialogAss
} }
} }
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -8,7 +8,7 @@
@if (this.step is BuilderStep.DESCRIBE) @if (this.step is BuilderStep.DESCRIBE)
{ {
<ReadFileContent Text="@T("Load description from file")" @bind-FileContent="@this.assistantDescription" EnableDragDrop="true" CatchAllDocuments="true"/> <ReadFileContent Text="@T("Load description from file")" @bind-FileContent="@this.assistantDescription" EnableDragDrop="true" CatchAllDocuments="true"/>
<MudTextField T="string" @bind-Text="@this.assistantDescription" Validation="@this.ValidateAssistantDescription" AdornmentIcon="@Icons.Material.Filled.AutoAwesome" Adornment="Adornment.Start" Label="@T("Describe your assistant")" HelperText="@T("Describe the task, inputs, and desired output in your own words. The model will infer all the plugin details.")" Placeholder="@T("I need an assistant that turns meeting notes into clear tasks with owners and deadlines.")" Variant="Variant.Outlined" Lines="8" AutoGrow="@true" MaxLines="18" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.assistantDescription" Validation="@this.ValidateAssistantDescription" AdornmentIcon="@Icons.Material.Filled.AutoAwesome" Adornment="Adornment.Start" Label="@T("Describe your assistant")" HelperText="@T("Describe the task, inputs, and desired output in your own words. The model will infer all the plugin details.")" Placeholder="@T("I need an assistant that turns meeting notes into clear tasks with owners and deadlines.")" Variant="Variant.Outlined" Lines="8" Sizing="InputSizing.Auto" MaxLines="18" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
@* This switch chooses between the two kinds of assistant the Builder can create, so it stays @* This switch chooses between the two kinds of assistant the Builder can create, so it stays
outside the advanced options. Its fields are required, and a collapsed panel would hide outside the advanced options. Its fields are required, and a collapsed panel would hide
@@ -53,8 +53,8 @@
<EnumSelection T="AssistantCategory" NameFunc="@(category => category.NameSelecting())" @bind-Value="@this.selectedCategory" ValidateSelection="@this.ValidatingCategory" Icon="@Icons.Material.Filled.Category" IconSize="Size.Small" Label="@T("Category (Optional)")" AllowOther="@true" OtherValue="AssistantCategory.OTHER" @bind-OtherInput="@this.customCategory" ValidateOther="@this.ValidateCustomCategory" LabelOther="@T("Custom assistant category")" /> <EnumSelection T="AssistantCategory" NameFunc="@(category => category.NameSelecting())" @bind-Value="@this.selectedCategory" ValidateSelection="@this.ValidatingCategory" Icon="@Icons.Material.Filled.Category" IconSize="Size.Small" Label="@T("Category (Optional)")" AllowOther="@true" OtherValue="AssistantCategory.OTHER" @bind-OtherInput="@this.customCategory" ValidateOther="@this.ValidateCustomCategory" LabelOther="@T("Custom assistant category")" />
@if (!this.createChatLauncher) @if (!this.createChatLauncher)
{ {
<MudTextField T="string" @bind-Text="@this.typicalInput" AdornmentIcon="@Icons.Material.Filled.Login" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Typical input (Optional)")" Placeholder="@T("What users provide, e.g. text, notes, files, or a URL")" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="3" AutoGrow="@true" MaxLines="8" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.typicalInput" AdornmentIcon="@Icons.Material.Filled.Login" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Typical input (Optional)")" Placeholder="@T("What users provide, e.g. text, notes, files, or a URL")" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="3" Sizing="InputSizing.Auto" MaxLines="8" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.expectedOutput" AdornmentIcon="@Icons.Material.Filled.Logout" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Expected output (Optional)")" Placeholder="@T("What users should get, e.g. a summary or checklist")" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="3" AutoGrow="@true" MaxLines="8" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.expectedOutput" AdornmentIcon="@Icons.Material.Filled.Logout" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Expected output (Optional)")" Placeholder="@T("What users should get, e.g. a summary or checklist")" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="3" Sizing="InputSizing.Auto" MaxLines="8" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudSelect T="AssistantComponentType" Label="@T("Input and UI components (Optional)")" MultiSelection="@true" @bind-SelectedValues="@this.selectedAssistantComponents" MultiSelectionTextFunc="@this.GetSelectedAssistantComponentText" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3 rounded-lg" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.ViewDay" IconSize="Size.Small"> <MudSelect T="AssistantComponentType" Label="@T("Input and UI components (Optional)")" MultiSelection="@true" @bind-SelectedValues="@this.selectedAssistantComponents" MultiSelectionTextFunc="@this.GetSelectedAssistantComponentText" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3 rounded-lg" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.ViewDay" IconSize="Size.Small">
@foreach (var component in ASSISTANT_COMPONENT_OPTIONS) @foreach (var component in ASSISTANT_COMPONENT_OPTIONS)
{ {
@@ -65,8 +65,8 @@
</MudSelect> </MudSelect>
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedOutputLanguage" Icon="@Icons.Material.Filled.Translate" IconSize="Size.Small" Label="@T("(Optional) Output language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customOutputLanguage" ValidateOther="@this.ValidateCustomOutputLanguage" LabelOther="@T("Custom output language")" /> <EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedOutputLanguage" Icon="@Icons.Material.Filled.Translate" IconSize="Size.Small" Label="@T("(Optional) Output language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customOutputLanguage" ValidateOther="@this.ValidateCustomOutputLanguage" LabelOther="@T("Custom output language")" />
<MudSwitch T="bool" @bind-Value="@this.allowGeneratedAssistantProfiles" Label="@T("Allow AI Studio profiles")" LabelPlacement="Placement.End" Color="Color.Primary" Class="mb-3"/> <MudSwitch T="bool" @bind-Value="@this.allowGeneratedAssistantProfiles" Label="@T("Allow AI Studio profiles")" LabelPlacement="Placement.End" Color="Color.Primary" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.extraRules" AdornmentIcon="@Icons.Material.Filled.Rule" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Additional rules (Optional)")" Placeholder="@T("What to avoid or consider, e.g. do not invent missing facts")" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="3" AutoGrow="@true" MaxLines="10" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.extraRules" AdornmentIcon="@Icons.Material.Filled.Rule" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Additional rules (Optional)")" Placeholder="@T("What to avoid or consider, e.g. do not invent missing facts")" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="3" Sizing="InputSizing.Auto" MaxLines="10" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.exampleRequest" AdornmentIcon="@Icons.Material.Filled.Lightbulb" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Example prompt (Optional)")" Placeholder="@T("An expected user prompt, e.g. summarize this document")" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="3" AutoGrow="@true" MaxLines="10" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.exampleRequest" AdornmentIcon="@Icons.Material.Filled.Lightbulb" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Example prompt (Optional)")" Placeholder="@T("An expected user prompt, e.g. summarize this document")" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="3" Sizing="InputSizing.Auto" MaxLines="10" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
} }
</CompactExpansionPanel> </CompactExpansionPanel>
@@ -85,7 +85,7 @@ else
</MudButton> </MudButton>
</MudStack> </MudStack>
<MudTextField T="string" @bind-Text="@this.reviewNotes" AdornmentIcon="@Icons.Material.Filled.EditNote" Adornment="Adornment.Start" Label="@T("Additional changes (Optional)")" HelperText="@T("These notes are applied on top of the accepted draft and can still change the generated assistant plugin. Leave empty to use the draft as-is.")" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="2" AutoGrow="@true" MaxLines="8" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.reviewNotes" AdornmentIcon="@Icons.Material.Filled.EditNote" Adornment="Adornment.Start" Label="@T("Additional changes (Optional)")" HelperText="@T("These notes are applied on top of the accepted draft and can still change the generated assistant plugin. Leave empty to use the draft as-is.")" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="2" Sizing="InputSizing.Auto" MaxLines="8" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudStack Row="@true" AlignItems="AlignItems.Center" Class="mb-6"> <MudStack Row="@true" AlignItems="AlignItems.Center" Class="mb-6">
<MudTooltip Text="@T("Return to the original assistant description. The current draft and the plugin preview will be discarded.")"> <MudTooltip Text="@T("Return to the original assistant description. The current draft and the plugin preview will be discarded.")">
@@ -102,9 +102,9 @@ public partial class AssistantBuilder : AssistantBaseCore<SettingsDialogAssistan
private string launcherProviderId = string.Empty; private string launcherProviderId = string.Empty;
private string launcherProfileId = string.Empty; private string launcherProfileId = string.Empty;
private string launcherChatTemplateId = string.Empty; private string launcherChatTemplateId = string.Empty;
private IEnumerable<string> launcherDataSourceIds = []; private IReadOnlyCollection<string> launcherDataSourceIds = [];
private HashSet<string> launcherToolIds = []; private HashSet<string> launcherToolIds = [];
private IEnumerable<AssistantComponentType> selectedAssistantComponents = []; private IReadOnlyCollection<AssistantComponentType> selectedAssistantComponents = [];
private CommonLanguages selectedOutputLanguage = CommonLanguages.AS_IS; private CommonLanguages selectedOutputLanguage = CommonLanguages.AS_IS;
private string customOutputLanguage = string.Empty; private string customOutputLanguage = string.Empty;
private bool allowGeneratedAssistantProfiles = true; private bool allowGeneratedAssistantProfiles = true;
@@ -391,7 +391,7 @@ public partial class AssistantBuilder : AssistantBaseCore<SettingsDialogAssistan
private async Task GenerateAssistantSpec() private async Task GenerateAssistantSpec()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -435,7 +435,7 @@ public partial class AssistantBuilder : AssistantBaseCore<SettingsDialogAssistan
private async Task GenerateLuaAssistant() private async Task GenerateLuaAssistant()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -530,7 +530,7 @@ public partial class AssistantBuilder : AssistantBaseCore<SettingsDialogAssistan
_ => this.selectedOutputLanguage.Name(), _ => this.selectedOutputLanguage.Name(),
}; };
private string GetSelectedAssistantComponentText(List<string?>? selectedValues) private string GetSelectedAssistantComponentText(IReadOnlyList<string?>? selectedValues)
{ {
if (selectedValues is null || selectedValues.Count == 0) if (selectedValues is null || selectedValues.Count == 0)
return T("Model decides"); return T("Model decides");
@@ -13,9 +13,9 @@
<MudTextSwitch Label="@T("Do you want to provide compiler messages?")" @bind-Value="@this.provideCompilerMessages" LabelOn="@T("Yes, provide compiler messages")" LabelOff="@T("No, there are no compiler messages")" /> <MudTextSwitch Label="@T("Do you want to provide compiler messages?")" @bind-Value="@this.provideCompilerMessages" LabelOn="@T("Yes, provide compiler messages")" LabelOff="@T("No, there are no compiler messages")" />
@if (this.provideCompilerMessages) @if (this.provideCompilerMessages)
{ {
<MudTextField T="string" @bind-Text="@this.compilerMessages" Validation="@this.ValidatingCompilerMessages" AdornmentIcon="@Icons.Material.Filled.Error" Adornment="Adornment.Start" Label="@T("Compiler messages")" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.compilerMessages" Validation="@this.ValidatingCompilerMessages" AdornmentIcon="@Icons.Material.Filled.Error" Adornment="Adornment.Start" Label="@T("Compiler messages")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
} }
</MudStack> </MudStack>
<MudTextField T="string" @bind-Text="@this.questions" Validation="@this.ValidateQuestions" AdornmentIcon="@Icons.Material.Filled.QuestionMark" Adornment="Adornment.Start" Label="@T("Your question(s)")" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.questions" Validation="@this.ValidateQuestions" AdornmentIcon="@Icons.Material.Filled.QuestionMark" Adornment="Adornment.Start" Label="@T("Your question(s)")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/> <ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/>
@@ -193,7 +193,7 @@ public partial class AssistantCoding : AssistantBaseCore<SettingsDialogCoding>
private async Task GetSupport() private async Task GetSupport()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -98,7 +98,7 @@ else
<MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyName" Validation="@this.ValidatePolicyName" Immediate="@true" Label="@T("Policy name")" HelperText="@T("Please give your policy a name that provides information about the intended purpose. The name will be displayed to users in AI Studio.")" Counter="60" MaxLength="60" Variant="Variant.Outlined" Margin="Margin.Normal" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3" OnKeyUp="@(() => this.PolicyNameWasChanged())"/> <MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyName" Validation="@this.ValidatePolicyName" Immediate="@true" Label="@T("Policy name")" HelperText="@T("Please give your policy a name that provides information about the intended purpose. The name will be displayed to users in AI Studio.")" Counter="60" MaxLength="60" Variant="Variant.Outlined" Margin="Margin.Normal" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3" OnKeyUp="@(() => this.PolicyNameWasChanged())"/>
<MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyDescription" Validation="@this.ValidatePolicyDescription" Immediate="@true" Label="@T("Policy description")" HelperText="@T("Please provide a brief description of your policy. Describe or explain what your policy does. This description will be shown to users in AI Studio.")" Counter="512" MaxLength="512" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" AutoGrow="@true" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/> <MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyDescription" Validation="@this.ValidatePolicyDescription" Immediate="@true" Label="@T("Policy description")" HelperText="@T("Please provide a brief description of your policy. Describe or explain what your policy does. This description will be shown to users in AI Studio.")" Counter="512" MaxLength="512" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextSwitch Disabled="@this.IsNoPolicySelectedOrProtected" Label="@T("Hide the policy definition when distributed via configuration plugin?")" Value="@this.policyHidePolicyDefinition" ValueChanged="async state => await this.PolicyHidePolicyDefinitionWasChanged(state)" LabelOn="@T("Yes, hide the policy definition")" LabelOff="@T("No, show the policy definition")" /> <MudTextSwitch Disabled="@this.IsNoPolicySelectedOrProtected" Label="@T("Hide the policy definition when distributed via configuration plugin?")" Value="@this.policyHidePolicyDefinition" ValueChanged="async state => await this.PolicyHidePolicyDefinitionWasChanged(state)" LabelOn="@T("Yes, hide the policy definition")" LabelOff="@T("No, show the policy definition")" />
@@ -128,7 +128,7 @@ else
@T("The analysis rules specify what the AI should pay particular attention to while reviewing the documents you provide, and which aspects it should highlight or save. For example, if you want to extract the potential of green hydrogen for agriculture from a variety of general publications, you can explicitly define this in the analysis rules.") @T("The analysis rules specify what the AI should pay particular attention to while reviewing the documents you provide, and which aspects it should highlight or save. For example, if you want to extract the potential of green hydrogen for agriculture from a variety of general publications, you can explicitly define this in the analysis rules.")
</MudJustifiedText> </MudJustifiedText>
<MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyAnalysisRules" Validation="@this.ValidateAnalysisRules" Immediate="@true" Label="@T("Analysis rules")" HelperText="@T("Please provide a description of your analysis rules. This rules will be used to instruct the AI on how to analyze the documents.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" AutoGrow="@true" MaxLines="26" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/> <MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyAnalysisRules" Validation="@this.ValidateAnalysisRules" Immediate="@true" Label="@T("Analysis rules")" HelperText="@T("Please provide a description of your analysis rules. This rules will be used to instruct the AI on how to analyze the documents.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" Sizing="InputSizing.Auto" MaxLines="26" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
@* No default target for the rule zones: while the policy definition is open, three @* No default target for the rule zones: while the policy definition is open, three
zones are in play, so each drop has to be aimed at the one it belongs to. *@ zones are in play, so each drop has to be aimed at the one it belongs to. *@
@@ -138,7 +138,7 @@ else
@T("After the AI has processed all documents, it needs your instructions on how the result should be formatted. Would you like a structured list with keywords or a continuous text? Should the output include emojis or be written in formal business language? You can specify all these preferences in the output rules. There, you can also predefine a desired structure—for example, by using Markdown formatting to define headings, paragraphs, or bullet points.") @T("After the AI has processed all documents, it needs your instructions on how the result should be formatted. Would you like a structured list with keywords or a continuous text? Should the output include emojis or be written in formal business language? You can specify all these preferences in the output rules. There, you can also predefine a desired structure—for example, by using Markdown formatting to define headings, paragraphs, or bullet points.")
</MudJustifiedText> </MudJustifiedText>
<MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyOutputRules" Validation="@this.ValidateOutputRules" Immediate="@true" Label="@T("Output rules")" HelperText="@T("Please provide a description of your output rules. This rules will be used to instruct the AI on how to format the output of the analysis.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" AutoGrow="@true" MaxLines="26" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/> <MudTextField T="string" Disabled="@this.IsNoPolicySelectedOrProtected" @bind-Text="@this.policyOutputRules" Validation="@this.ValidateOutputRules" Immediate="@true" Label="@T("Output rules")" HelperText="@T("Please provide a description of your output rules. This rules will be used to instruct the AI on how to format the output of the analysis.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" Sizing="InputSizing.Auto" MaxLines="26" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<ReadFileContent Text="@T("Load output rules from document")" @bind-FileContent="@this.policyOutputRules" EnableDragDrop="true" Disabled="@this.IsNoPolicySelectedOrProtected"/> <ReadFileContent Text="@T("Load output rules from document")" @bind-FileContent="@this.policyOutputRules" EnableDragDrop="true" Disabled="@this.IsNoPolicySelectedOrProtected"/>
@@ -445,7 +445,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
private bool ArePolicyControlsDisabled => this.IsProcessing || this.IsMediaImportBusy; private bool ArePolicyControlsDisabled => this.IsProcessing || this.IsMediaImportBusy;
private void SelectedPolicyChanged(DataDocumentAnalysisPolicy? policy) private async Task SelectedPolicyChanged(DataDocumentAnalysisPolicy? policy)
{ {
if (this.ArePolicyControlsDisabled) if (this.ArePolicyControlsDisabled)
return; return;
@@ -456,7 +456,9 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
this.documentSelectionExpanded = !this.policyDefinitionExpanded; this.documentSelectionExpanded = !this.policyDefinitionExpanded;
this.ApplyPolicyPreselection(preferPolicyPreselection: true); this.ApplyPolicyPreselection(preferPolicyPreselection: true);
this.Form?.ResetValidation(); if (this.Form is not null)
await this.Form.ResetValidationAsync();
this.ClearInputIssues(); this.ClearInputIssues();
} }
@@ -502,7 +504,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
this.SettingsManager.ConfigurationData.DocumentAnalysis.Policies.Add(addedPolicy); this.SettingsManager.ConfigurationData.DocumentAnalysis.Policies.Add(addedPolicy);
await this.SettingsManager.StoreSettings(); await this.SettingsManager.StoreSettings();
this.SelectedPolicyChanged(addedPolicy); await this.SelectedPolicyChanged(addedPolicy);
} }
private async Task AddPolicy() private async Task AddPolicy()
@@ -556,7 +558,8 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
this.ResetForm(); this.ResetForm();
await this.SettingsManager.StoreSettings(); await this.SettingsManager.StoreSettings();
this.Form?.ResetValidation(); if (this.Form is not null)
await this.Form.ResetValidationAsync();
} }
/// <summary> /// <summary>
@@ -728,7 +731,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
#region Overrides of MSGComponentBase #region Overrides of MSGComponentBase
protected override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
{ {
switch (triggeredEvent) switch (triggeredEvent)
{ {
@@ -738,17 +741,17 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
break; break;
case Event.PLUGINS_RELOADED: case Event.PLUGINS_RELOADED:
this.HandlePluginsReloaded(); await this.HandlePluginsReloaded();
this.StateHasChanged(); this.StateHasChanged();
break; break;
} }
return base.ProcessIncomingMessage(sendingComponent, triggeredEvent, data); await base.ProcessIncomingMessage(sendingComponent, triggeredEvent, data);
} }
#endregion #endregion
private void HandlePluginsReloaded() private async Task HandlePluginsReloaded()
{ {
// Check if the currently selected policy still exists after plugin reload: // Check if the currently selected policy still exists after plugin reload:
if (this.selectedPolicy is not null) if (this.selectedPolicy is not null)
@@ -788,7 +791,9 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
this.ApplyPolicyPreselection(preferPolicyPreselection: true); this.ApplyPolicyPreselection(preferPolicyPreselection: true);
// Reset validation state: // Reset validation state:
this.Form?.ResetValidation(); if (this.Form is not null)
await this.Form.ResetValidationAsync();
this.ClearInputIssues(); this.ClearInputIssues();
} }
@@ -959,7 +964,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
private async Task Analyze() private async Task Analyze()
{ {
await this.AutoSave(); await this.AutoSave();
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -90,12 +90,12 @@ else
if (component is AssistantTextArea textArea) if (component is AssistantTextArea textArea)
{ {
var lines = textArea.IsSingleLine ? 1 : 6; var lines = textArea.IsSingleLine ? 1 : 6;
var autoGrow = !textArea.IsSingleLine; var sizing = textArea.IsSingleLine ? InputSizing.Fixed : InputSizing.Auto;
<MudTextField T="string" <MudTextField T="string"
UserAttributes="@SPELLCHECK_ATTRIBUTES" UserAttributes="@SPELLCHECK_ATTRIBUTES"
Text="@this.assistantState.Text[textArea.Name]" Text="@this.assistantState.Text[textArea.Name]"
TextChanged="@(value => this.assistantState.Text[textArea.Name] = value)" TextChanged="@(value => this.assistantState.Text[textArea.Name] = value ?? string.Empty)"
Label="@textArea.Label" Label="@textArea.Label"
HelperText="@textArea.HelperText" HelperText="@textArea.HelperText"
HelperTextOnFocus="@textArea.HelperTextOnFocus" HelperTextOnFocus="@textArea.HelperTextOnFocus"
@@ -109,7 +109,7 @@ else
AdornmentColor="@textArea.GetAdornmentColor()" AdornmentColor="@textArea.GetAdornmentColor()"
Variant="Variant.Outlined" Variant="Variant.Outlined"
Lines="@lines" Lines="@lines"
AutoGrow="@autoGrow" Sizing="@sizing"
MaxLines="12" MaxLines="12"
Class='@MergeClass(textArea.Class, "mb-3")' Class='@MergeClass(textArea.Class, "mb-3")'
Style="@GetOptionalStyle(textArea.Style)" /> Style="@GetOptionalStyle(textArea.Style)" />
@@ -479,7 +479,7 @@ else
<MudItem Class="d-flex"> <MudItem Class="d-flex">
<MudColorPicker Text="@this.assistantState.Colors[colorPicker.Name]" <MudColorPicker Text="@this.assistantState.Colors[colorPicker.Name]"
TextChanged="@(value => this.assistantState.Colors[colorPicker.Name] = value)" TextChanged="@(value => this.assistantState.Colors[colorPicker.Name] = value ?? string.Empty)"
Label="@colorPicker.Label" Label="@colorPicker.Label"
Placeholder="@colorPicker.Placeholder" Placeholder="@colorPicker.Placeholder"
ShowAlpha="@colorPicker.ShowAlpha" ShowAlpha="@colorPicker.ShowAlpha"
@@ -5,7 +5,7 @@
@if (this.provideHistory) @if (this.provideHistory)
{ {
<MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg"> <MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg">
<MudTextField T="string" @bind-Text="@this.inputHistory" Validation="@this.ValidateHistory" Label="@T("Previous conversation")" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Provide the previous conversation, e.g., the last e-mail, the last chat, etc.")" Class="mb-3" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.DocumentScanner"/> <MudTextField T="string" @bind-Text="@this.inputHistory" Validation="@this.ValidateHistory" Label="@T("Previous conversation")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Provide the previous conversation, e.g., the last e-mail, the last chat, etc.")" Class="mb-3" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.DocumentScanner"/>
</MudPaper> </MudPaper>
} }
@@ -74,7 +74,7 @@ public partial class AssistantEMail : AssistantBaseCore<SettingsDialogWritingEMa
private string inputGreeting = string.Empty; private string inputGreeting = string.Empty;
private string inputBulletPoints = string.Empty; private string inputBulletPoints = string.Empty;
private readonly List<string> bulletPointsLines = []; private readonly List<string> bulletPointsLines = [];
private IEnumerable<string> selectedFoci = new HashSet<string>(); private IReadOnlyCollection<string> selectedFoci = new HashSet<string>();
private string inputName = string.Empty; private string inputName = string.Empty;
private CommonLanguages selectedTargetLanguage = CommonLanguages.AS_IS; private CommonLanguages selectedTargetLanguage = CommonLanguages.AS_IS;
private string customTargetLanguage = string.Empty; private string customTargetLanguage = string.Empty;
@@ -259,7 +259,7 @@ public partial class AssistantEMail : AssistantBaseCore<SettingsDialogWritingEMa
private async Task CreateMail() private async Task CreateMail()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -90,7 +90,7 @@ else
@T("Common ERI server settings") @T("Common ERI server settings")
</MudText> </MudText>
<MudTextField T="string" Disabled="@this.IsERIInputDisabled" @bind-Text="@this.serverName" Validation="@this.ValidateServerName" Immediate="@true" Label="@T("ERI server name")" HelperText="@T("Please give your ERI server a name that provides information about the data source and/or its intended purpose. The name will be displayed to users in AI Studio.")" Counter="60" MaxLength="60" Variant="Variant.Outlined" Margin="Margin.Normal" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3" OnKeyUp="() => this.ServerNameWasChanged()"/> <MudTextField T="string" Disabled="@this.IsERIInputDisabled" @bind-Text="@this.serverName" Validation="@this.ValidateServerName" Immediate="@true" Label="@T("ERI server name")" HelperText="@T("Please give your ERI server a name that provides information about the data source and/or its intended purpose. The name will be displayed to users in AI Studio.")" Counter="60" MaxLength="60" Variant="Variant.Outlined" Margin="Margin.Normal" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3" OnKeyUp="() => this.ServerNameWasChanged()"/>
<MudTextField T="string" Disabled="@this.IsERIInputDisabled" @bind-Text="@this.serverDescription" Validation="@this.ValidateServerDescription" Immediate="@true" Label="@T("ERI server description")" HelperText="@T("Please provide a brief description of your ERI server. Describe or explain what your ERI server does and what data it uses for this purpose. This description will be shown to users in AI Studio.")" Counter="512" MaxLength="512" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" AutoGrow="@true" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/> <MudTextField T="string" Disabled="@this.IsERIInputDisabled" @bind-Text="@this.serverDescription" Validation="@this.ValidateServerDescription" Immediate="@true" Label="@T("ERI server description")" HelperText="@T("Please provide a brief description of your ERI server. Describe or explain what your ERI server does and what data it uses for this purpose. This description will be shown to users in AI Studio.")" Counter="512" MaxLength="512" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudStack Row="@true" Class="mb-3"> <MudStack Row="@true" Class="mb-3">
<MudSelect Disabled="@this.IsERIInputDisabled" T="ProgrammingLanguages" @bind-Value="@this.selectedProgrammingLanguage" AdornmentIcon="@Icons.Material.Filled.Code" Adornment="Adornment.Start" Label="@T("Programming language")" Variant="Variant.Outlined" Margin="Margin.Dense" Validation="@this.ValidateProgrammingLanguage"> <MudSelect Disabled="@this.IsERIInputDisabled" T="ProgrammingLanguages" @bind-Value="@this.selectedProgrammingLanguage" AdornmentIcon="@Icons.Material.Filled.Code" Adornment="Adornment.Start" Label="@T("Programming language")" Variant="Variant.Outlined" Margin="Margin.Dense" Validation="@this.ValidateProgrammingLanguage">
@@ -136,7 +136,7 @@ else
</MudSelect> </MudSelect>
@if (this.selectedDataSource is DataSources.CUSTOM) @if (this.selectedDataSource is DataSources.CUSTOM)
{ {
<MudTextField Disabled="@this.IsERIInputDisabled" T="string" @bind-Text="@this.otherDataSource" Validation="@this.ValidateOtherDataSource" Label="@T("Describe your data source")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" AutoGrow="@true" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField Disabled="@this.IsERIInputDisabled" T="string" @bind-Text="@this.otherDataSource" Validation="@this.ValidateOtherDataSource" Label="@T("Describe your data source")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
} }
</MudStack> </MudStack>
@@ -185,7 +185,7 @@ else
</MudSelectItemExtended> </MudSelectItemExtended>
} }
</MudSelectExtended> </MudSelectExtended>
<MudTextField Disabled="@this.IsERIInputDisabled" T="string" @bind-Text="@this.authDescription" Label="@this.AuthDescriptionTitle()" Validation="@this.ValidateAuthDescription" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" AutoGrow="@true" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField Disabled="@this.IsERIInputDisabled" T="string" @bind-Text="@this.authDescription" Label="@this.AuthDescriptionTitle()" Validation="@this.ValidateAuthDescription" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="6" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
</MudStack> </MudStack>
@if (this.selectedAuthenticationMethods.Contains(Auth.KERBEROS)) @if (this.selectedAuthenticationMethods.Contains(Auth.KERBEROS))
@@ -316,7 +316,7 @@ else
@T("You can integrate additional libraries. Perhaps you want to evaluate the prompts in advance using a machine learning method or analyze them with a text mining approach? Or maybe you want to preprocess images in the prompts? For such advanced scenarios, you can specify which libraries you want to use here. It's best to describe which library you want to integrate for which purpose. This way, the LLM that writes the ERI server for you can try to use these libraries effectively. This should result in less rework being necessary. If you don't know the necessary libraries, you can instead attempt to describe the intended use. The LLM can then attempt to choose suitable libraries. However, hallucinations can occur, and fictional libraries might be selected.") @T("You can integrate additional libraries. Perhaps you want to evaluate the prompts in advance using a machine learning method or analyze them with a text mining approach? Or maybe you want to preprocess images in the prompts? For such advanced scenarios, you can specify which libraries you want to use here. It's best to describe which library you want to integrate for which purpose. This way, the LLM that writes the ERI server for you can try to use these libraries effectively. This should result in less rework being necessary. If you don't know the necessary libraries, you can instead attempt to describe the intended use. The LLM can then attempt to choose suitable libraries. However, hallucinations can occur, and fictional libraries might be selected.")
</MudJustifiedText> </MudJustifiedText>
<MudTextField Disabled="@this.IsERIInputDisabled" T="string" @bind-Text="@this.additionalLibraries" Label="@T("(Optional) Additional libraries")" HelperText="@T("Do you want to include additional libraries? Then name them and briefly describe what you want to achieve with them.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" AutoGrow="@true" MaxLines="12" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/> <MudTextField Disabled="@this.IsERIInputDisabled" T="string" @bind-Text="@this.additionalLibraries" Label="@T("(Optional) Additional libraries")" HelperText="@T("Do you want to include additional libraries? Then name them and briefly describe what you want to achieve with them.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="3" Sizing="InputSizing.Auto" MaxLines="12" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudText Typo="Typo.h4" Class="mt-9 mb-1"> <MudText Typo="Typo.h4" Class="mt-9 mb-1">
@T("Provider selection for generation") @T("Provider selection for generation")
@@ -611,7 +611,8 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
this.ResetForm(); this.ResetForm();
await this.SettingsManager.StoreSettings(); await this.SettingsManager.StoreSettings();
this.Form?.ResetValidation(); if (this.Form is not null)
await this.Form.ResetValidationAsync();
} }
private bool IsNoneERIServerSelected => this.selectedERIServer is null; private bool IsNoneERIServerSelected => this.selectedERIServer is null;
@@ -1106,7 +1107,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
return; return;
await this.AutoSave(); await this.AutoSave();
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -2,6 +2,6 @@
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogGrammarSpelling> @inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogGrammarSpelling>
<ReadFileContent Text="@T("Load text from file")" @bind-FileContent="@this.inputText" EnableDragDrop="true" CatchAllDocuments="true"/> <ReadFileContent Text="@T("Load text from file")" @bind-FileContent="@this.inputText" EnableDragDrop="true" CatchAllDocuments="true"/>
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidateText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Your input to check")" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidateText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Your input to check")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="@T("Language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom language")" /> <EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="@T("Language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom language")" />
<ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/> <ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/>
@@ -135,7 +135,7 @@ public partial class AssistantGrammarSpelling : AssistantBaseCore<SettingsDialog
private async Task ProofreadText() private async Task ProofreadText()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -349,7 +349,7 @@ public partial class AssistantI18N : AssistantBaseCore<SettingsDialogI18N>
private async Task LocalizeTextContent() private async Task LocalizeTextContent()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -1,7 +1,7 @@
@attribute [Route(Routes.ASSISTANT_ICON_FINDER)] @attribute [Route(Routes.ASSISTANT_ICON_FINDER)]
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogIconFinder> @inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogIconFinder>
<MudTextField T="string" @bind-Text="@this.inputContext" Validation="@this.ValidatingContext" AdornmentIcon="@Icons.Material.Filled.Description" Adornment="Adornment.Start" Label="@T("Your context")" Variant="Variant.Outlined" Lines="3" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.inputContext" Validation="@this.ValidatingContext" AdornmentIcon="@Icons.Material.Filled.Description" Adornment="Adornment.Start" Label="@T("Your context")" Variant="Variant.Outlined" Lines="3" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudStack Row="@true" AlignItems="AlignItems.Center" Class="mb-3"> <MudStack Row="@true" AlignItems="AlignItems.Center" Class="mb-3">
<MudSelect T="IconSources" @bind-Value="@this.selectedIconSource" AdornmentIcon="@Icons.Material.Filled.Source" Adornment="Adornment.Start" Label="@T("Your icon source")" Variant="Variant.Outlined" Margin="Margin.Dense"> <MudSelect T="IconSources" @bind-Value="@this.selectedIconSource" AdornmentIcon="@Icons.Material.Filled.Source" Adornment="Adornment.Start" Label="@T("Your icon source")" Variant="Variant.Outlined" Margin="Margin.Dense">
@@ -91,7 +91,7 @@ public partial class AssistantIconFinder : AssistantBaseCore<SettingsDialogIconF
private async Task FindIcon() private async Task FindIcon()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -5,13 +5,13 @@
<MudTextField T="string" @bind-Text="@this.inputCountryLegalFramework" Label="@T("Provide the country, where the company is located")" Validation="@this.ValidateCountryLegalFramework" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Flag" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3" HelperText="@T("This is important to consider the legal framework of the country.")"/> <MudTextField T="string" @bind-Text="@this.inputCountryLegalFramework" Label="@T("Provide the country, where the company is located")" Validation="@this.ValidateCountryLegalFramework" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Flag" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3" HelperText="@T("This is important to consider the legal framework of the country.")"/>
@* Four zones, so no default target: every drop has to be aimed at the field it belongs to. *@ @* Four zones, so no default target: every drop has to be aimed at the field it belongs to. *@
<ReadFileContent Text="@T("Load the mandatory information from file")" @bind-FileContent="@this.inputMandatoryInformation" EnableDragDrop="true"/> <ReadFileContent Text="@T("Load the mandatory information from file")" @bind-FileContent="@this.inputMandatoryInformation" EnableDragDrop="true"/>
<MudTextField T="string" @bind-Text="@this.inputMandatoryInformation" Label="@T("(Optional) Provide mandatory information")" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.TextSnippet" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Mandatory information that your company requires for all job postings. This can include the company description, etc.")" /> <MudTextField T="string" @bind-Text="@this.inputMandatoryInformation" Label="@T("(Optional) Provide mandatory information")" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.TextSnippet" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Mandatory information that your company requires for all job postings. This can include the company description, etc.")" />
<ReadFileContent Text="@T("Load the job description from file")" @bind-FileContent="@this.inputJobDescription" EnableDragDrop="true"/> <ReadFileContent Text="@T("Load the job description from file")" @bind-FileContent="@this.inputJobDescription" EnableDragDrop="true"/>
<MudTextField T="string" @bind-Text="@this.inputJobDescription" Label="@T("Job description")" Validation="@this.ValidateJobDescription" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Settings" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Describe what the person is supposed to do in the company. This might be just short bullet points.")" /> <MudTextField T="string" @bind-Text="@this.inputJobDescription" Label="@T("Job description")" Validation="@this.ValidateJobDescription" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Settings" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Describe what the person is supposed to do in the company. This might be just short bullet points.")" />
<ReadFileContent Text="@T("Load the qualifications from file")" @bind-FileContent="@this.inputQualifications" EnableDragDrop="true"/> <ReadFileContent Text="@T("Load the qualifications from file")" @bind-FileContent="@this.inputQualifications" EnableDragDrop="true"/>
<MudTextField T="string" @bind-Text="@this.inputQualifications" Label="@T("(Optional) Provide necessary job qualifications")" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Settings" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Describe what the person should bring to the table. This might be just short bullet points.")" /> <MudTextField T="string" @bind-Text="@this.inputQualifications" Label="@T("(Optional) Provide necessary job qualifications")" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Settings" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Describe what the person should bring to the table. This might be just short bullet points.")" />
<ReadFileContent Text="@T("Load the responsibilities from file")" @bind-FileContent="@this.inputResponsibilities" EnableDragDrop="true"/> <ReadFileContent Text="@T("Load the responsibilities from file")" @bind-FileContent="@this.inputResponsibilities" EnableDragDrop="true"/>
<MudTextField T="string" @bind-Text="@this.inputResponsibilities" Label="@T("(Optional) Provide job responsibilities")" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Settings" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Describe the responsibilities the person should take on in the company.")" /> <MudTextField T="string" @bind-Text="@this.inputResponsibilities" Label="@T("(Optional) Provide job responsibilities")" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Settings" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES" HelperText="@T("Describe the responsibilities the person should take on in the company.")" />
<MudTextField T="string" @bind-Text="@this.inputWorkLocation" Label="@T("(Optional) Provide the work location")" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.MyLocation" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/> <MudTextField T="string" @bind-Text="@this.inputWorkLocation" Label="@T("(Optional) Provide the work location")" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.MyLocation" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputEntryDate" Label="@T("(Optional) Provide the entry date")" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.DateRange" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/> <MudTextField T="string" @bind-Text="@this.inputEntryDate" Label="@T("(Optional) Provide the entry date")" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.DateRange" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
<MudTextField T="string" @bind-Text="@this.inputValidUntil" Label="@T("(Optional) Provide the date until the job posting is valid")" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.DateRange" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/> <MudTextField T="string" @bind-Text="@this.inputValidUntil" Label="@T("(Optional) Provide the date until the job posting is valid")" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.DateRange" Variant="Variant.Outlined" Margin="Margin.Dense" UserAttributes="@USER_INPUT_ATTRIBUTES" Class="mb-3"/>
@@ -325,7 +325,7 @@ public partial class AssistantJobPostings : AssistantBaseCore<SettingsDialogJobP
private async Task CreateJobPosting() private async Task CreateJobPosting()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -8,8 +8,8 @@
@* Two zones, so no default target: the user has to aim at the one they mean. *@ @* Two zones, so no default target: the user has to aim at the one they mean. *@
<ReadFileContent Text="@T("Load the legal document from file")" @bind-FileContent="@this.inputLegalDocument" EnableDragDrop="true"/> <ReadFileContent Text="@T("Load the legal document from file")" @bind-FileContent="@this.inputLegalDocument" EnableDragDrop="true"/>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputLegalDocument" Validation="@this.ValidatingLegalDocument" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Legal document")" Variant="Variant.Outlined" Lines="12" AutoGrow="@true" MaxLines="24" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputLegalDocument" Validation="@this.ValidatingLegalDocument" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Legal document")" Variant="Variant.Outlined" Lines="12" Sizing="InputSizing.Auto" MaxLines="24" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<ReadFileContent Text="@T("Load your questions from file")" @bind-FileContent="@this.inputQuestions" EnableDragDrop="true"/> <ReadFileContent Text="@T("Load your questions from file")" @bind-FileContent="@this.inputQuestions" EnableDragDrop="true"/>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputQuestions" Validation="@this.ValidatingQuestions" AdornmentIcon="@Icons.Material.Filled.QuestionAnswer" Adornment="Adornment.Start" Label="@T("Your questions")" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputQuestions" Validation="@this.ValidatingQuestions" AdornmentIcon="@Icons.Material.Filled.QuestionAnswer" Adornment="Adornment.Start" Label="@T("Your questions")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/> <ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/>
@@ -116,7 +116,7 @@ public partial class AssistantLegalCheck : AssistantBaseCore<SettingsDialogLegal
private async Task AskQuestions() private async Task AskQuestions()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -443,7 +443,7 @@ public partial class AssistantLogViewer : MSGComponentBase
return value == OTHER_OPTION_VALUE ? T("Other") : value; return value == OTHER_OPTION_VALUE ? T("Other") : value;
} }
private string GetMultiSelectionText(List<string?>? selectedValues) private string GetMultiSelectionText(IReadOnlyList<string?>? selectedValues)
{ {
if (selectedValues is null || selectedValues.Count == 0) if (selectedValues is null || selectedValues.Count == 0)
return T("All"); return T("All");
@@ -2,7 +2,7 @@
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogMyTasks> @inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogMyTasks>
<ProfileFormSelection Validation="@this.ValidateProfile" @bind-Profile="@this.CurrentProfile"/> <ProfileFormSelection Validation="@this.ValidateProfile" @bind-Profile="@this.CurrentProfile"/>
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Text or email")" Variant="Variant.Outlined" Lines="12" AutoGrow="@true" MaxLines="24" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Text or email")" Variant="Variant.Outlined" Lines="12" Sizing="InputSizing.Auto" MaxLines="24" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudText Typo="Typo.h6" Class="mb-1 mt-1">@T("Attach documents")</MudText> <MudText Typo="Typo.h6" Class="mb-1 mt-1">@T("Attach documents")</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2"> <MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("You can enter text, attach one or more documents, or use both. At least one input is required.") @T("You can enter text, attach one or more documents, or use both. At least one input is required.")
@@ -155,7 +155,7 @@ public partial class AssistantMyTasks : AssistantBaseCore<SettingsDialogMyTasks>
private async Task OnDocumentsChanged(HashSet<FileAttachment> _) private async Task OnDocumentsChanged(HashSet<FileAttachment> _)
{ {
if(this.Form is not null) if(this.Form is not null)
await this.Form.Validate(); await this.Form.ValidateAsync();
} }
private string? ValidateProfile(Profile profile) private string? ValidateProfile(Profile profile)
@@ -204,7 +204,7 @@ public partial class AssistantMyTasks : AssistantBaseCore<SettingsDialogMyTasks>
private async Task AnalyzeText() private async Task AnalyzeText()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -12,7 +12,7 @@
Label="@T("Prompt or prompt description")" Label="@T("Prompt or prompt description")"
Variant="Variant.Outlined" Variant="Variant.Outlined"
Lines="8" Lines="8"
AutoGrow="@true" Sizing="InputSizing.Auto"
MaxLines="20" MaxLines="20"
Class="mb-3" Class="mb-3"
UserAttributes="@USER_INPUT_ATTRIBUTES"/> UserAttributes="@USER_INPUT_ATTRIBUTES"/>
@@ -29,7 +29,7 @@
LabelOther="@T("Custom language")"/> LabelOther="@T("Custom language")"/>
<MudTextField T="string" <MudTextField T="string"
AutoGrow="true" Sizing="InputSizing.Auto"
Lines="2" Lines="2"
@bind-Text="@this.importantAspects" @bind-Text="@this.importantAspects"
Class="mb-3" Class="mb-3"
@@ -59,22 +59,22 @@
<MudGrid Class="mb-3"> <MudGrid Class="mb-3">
<MudItem xs="12" sm="6" md="4"> <MudItem xs="12" sm="6" md="4">
<MudTextField T="string" Value="@this.recClarityDirectness" Label="@T("Be clear and direct")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" AutoGrow="@true" /> <MudTextField T="string" Value="@this.recClarityDirectness" Label="@T("Be clear and direct")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
</MudItem> </MudItem>
<MudItem xs="12" sm="6" md="4"> <MudItem xs="12" sm="6" md="4">
<MudTextField T="string" Value="@this.recExamplesContext" Label="@T("Add examples and context")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" AutoGrow="@true" /> <MudTextField T="string" Value="@this.recExamplesContext" Label="@T("Add examples and context")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
</MudItem> </MudItem>
<MudItem xs="12" sm="6" md="4"> <MudItem xs="12" sm="6" md="4">
<MudTextField T="string" Value="@this.recSequentialSteps" Label="@T("Use sequential steps")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" AutoGrow="@true" /> <MudTextField T="string" Value="@this.recSequentialSteps" Label="@T("Use sequential steps")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
</MudItem> </MudItem>
<MudItem xs="12" sm="6" md="4"> <MudItem xs="12" sm="6" md="4">
<MudTextField T="string" Value="@this.recStructureMarkers" Label="@T("Structure with markers")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" AutoGrow="@true" /> <MudTextField T="string" Value="@this.recStructureMarkers" Label="@T("Structure with markers")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
</MudItem> </MudItem>
<MudItem xs="12" sm="6" md="4"> <MudItem xs="12" sm="6" md="4">
<MudTextField T="string" Value="@this.recRoleDefinition" Label="@T("Give the model a role")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" AutoGrow="@true" /> <MudTextField T="string" Value="@this.recRoleDefinition" Label="@T("Give the model a role")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
</MudItem> </MudItem>
<MudItem xs="12" sm="6" md="4"> <MudItem xs="12" sm="6" md="4">
<MudTextField T="string" Value="@this.recLanguageChoice" Label="@T("Choose prompt language deliberately")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" AutoGrow="@true" /> <MudTextField T="string" Value="@this.recLanguageChoice" Label="@T("Choose prompt language deliberately")" ReadOnly="true" Variant="Variant.Outlined" Lines="2" Sizing="InputSizing.Auto" />
</MudItem> </MudItem>
</MudGrid> </MudGrid>
} }
@@ -290,7 +290,7 @@ public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialog
private async Task OptimizePromptAsync() private async Task OptimizePromptAsync()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -2,7 +2,7 @@
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogRewrite> @inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogRewrite>
<ReadFileContent Text="@T("Load text from file")" @bind-FileContent="@this.inputText" EnableDragDrop="true" CatchAllDocuments="true"/> <ReadFileContent Text="@T("Load text from file")" @bind-FileContent="@this.inputText" EnableDragDrop="true" CatchAllDocuments="true"/>
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidateText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Your input to improve")" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidateText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Your input to improve")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="@T("Language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom language")" /> <EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="@T("Language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom language")" />
<EnumSelection T="WritingStyles" NameFunc="@(style => style.Name())" @bind-Value="@this.selectedWritingStyle" Icon="@Icons.Material.Filled.Edit" Label="@T("Writing style")" AllowOther="@false" /> <EnumSelection T="WritingStyles" NameFunc="@(style => style.Name())" @bind-Value="@this.selectedWritingStyle" Icon="@Icons.Material.Filled.Edit" Label="@T("Writing style")" AllowOther="@false" />
<EnumSelection T="SentenceStructure" NameFunc="@(voice => voice.Name())" @bind-Value="@this.selectedSentenceStructure" Icon="@Icons.Material.Filled.Person4" Label="@T("Sentence structure")" /> <EnumSelection T="SentenceStructure" NameFunc="@(voice => voice.Name())" @bind-Value="@this.selectedSentenceStructure" Icon="@Icons.Material.Filled.Person4" Label="@T("Sentence structure")" />
@@ -148,7 +148,7 @@ public partial class AssistantRewriteImprove : AssistantBaseCore<SettingsDialogR
private async Task RewriteText() private async Task RewriteText()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -20,7 +20,7 @@ public partial class AssistantSWOTAnalysis
/// </remarks> /// </remarks>
private async Task AnalyzeText() private async Task AnalyzeText()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -14,15 +14,15 @@
<MudText Typo="Typo.h5" Class="mb-3"> <MudText Typo="Typo.h5" Class="mb-3">
@T("Input") @T("Input")
</MudText> </MudText>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Subject of analysis")" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Subject of analysis")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<ReadFileContent @bind-FileContent="@this.inputText" MediaImportTargetId="swot-analysis-subject" EnableDragDrop="true" CatchAllDocuments="true"/> <ReadFileContent @bind-FileContent="@this.inputText" MediaImportTargetId="swot-analysis-subject" EnableDragDrop="true" CatchAllDocuments="true"/>
<MudText Typo="Typo.h5" Class="mb-3 mt-6"> <MudText Typo="Typo.h5" Class="mb-3 mt-6">
@T("Analysis Options") @T("Analysis Options")
</MudText> </MudText>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.analysisGoal" Validation="@this.ValidatingAnalysisGoal" AdornmentIcon="@Icons.Material.Filled.TrackChanges" Adornment="Adornment.Start" Label="@T("Analysis goal")" Variant="Variant.Outlined" Lines="4" AutoGrow="@true" Class="mb-3"/> <MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.analysisGoal" Validation="@this.ValidatingAnalysisGoal" AdornmentIcon="@Icons.Material.Filled.TrackChanges" Adornment="Adornment.Start" Label="@T("Analysis goal")" Variant="Variant.Outlined" Lines="4" Sizing="InputSizing.Auto" Class="mb-3"/>
<ReadFileContent @bind-FileContent="@this.analysisGoal" MediaImportTargetId="swot-analysis-goal" EnableDragDrop="true"/> <ReadFileContent @bind-FileContent="@this.analysisGoal" MediaImportTargetId="swot-analysis-goal" EnableDragDrop="true"/>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.importantAspects" AdornmentIcon="@Icons.Material.Filled.List" Adornment="Adornment.Start" Label="@T("(Optional) Analysis focus")" HelperText="@T("Specify topics the SWOT analysis should pay particular attention to.")" Variant="Variant.Outlined" Lines="4" AutoGrow="@true" Class="mb-3"/> <MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.importantAspects" AdornmentIcon="@Icons.Material.Filled.List" Adornment="Adornment.Start" Label="@T("(Optional) Analysis focus")" HelperText="@T("Specify topics the SWOT analysis should pay particular attention to.")" Variant="Variant.Outlined" Lines="4" Sizing="InputSizing.Auto" Class="mb-3"/>
<ReadFileContent @bind-FileContent="@this.importantAspects" MediaImportTargetId="swot-analysis-focus" EnableDragDrop="true"/> <ReadFileContent @bind-FileContent="@this.importantAspects" MediaImportTargetId="swot-analysis-focus" EnableDragDrop="true"/>
<MudText Typo="Typo.h5" Class="mb-3 mt-6"> <MudText Typo="Typo.h5" Class="mb-3 mt-6">
@@ -8,7 +8,7 @@
<MudJustifiedText Typo="Typo.body1" Class="mb-2"> <MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("You can enter text, use one or more documents or images, or use both. At least one of these options is required.") @T("You can enter text, use one or more documents or images, or use both. At least one of these options is required.")
</MudJustifiedText> </MudJustifiedText>
<MudTextField T="string" @bind-Text="@this.inputContent" Validation="@this.ValidatingContext" Adornment="Adornment.Start" Lines="6" MaxLines="12" AutoGrow="@false" Label="@T("Text content")" Variant="Variant.Outlined" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.inputContent" Validation="@this.ValidatingContext" Adornment="Adornment.Start" Lines="6" MaxLines="12" Sizing="InputSizing.Fixed" Label="@T("Text content")" Variant="Variant.Outlined" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
@* Side by side where the window is wide enough; each column ends with its zone, so both zones line up below explanations of different length: *@ @* Side by side where the window is wide enough; each column ends with its zone, so both zones line up below explanations of different length: *@
<MudGrid Class="mt-1"> <MudGrid Class="mt-1">
@@ -60,7 +60,7 @@
<MudJustifiedText Typo="Typo.body1" Class="mb-2"> <MudJustifiedText Typo="Typo.body1" Class="mb-2">
@T("You might want to specify important aspects that the LLM should consider when creating the slides. For example, the use of emojis or specific topics that should be highlighted.") @T("You might want to specify important aspects that the LLM should consider when creating the slides. For example, the use of emojis or specific topics that should be highlighted.")
</MudJustifiedText> </MudJustifiedText>
<MudTextField T="string" AutoGrow="true" Lines="3" @bind-Text="@this.importantAspects" class="mb-1" Label="@T("(Optional) Important Aspects")" ShrinkLabel="true" Variant="Variant.Outlined" AdornmentIcon="@Icons.Material.Filled.List" Adornment="Adornment.Start" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" Sizing="InputSizing.Auto" Lines="3" @bind-Text="@this.importantAspects" class="mb-1" Label="@T("(Optional) Important Aspects")" ShrinkLabel="true" Variant="Variant.Outlined" AdornmentIcon="@Icons.Material.Filled.List" Adornment="Adornment.Start" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudText Typo="Typo.h6" Class="mb-1 mt-3"> @T("Extent of the planned presentation")</MudText> <MudText Typo="Typo.h6" Class="mb-1 mt-3"> @T("Extent of the planned presentation")</MudText>
<MudJustifiedText Typo="Typo.body1" Class="mb-2"> <MudJustifiedText Typo="Typo.body1" Class="mb-2">
@@ -69,7 +69,7 @@ public partial class SlideAssistant
this.pictureLibraryPath = path; this.pictureLibraryPath = path;
await this.ReadPictureLibraryOverviewAsync(); await this.ReadPictureLibraryOverviewAsync();
if (this.Form is not null) if (this.Form is not null)
await this.Form.Validate(); await this.Form.ValidateAsync();
} }
private async Task UseNoPictureLibrary() => await this.OnPictureLibraryChanged(string.Empty); private async Task UseNoPictureLibrary() => await this.OnPictureLibraryChanged(string.Empty);
@@ -245,7 +245,7 @@ public partial class SlideAssistant
this.LoadTemplate(); this.LoadTemplate();
this.ApplyPreselectedTemplateSlideUses(); this.ApplyPreselectedTemplateSlideUses();
if (this.Form is not null) if (this.Form is not null)
await this.Form.Validate(); await this.Form.ValidateAsync();
} }
/// <summary> /// <summary>
@@ -299,9 +299,9 @@ public partial class SlideAssistant
/// <returns>The name, or empty when the LLM decides, which it also does when the template has no layout of this name.</returns> /// <returns>The name, or empty when the LLM decides, which it also does when the template has no layout of this name.</returns>
private string LayoutNameOf(LayoutPurpose purpose) => this.template is not null && this.layoutNames.TryGetValue(purpose, out var name) && this.template.FindFamilyByName(name) is not null ? name : string.Empty; private string LayoutNameOf(LayoutPurpose purpose) => this.template is not null && this.layoutNames.TryGetValue(purpose, out var name) && this.template.FindFamilyByName(name) is not null ? name : string.Empty;
private void SetLayoutName(LayoutPurpose purpose, string name) private void SetLayoutName(LayoutPurpose purpose, string? name)
{ {
if (name.Length == 0) if (string.IsNullOrEmpty(name))
this.layoutNames.Remove(purpose); this.layoutNames.Remove(purpose);
else else
this.layoutNames[purpose] = name; this.layoutNames[purpose] = name;
@@ -427,14 +427,14 @@ public partial class SlideAssistant : AssistantBaseCore<SettingsDialogSlideBuild
{ {
await this.KeepSlidePicturesOutOfDocumentsAsync(); await this.KeepSlidePicturesOutOfDocumentsAsync();
if(this.Form is not null) if(this.Form is not null)
await this.Form.Validate(); await this.Form.ValidateAsync();
} }
private async Task OnSlidePicturesChanged(HashSet<FileAttachment> _) private async Task OnSlidePicturesChanged(HashSet<FileAttachment> _)
{ {
await this.KeepSlidePicturesOutOfDocumentsAsync(); await this.KeepSlidePicturesOutOfDocumentsAsync();
if(this.Form is not null) if(this.Form is not null)
await this.Form.Validate(); await this.Form.ValidateAsync();
} }
/// <summary> /// <summary>
@@ -622,7 +622,7 @@ public partial class SlideAssistant : AssistantBaseCore<SettingsDialogSlideBuild
private async Task CreateSlideBuilder() private async Task CreateSlideBuilder()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -2,7 +2,7 @@
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogSynonyms> @inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogSynonyms>
<MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.Spellcheck" Adornment="Adornment.Start" Label="@T("Your word or phrase")" Variant="Variant.Outlined" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.Spellcheck" Adornment="Adornment.Start" Label="@T("Your word or phrase")" Variant="Variant.Outlined" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<MudTextField T="string" @bind-Text="@this.inputContext" AdornmentIcon="@Icons.Material.Filled.Description" Adornment="Adornment.Start" Lines="2" AutoGrow="@false" Label="@T("(Optional) The context for the given word or phrase")" Variant="Variant.Outlined" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.inputContext" AdornmentIcon="@Icons.Material.Filled.Description" Adornment="Adornment.Start" Lines="2" Sizing="InputSizing.Fixed" Label="@T("(Optional) The context for the given word or phrase")" Variant="Variant.Outlined" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedLanguage" Icon="@Icons.Material.Filled.Translate" Label="@T("Language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom target language")" /> <EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelectingOptional())" @bind-Value="@this.selectedLanguage" Icon="@Icons.Material.Filled.Translate" Label="@T("Language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom target language")" />
<ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/> <ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/>
@@ -183,7 +183,7 @@ public partial class AssistantSynonyms : AssistantBaseCore<SettingsDialogSynonym
private async Task FindSynonyms() private async Task FindSynonyms()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -7,8 +7,8 @@
} }
<ReadFileContent @bind-FileContent="@this.inputText" EnableDragDrop="true" CatchAllDocuments="true"/> <ReadFileContent @bind-FileContent="@this.inputText" EnableDragDrop="true" CatchAllDocuments="true"/>
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Your input")" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Your input")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.Name())" @bind-Value="@this.selectedTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="@T("Target language")" AllowOther="@true" @bind-OtherInput="@this.customTargetLanguage" OtherValue="CommonLanguages.OTHER" LabelOther="@T("Custom target language")" ValidateOther="@this.ValidateCustomLanguage" /> <EnumSelection T="CommonLanguages" NameFunc="@(language => language.Name())" @bind-Value="@this.selectedTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="@T("Target language")" AllowOther="@true" @bind-OtherInput="@this.customTargetLanguage" OtherValue="CommonLanguages.OTHER" LabelOther="@T("Custom target language")" ValidateOther="@this.ValidateCustomLanguage" />
<EnumSelection T="Complexity" NameFunc="@(complexity => complexity.Name())" @bind-Value="@this.selectedComplexity" Icon="@Icons.Material.Filled.Layers" Label="@T("Target complexity")" AllowOther="@true" @bind-OtherInput="@this.expertInField" OtherValue="Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS" LabelOther="@T("Your expertise")" ValidateOther="@this.ValidateExpertInField" /> <EnumSelection T="Complexity" NameFunc="@(complexity => complexity.Name())" @bind-Value="@this.selectedComplexity" Icon="@Icons.Material.Filled.Layers" Label="@T("Target complexity")" AllowOther="@true" @bind-OtherInput="@this.expertInField" OtherValue="Complexity.SCIENTIFIC_LANGUAGE_OTHER_EXPERTS" LabelOther="@T("Your expertise")" ValidateOther="@this.ValidateExpertInField" />
<MudTextField T="string" AutoGrow="true" Lines="2" @bind-Text="@this.importantAspects" class="mb-3" Label="@T("(Optional) Important Aspects")" HelperText="@T("(Optional) Specify aspects for the LLM to focus on when generating a summary, such as summary length or specific topics to emphasize.")" ShrinkLabel="true" Variant="Variant.Outlined" AdornmentIcon="@Icons.Material.Filled.List" Adornment="Adornment.Start"/> <MudTextField T="string" Sizing="InputSizing.Auto" Lines="2" @bind-Text="@this.importantAspects" class="mb-3" Label="@T("(Optional) Important Aspects")" HelperText="@T("(Optional) Specify aspects for the LLM to focus on when generating a summary, such as summary length or specific topics to emphasize.")" ShrinkLabel="true" Variant="Variant.Outlined" AdornmentIcon="@Icons.Material.Filled.List" Adornment="Adornment.Start"/>
<ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/> <ProviderSelection @bind-ProviderSettings="@this.ProviderSettings" ValidateProvider="@this.ValidatingProvider"/>
@@ -160,7 +160,7 @@ public partial class AssistantTextSummarizer : AssistantBaseCore<SettingsDialogT
private async Task SummarizeText() private async Task SummarizeText()
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -15,7 +15,7 @@
} }
else else
{ {
<MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Your input")" Variant="Variant.Outlined" Lines="6" AutoGrow="@true" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" Disabled="@this.isAgentRunning" @bind-Text="@this.inputText" Validation="@this.ValidatingText" AdornmentIcon="@Icons.Material.Filled.DocumentScanner" Adornment="Adornment.Start" Label="@T("Your input")" Variant="Variant.Outlined" Lines="6" Sizing="InputSizing.Auto" MaxLines="12" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
} }
<EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelecting())" @bind-Value="@this.selectedTargetLanguage" ValidateSelection="@this.ValidatingTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="@T("Target language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom target language")" /> <EnumSelection T="CommonLanguages" NameFunc="@(language => language.NameSelecting())" @bind-Value="@this.selectedTargetLanguage" ValidateSelection="@this.ValidatingTargetLanguage" Icon="@Icons.Material.Filled.Translate" Label="@T("Target language")" AllowOther="@true" OtherValue="CommonLanguages.OTHER" @bind-OtherInput="@this.customTargetLanguage" ValidateOther="@this.ValidateCustomLanguage" LabelOther="@T("Custom target language")" />
@@ -153,7 +153,7 @@ public partial class AssistantTranslation : AssistantBaseCore<SettingsDialogTran
private async Task TranslateText(bool force) private async Task TranslateText(bool force)
{ {
await this.Form!.Validate(); await this.Form!.ValidateAsync();
if (!this.InputIsValid) if (!this.InputIsValid)
return; return;
@@ -104,7 +104,7 @@
<MudTextField T="string" @bind-Text="@this.editor.Author" Label="@T("Author (optional)")" Variant="Variant.Outlined" Disabled="@this.IsCurrentBusy" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.editor.Author" Label="@T("Author (optional)")" Variant="Variant.Outlined" Disabled="@this.IsCurrentBusy" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
</MudItem> </MudItem>
</MudGrid> </MudGrid>
<MudTextField T="string" @bind-Text="@this.editor.Instruction" Label="@T("Briefing scope, notes, or current change instruction (optional)")" Variant="Variant.Outlined" AutoGrow="true" Lines="3" Class="mt-3" Disabled="@this.IsCurrentBusy" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.editor.Instruction" Label="@T("Briefing scope, notes, or current change instruction (optional)")" Variant="Variant.Outlined" Sizing="InputSizing.Auto" Lines="3" Class="mt-3" Disabled="@this.IsCurrentBusy" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
<EnumSelection T="VisualBriefingProtectionLevel" <EnumSelection T="VisualBriefingProtectionLevel"
NameFunc="@this.ProtectionLevelName" NameFunc="@this.ProtectionLevelName"
@@ -37,7 +37,7 @@ public partial class VisualBriefingAssistant
if (selected is not null) if (selected is not null)
await this.ApplySelectedProjectAsync(selected); await this.ApplySelectedProjectAsync(selected);
else else
this.ClearSelectedProject(); await this.ClearSelectedProjectAsync();
} }
/// <summary> /// <summary>
@@ -150,7 +150,7 @@ public partial class VisualBriefingAssistant
this.BuildOrchestrator.ForgetBriefing(id); this.BuildOrchestrator.ForgetBriefing(id);
this.BuildProgressService.Forget(id); this.BuildProgressService.Forget(id);
this.ClearSelectedProject(); await this.ClearSelectedProjectAsync();
await this.ReloadListAsync(); await this.ReloadListAsync();
} }
@@ -296,14 +296,14 @@ public partial class VisualBriefingAssistant
} }
await this.Store.RememberSelectionAsync(project.BriefingId); await this.Store.RememberSelectionAsync(project.BriefingId);
this.ClearSelectedProject(); await this.ClearSelectedProjectAsync();
this.selectedProject = project; this.selectedProject = project;
} }
/// <summary> /// <summary>
/// Clears editor-only state so an unavailable project cannot trigger saves or background work. /// Clears editor-only state so an unavailable project cannot trigger saves or background work.
/// </summary> /// </summary>
private void ClearSelectedProject() private async Task ClearSelectedProjectAsync()
{ {
this.selectedProject = null; this.selectedProject = null;
this.selectedBriefing = null; this.selectedBriefing = null;
@@ -316,7 +316,8 @@ public partial class VisualBriefingAssistant
this.lastPersistedState = string.Empty; this.lastPersistedState = string.Empty;
this.formIssues = []; this.formIssues = [];
this.formValidationPending = false; this.formValidationPending = false;
this.visualBriefingForm?.ResetValidation(); if (this.visualBriefingForm is not null)
await this.visualBriefingForm.ResetValidationAsync();
} }
/// <summary> /// <summary>
@@ -203,7 +203,7 @@ public partial class VisualBriefingAssistant : MSGComponentBase
if (this.formValidationPending && this.visualBriefingForm is not null) if (this.formValidationPending && this.visualBriefingForm is not null)
{ {
this.formValidationPending = false; this.formValidationPending = false;
await this.visualBriefingForm.Validate(); await this.visualBriefingForm.ValidateAsync();
} }
if (this.selectedBriefing is null || this.IsCurrentBusy) if (this.selectedBriefing is null || this.IsCurrentBusy)
@@ -865,7 +865,7 @@ public partial class ContentBlockComponent : MSGComponentBase
if (this.RemoveBlockFunc is null || !this.BlockActionsEnabled()) if (this.RemoveBlockFunc is null || !this.BlockActionsEnabled())
return; return;
var remove = await this.DialogService.ShowMessageBox( var remove = await this.DialogService.ShowMessageBoxAsync(
T("Remove Message"), T("Remove Message"),
T("Do you really want to remove this message?"), T("Do you really want to remove this message?"),
T("Yes, remove it"), T("Yes, remove it"),
@@ -947,7 +947,7 @@ public partial class ContentBlockComponent : MSGComponentBase
if(this.Role is not ChatRole.AI) if(this.Role is not ChatRole.AI)
return; return;
var regenerate = await this.DialogService.ShowMessageBox( var regenerate = await this.DialogService.ShowMessageBoxAsync(
T("Regenerate Message"), T("Regenerate Message"),
T("Do you really want to regenerate this message?"), T("Do you really want to regenerate this message?"),
T("Yes, regenerate it"), T("Yes, regenerate it"),
@@ -962,7 +962,7 @@ public partial class ContentBlockComponent : MSGComponentBase
if (this.RollbackFunc is null || this.Role is not ChatRole.AI || !this.BlockActionsEnabled()) if (this.RollbackFunc is null || this.Role is not ChatRole.AI || !this.BlockActionsEnabled())
return; return;
var rollback = await this.DialogService.ShowMessageBox( var rollback = await this.DialogService.ShowMessageBoxAsync(
T("Roll Back Chat"), T("Roll Back Chat"),
T("Do you really want to roll back this chat to this AI response? All later messages and their attachments will be permanently removed."), T("Do you really want to roll back this chat to this AI response? All later messages and their attachments will be permanently removed."),
T("Yes, roll back the chat"), T("Yes, roll back the chat"),
@@ -991,7 +991,7 @@ public partial class ContentBlockComponent : MSGComponentBase
if(this.Role is not ChatRole.USER) if(this.Role is not ChatRole.USER)
return; return;
var edit = await this.DialogService.ShowMessageBox( var edit = await this.DialogService.ShowMessageBoxAsync(
T("Edit Message"), T("Edit Message"),
T("Do you really want to edit this message? In order to edit this message, the AI response will be deleted."), T("Do you really want to edit this message? In order to edit this message, the AI response will be deleted."),
T("Yes, remove the AI response and edit it"), T("Yes, remove the AI response and edit it"),
@@ -46,7 +46,7 @@
@ref="@this.inputField" @ref="@this.inputField"
@bind-Text="@this.UserInput" @bind-Text="@this.UserInput"
Variant="Variant.Outlined" Variant="Variant.Outlined"
AutoGrow="@true" Sizing="InputSizing.Auto"
Lines="3" Lines="3"
MaxLines="12" MaxLines="12"
Label="@this.InputLabel" Label="@this.InputLabel"
@@ -6,13 +6,13 @@
<ActivatorContent> <ActivatorContent>
@if (this.CurrentChatTemplate != ChatTemplate.NO_CHAT_TEMPLATE) @if (this.CurrentChatTemplate != ChatTemplate.NO_CHAT_TEMPLATE)
{ {
<MudButton IconSize="Size.Large" StartIcon="@this.ChatTemplateIcon(this.CurrentChatTemplate)" IconColor="Color.Default"> <MudButton IconSize="Size.Large" StartIcon="@this.ChatTemplateIcon(this.CurrentChatTemplate)" IconColor="Color.Default" OnClick="@context.ToggleAsync">
@this.CurrentChatTemplate.GetSafeName() @this.CurrentChatTemplate.GetSafeName()
</MudButton> </MudButton>
} }
else else
{ {
<MudIconButton Icon="@Icons.Material.Filled.RateReview" /> <MudIconButton Icon="@Icons.Material.Filled.RateReview" OnClick="@context.ToggleAsync" />
} }
</ActivatorContent> </ActivatorContent>
<ChildContent> <ChildContent>
@@ -1,4 +1,4 @@
<MudTabs ActivePanelIndex="this.SelectedIndex" ActivePanelIndexChanged="async idx => await this.TabChanged(idx)" PanelClass="code-block mt-1" MinimumTabWidth="30px" Class="mt-2"> <MudTabs ActivePanelIndex="this.SelectedIndex" ActivePanelIndexChanged="async idx => await this.TabChanged(idx)" TabPanelsClass="code-block mt-1" MinimumTabWidth="30px" Class="mt-2">
@foreach (var block in this.blocks) @foreach (var block in this.blocks)
{ {
<MudTabPanel Text="@block.Title"> <MudTabPanel Text="@block.Title">
@@ -79,10 +79,10 @@ public partial class ConfigurationDirectory : ConfigurationBaseCore
#endregion #endregion
private void InternalUpdate(string text) private void InternalUpdate(string? text)
{ {
this.timer.Stop(); this.timer.Stop();
this.internalText = text; this.internalText = text ?? string.Empty;
this.timer.Start(); this.timer.Start();
} }
@@ -85,10 +85,10 @@ public partial class ConfigurationFile : ConfigurationBaseCore
#endregion #endregion
private void InternalUpdate(string text) private void InternalUpdate(string? text)
{ {
this.timer.Stop(); this.timer.Stop();
this.internalText = text; this.internalText = text ?? string.Empty;
this.timer.Start(); this.timer.Start();
} }
@@ -53,8 +53,12 @@ public partial class ConfigurationSelect<TConfig> : ConfigurationBaseCore
#endregion #endregion
private async Task OptionChanged(TConfig updatedValue) private async Task OptionChanged(TConfig? updatedValue)
{ {
// The select hands out null only when it has no value at all, which leaves nothing to store:
if (updatedValue is null)
return;
this.SelectionUpdate(updatedValue); this.SelectionUpdate(updatedValue);
await this.SelectionUpdateAsync(updatedValue); await this.SelectionUpdateAsync(updatedValue);
await this.SettingsManager.StoreSettings(); await this.SettingsManager.StoreSettings();
@@ -12,7 +12,7 @@
AdornmentColor="@this.IconColor" AdornmentColor="@this.IconColor"
UserAttributes="@SPELLCHECK_ATTRIBUTES" UserAttributes="@SPELLCHECK_ATTRIBUTES"
Lines="@this.NumLines" Lines="@this.NumLines"
AutoGrow="@this.AutoGrow" Sizing="@this.Sizing"
MaxLines="@this.GetMaxLines" MaxLines="@this.GetMaxLines"
Class="@this.InputClass" Class="@this.InputClass"
Immediate="@true" Immediate="@true"
@@ -36,7 +36,7 @@ else
AdornmentColor="@this.IconColor" AdornmentColor="@this.IconColor"
UserAttributes="@SPELLCHECK_ATTRIBUTES" UserAttributes="@SPELLCHECK_ATTRIBUTES"
Lines="@this.NumLines" Lines="@this.NumLines"
AutoGrow="@this.AutoGrow" Sizing="@this.Sizing"
MaxLines="@this.GetMaxLines" MaxLines="@this.GetMaxLines"
Class="@this.InputClass" Class="@this.InputClass"
Immediate="@true" Immediate="@true"
@@ -129,6 +129,8 @@ public partial class ConfigurationText : ConfigurationBaseCore
private bool AutoGrow => this.ExpandToContent || this.NumLines > 1; private bool AutoGrow => this.ExpandToContent || this.NumLines > 1;
private InputSizing Sizing => this.AutoGrow ? InputSizing.Auto : InputSizing.Fixed;
private int GetMaxLines => this.ExpandToContent ? FilePatternSelection.MAX_FIELD_LINES : this.AutoGrow ? this.MaxLines : 1; private int GetMaxLines => this.ExpandToContent ? FilePatternSelection.MAX_FIELD_LINES : this.AutoGrow ? this.MaxLines : 1;
private string InputClass => this.ExpandToContent ? "pattern-text-field" : string.Empty; private string InputClass => this.ExpandToContent ? "pattern-text-field" : string.Empty;
@@ -139,13 +141,13 @@ public partial class ConfigurationText : ConfigurationBaseCore
// //
private Adornment IconAdornment => this.NumLines == 1 ? Adornment.Start : Adornment.None; private Adornment IconAdornment => this.NumLines == 1 ? Adornment.Start : Adornment.None;
protected void InternalUpdate(string text) protected void InternalUpdate(string? text)
{ {
if (this.IsDisabled) if (this.IsDisabled)
return; return;
this.timer.Stop(); this.timer.Stop();
this.internalText = text; this.internalText = text ?? string.Empty;
this.timer.Start(); this.timer.Start();
} }
@@ -1,7 +1,7 @@
@using AIStudio.Tools.ChatArchive @using AIStudio.Tools.ChatArchive
@inherits MSGComponentBase @inherits MSGComponentBase
<MudTabs Elevation="0" Rounded="@true" ApplyEffectsToContainer="@true" Outlined="@true" PanelClass="pa-4"> <MudTabs Elevation="0" Rounded="@true" ApplyEffectsToContainer="@true" Outlined="@true" TabPanelsClass="pa-4">
<MudTabPanel Text="@T("Back up")" Icon="@Icons.Material.Filled.Archive" Disabled="@(this.isBusy || this.DataRestoreService.IsPreparing)"> <MudTabPanel Text="@T("Back up")" Icon="@Icons.Material.Filled.Archive" Disabled="@(this.isBusy || this.DataRestoreService.IsPreparing)">
<MudText Typo="Typo.body1" Class="mb-3"> <MudText Typo="Typo.body1" Class="mb-3">
@@ -206,7 +206,7 @@ public partial class DataSourceManagement : MSGComponentBase
if (eriDataSource.AuthMethod is AuthMethod.KERBEROS) if (eriDataSource.AuthMethod is AuthMethod.KERBEROS)
{ {
await this.DialogService.ShowMessageBox( await this.DialogService.ShowMessageBoxAsync(
T("Export ERI Data Source"), T("Export ERI Data Source"),
T("Kerberos/SSO ERI data sources cannot be exported yet. Please configure them manually in the configuration plugin."), T("Kerberos/SSO ERI data sources cannot be exported yet. Please configure them manually in the configuration plugin."),
T("Close")); T("Close"));
@@ -226,7 +226,7 @@ public partial class DataSourceManagement : MSGComponentBase
var secretResponse = await this.RustService.GetSecret(eriDataSource, SecretStoreType.DATA_SOURCE, isTrying: true); var secretResponse = await this.RustService.GetSecret(eriDataSource, SecretStoreType.DATA_SOURCE, isTrying: true);
if (!secretResponse.Success) if (!secretResponse.Success)
{ {
await this.DialogService.ShowMessageBox( await this.DialogService.ShowMessageBoxAsync(
T("Export ERI Data Source"), T("Export ERI Data Source"),
string.Format(T("Cannot export this ERI data source because no authentication secret is configured. The issue was: {0}"), secretResponse.Issue), string.Format(T("Cannot export this ERI data source because no authentication secret is configured. The issue was: {0}"), secretResponse.Issue),
T("Close")); T("Close"));
@@ -236,7 +236,7 @@ public partial class DataSourceManagement : MSGComponentBase
var encryption = PluginFactory.EnterpriseEncryption; var encryption = PluginFactory.EnterpriseEncryption;
if (encryption?.IsAvailable != true) if (encryption?.IsAvailable != true)
{ {
await this.DialogService.ShowMessageBox( await this.DialogService.ShowMessageBoxAsync(
T("Export ERI Data Source"), T("Export ERI Data Source"),
T("Cannot export this ERI data source because no enterprise encryption secret is configured."), T("Cannot export this ERI data source because no enterprise encryption secret is configured."),
T("Close")); T("Close"));
@@ -274,7 +274,7 @@ public partial class DataSourceManagement : MSGComponentBase
var decryptedSecret = await secretResponse.Secret.Decrypt(Program.ENCRYPTION); var decryptedSecret = await secretResponse.Secret.Decrypt(Program.ENCRYPTION);
if (!encryption.TryEncrypt(decryptedSecret, this.SettingsManager.ConfigurationData.App.EnterpriseEncryptionExportFormat, out var encryptedSecret)) if (!encryption.TryEncrypt(decryptedSecret, this.SettingsManager.ConfigurationData.App.EnterpriseEncryptionExportFormat, out var encryptedSecret))
{ {
await this.DialogService.ShowMessageBox( await this.DialogService.ShowMessageBoxAsync(
T("Export ERI Data Source"), T("Export ERI Data Source"),
T("Cannot export this ERI data source because the authentication secret could not be encrypted."), T("Cannot export this ERI data source because the authentication secret could not be encrypted."),
T("Close")); T("Close"));
@@ -353,7 +353,7 @@ public partial class DataSourceManagement : MSGComponentBase
if (!this.DataSourceEmbeddingService.IsIndexingPaused) if (!this.DataSourceEmbeddingService.IsIndexingPaused)
return false; return false;
await this.DialogService.ShowMessageBox(title, T("AI Studio is backing up or restoring the indexes of your data sources right now. Please try again once that is done."), T("Close")); await this.DialogService.ShowMessageBoxAsync(title, T("AI Studio is backing up or restoring the indexes of your data sources right now. Please try again once that is done."), T("Close"));
return true; return true;
} }
@@ -413,7 +413,7 @@ public partial class DataSourceManagement : MSGComponentBase
var deleteSecretResponse = await this.RustService.DeleteSecret(mailbox, SecretStoreType.DATA_SOURCE); var deleteSecretResponse = await this.RustService.DeleteSecret(mailbox, SecretStoreType.DATA_SOURCE);
if (!deleteSecretResponse.Success) if (!deleteSecretResponse.Success)
{ {
await this.DialogService.ShowMessageBox( await this.DialogService.ShowMessageBoxAsync(
T("Delete Mailbox"), T("Delete Mailbox"),
string.Format(T("The password of this mailbox could not be deleted from the operating system, so the mailbox was kept. The issue was: {0}"), deleteSecretResponse.Issue), string.Format(T("The password of this mailbox could not be deleted from the operating system, so the mailbox was kept. The issue was: {0}"), deleteSecretResponse.Issue),
T("Close")); T("Close"));
@@ -1,3 +1,3 @@
@inherits MudComponentBase @inherits MudComponentBase
<MudTextField T="string" Disabled="@this.Disabled" Text="@this.text" TextChanged="@this.OnTextChanged" Validation="@this.ValidationFunc" Label="@this.Label" Variant="Variant.Outlined" Lines="@this.Lines" MaxLines="@this.MaxLines" AutoGrow="@(this.MaxLines > this.Lines)" Margin="Margin.Dense" UserAttributes="@this.Attributes" HelperText="@this.HelpText" Placeholder="@this.Placeholder" Class="mb-3" Immediate="true" Adornment="Adornment.Start" AdornmentIcon="@this.Icon"/> <MudTextField T="string" Disabled="@this.Disabled" Text="@this.text" TextChanged="@this.OnTextChanged" Validation="@this.ValidationFunc" Label="@this.Label" Variant="Variant.Outlined" Lines="@this.Lines" MaxLines="@this.MaxLines" Sizing="@(this.MaxLines > this.Lines ? InputSizing.Auto : InputSizing.Fixed)" Margin="Margin.Dense" UserAttributes="@this.Attributes" HelperText="@this.HelpText" Placeholder="@this.Placeholder" Class="mb-3" Immediate="true" Adornment="Adornment.Start" AdornmentIcon="@this.Icon"/>
@@ -97,9 +97,9 @@ public partial class DebouncedTextField : MudComponentBase, IDisposable
#endregion #endregion
private void OnTextChanged(string value) private void OnTextChanged(string? value)
{ {
this.text = value; this.text = value ?? string.Empty;
this.debounceTimer.Stop(); this.debounceTimer.Stop();
this.debounceTimer.Start(); this.debounceTimer.Start();
} }
@@ -60,10 +60,10 @@ public partial class DirectChatLauncherForm : MSGComponentBase
/// The data sources the chat starts with. An empty selection keeps the normal chat defaults. /// The data sources the chat starts with. An empty selection keeps the normal chat defaults.
/// </summary> /// </summary>
[Parameter] [Parameter]
public IEnumerable<string> DataSourceIds { get; set; } = []; public IReadOnlyCollection<string> DataSourceIds { get; set; } = [];
[Parameter] [Parameter]
public EventCallback<IEnumerable<string>> DataSourceIdsChanged { get; set; } public EventCallback<IReadOnlyCollection<string>> DataSourceIdsChanged { get; set; }
/// <summary> /// <summary>
/// The tools preselected for the chat. An empty selection keeps the normal chat defaults. /// The tools preselected for the chat. An empty selection keeps the normal chat defaults.
@@ -102,29 +102,29 @@ public partial class DirectChatLauncherForm : MSGComponentBase
await this.WorkspaceNameChanged.InvokeAsync(workspaceName); await this.WorkspaceNameChanged.InvokeAsync(workspaceName);
} }
private async Task SetProviderId(string providerId) private async Task SetProviderId(string? providerId)
{ {
this.ProviderId = providerId; this.ProviderId = providerId ?? string.Empty;
await this.ProviderIdChanged.InvokeAsync(providerId); await this.ProviderIdChanged.InvokeAsync(this.ProviderId);
} }
private async Task SetProfileId(string profileId) private async Task SetProfileId(string? profileId)
{ {
this.ProfileId = profileId; this.ProfileId = profileId ?? string.Empty;
await this.ProfileIdChanged.InvokeAsync(profileId); await this.ProfileIdChanged.InvokeAsync(this.ProfileId);
} }
private async Task SetChatTemplateId(string chatTemplateId) private async Task SetChatTemplateId(string? chatTemplateId)
{ {
this.ChatTemplateId = chatTemplateId; this.ChatTemplateId = chatTemplateId ?? string.Empty;
await this.ChatTemplateIdChanged.InvokeAsync(chatTemplateId); await this.ChatTemplateIdChanged.InvokeAsync(this.ChatTemplateId);
} }
// //
// MudSelect hands out its selection as a lazy sequence of nullable strings. We materialize it // MudSelect hands out its selection as a collection of nullable strings. We copy it and drop
// once and drop empty entries, so the host always receives a stable list of usable IDs: // empty entries, so the host always receives a stable list of usable IDs:
// //
private async Task SetDataSourceIds(IEnumerable<string?>? dataSourceIds) private async Task SetDataSourceIds(IReadOnlyCollection<string?>? dataSourceIds)
{ {
var selectedDataSourceIds = dataSourceIds is null ? [] : dataSourceIds.Where(id => !string.IsNullOrWhiteSpace(id)).Select(id => id!).ToArray(); var selectedDataSourceIds = dataSourceIds is null ? [] : dataSourceIds.Where(id => !string.IsNullOrWhiteSpace(id)).Select(id => id!).ToArray();
@@ -138,7 +138,7 @@ public partial class DirectChatLauncherForm : MSGComponentBase
await this.ToolIdsChanged.InvokeAsync(toolIds); await this.ToolIdsChanged.InvokeAsync(toolIds);
} }
private string GetSelectedDataSourceText(List<string?>? selectedValues) private string GetSelectedDataSourceText(IReadOnlyList<string?>? selectedValues)
{ {
if (selectedValues is null || selectedValues.Count == 0) if (selectedValues is null || selectedValues.Count == 0)
return T("Use the normal chat data source defaults"); return T("Use the normal chat data source defaults");
@@ -62,8 +62,9 @@ namespace AIStudio.Components
[Parameter] [Parameter]
public string Style { get; set; } = string.Empty; public string Style { get; set; } = string.Empty;
private async Task OnValueChanged(string newValue) private async Task OnValueChanged(string? changedValue)
{ {
var newValue = changedValue ?? string.Empty;
if (this.Value != newValue) if (this.Value != newValue)
{ {
this.Value = newValue; this.Value = newValue;
@@ -97,7 +98,7 @@ namespace AIStudio.Components
return [this.Default, .. items]; return [this.Default, .. items];
} }
private string GetMultiSelectionText(List<string?>? selectedValues) private string GetMultiSelectionText(IReadOnlyList<string?>? selectedValues)
{ {
if (selectedValues is null || selectedValues.Count == 0) if (selectedValues is null || selectedValues.Count == 0)
return this.Default.Display; return this.Default.Display;
@@ -80,9 +80,9 @@ public partial class EnumSelection<T> : EnumSelectionBase where T : struct, Enum
await this.SelectionUpdated(value); await this.SelectionUpdated(value);
} }
private async Task OtherValueChanged(string value) private async Task OtherValueChanged(string? value)
{ {
await this.OtherInputChanged.InvokeAsync(value); await this.OtherInputChanged.InvokeAsync(value ?? string.Empty);
await this.SelectionUpdated(this.Value); await this.SelectionUpdated(this.Value);
} }
} }
@@ -12,8 +12,8 @@
</MudStack> </MudStack>
<MudStack Spacing="1"> <MudStack Spacing="1">
<MudTextField T="string" InputId="@this.folderInputId" Text="@this.state.FolderText" TextChanged="@this.ChangeFoldersAsync" Immediate="@true" Disabled="@this.Disabled" Label="@T("Folders")" Lines="1" AutoGrow="@true" MaxLines="@FilePatternSelection.MAX_FIELD_LINES" Class="pattern-text-field" Variant="Variant.Outlined" Margin="Margin.Dense" Validation="@FileExclusions.ValidateFolders" UserAttributes="@INPUT_ATTRIBUTES" Placeholder="node_modules/;bin/;cmake-build-*/" Adornment="@(this.ShowReset ? Adornment.End : Adornment.None)" AdornmentIcon="@Icons.Material.Filled.Restore" OnAdornmentClick="@(() => this.RestoreDefaultsAsync(true))" AdornmentAriaLabel="@this.FolderRestoreLabel"/> <MudTextField T="string" InputId="@this.folderInputId" Text="@this.state.FolderText" TextChanged="@this.ChangeFoldersAsync" Immediate="@true" Disabled="@this.Disabled" Label="@T("Folders")" Lines="1" Sizing="InputSizing.Auto" MaxLines="@FilePatternSelection.MAX_FIELD_LINES" Class="pattern-text-field" Variant="Variant.Outlined" Margin="Margin.Dense" Validation="@FileExclusions.ValidateFolders" UserAttributes="@INPUT_ATTRIBUTES" Placeholder="node_modules/;bin/;cmake-build-*/" Adornment="@(this.ShowReset ? Adornment.End : Adornment.None)" AdornmentIcon="@Icons.Material.Filled.Restore" OnAdornmentClick="@(() => this.RestoreDefaultsAsync(true))" AdornmentAriaLabel="@this.FolderRestoreLabel"/>
<MudTextField T="string" InputId="@this.fileInputId" Text="@this.state.FileText" TextChanged="@this.ChangeFilesAsync" Immediate="@true" Disabled="@this.Disabled" Label="@T("Files")" Lines="1" AutoGrow="@true" MaxLines="@FilePatternSelection.MAX_FIELD_LINES" Class="pattern-text-field" Variant="Variant.Outlined" Margin="Margin.Dense" Validation="@FileExclusions.ValidateFiles" UserAttributes="@INPUT_ATTRIBUTES" Placeholder="*.min.js;*.webm;draft-*" Adornment="@(this.ShowReset ? Adornment.End : Adornment.None)" AdornmentIcon="@Icons.Material.Filled.Restore" OnAdornmentClick="@(() => this.RestoreDefaultsAsync(false))" AdornmentAriaLabel="@this.FileRestoreLabel"/> <MudTextField T="string" InputId="@this.fileInputId" Text="@this.state.FileText" TextChanged="@this.ChangeFilesAsync" Immediate="@true" Disabled="@this.Disabled" Label="@T("Files")" Lines="1" Sizing="InputSizing.Auto" MaxLines="@FilePatternSelection.MAX_FIELD_LINES" Class="pattern-text-field" Variant="Variant.Outlined" Margin="Margin.Dense" Validation="@FileExclusions.ValidateFiles" UserAttributes="@INPUT_ATTRIBUTES" Placeholder="*.min.js;*.webm;draft-*" Adornment="@(this.ShowReset ? Adornment.End : Adornment.None)" AdornmentIcon="@Icons.Material.Filled.Restore" OnAdornmentClick="@(() => this.RestoreDefaultsAsync(false))" AdornmentAriaLabel="@this.FileRestoreLabel"/>
</MudStack> </MudStack>
<MudText Typo="Typo.caption" Class="mud-text-secondary mt-1">@T("These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/.")</MudText> <MudText Typo="Typo.caption" Class="mud-text-secondary mt-1">@T("These files and folders are left out, even when a file pattern selects them. Separate entries with a semicolon or a line break. End an entry with a slash to exclude every folder of that name, e.g., node_modules/.")</MudText>
@@ -70,9 +70,9 @@ public partial class FileExclusionEditor : MSGComponentBase
base.OnParametersSet(); base.OnParametersSet();
} }
protected Task ChangeFoldersAsync(string text) => this.ChangePatternsAsync(text, folders: true); protected Task ChangeFoldersAsync(string? text) => this.ChangePatternsAsync(text ?? string.Empty, folders: true);
protected Task ChangeFilesAsync(string text) => this.ChangePatternsAsync(text, folders: false); protected Task ChangeFilesAsync(string? text) => this.ChangePatternsAsync(text ?? string.Empty, folders: false);
private async Task ChangePatternsAsync(string text, bool folders) private async Task ChangePatternsAsync(string text, bool folders)
{ {
@@ -24,10 +24,10 @@ public partial class ProfileFormSelection : MSGComponentBase
[Inject] [Inject]
public IDialogService DialogService { get; init; } = null!; public IDialogService DialogService { get; init; } = null!;
private async Task SelectionChanged(Profile profile) private async Task SelectionChanged(Profile? profile)
{ {
this.Profile = profile; this.Profile = profile ?? Profile.NO_PROFILE;
await this.ProfileChanged.InvokeAsync(profile); await this.ProfileChanged.InvokeAsync(this.Profile);
} }
private async Task OpenSettingsDialog() private async Task OpenSettingsDialog()
@@ -5,13 +5,13 @@
<ActivatorContent> <ActivatorContent>
@if (this.CurrentProfile != Profile.NO_PROFILE) @if (this.CurrentProfile != Profile.NO_PROFILE)
{ {
<MudButton IconSize="Size.Large" StartIcon="@Icons.Material.Filled.Person4" IconColor="Color.Default"> <MudButton IconSize="Size.Large" StartIcon="@Icons.Material.Filled.Person4" IconColor="Color.Default" OnClick="@context.ToggleAsync">
@this.CurrentProfile.GetSafeName() @this.CurrentProfile.GetSafeName()
</MudButton> </MudButton>
} }
else else
{ {
<MudIconButton Icon="@Icons.Material.Filled.Person4" Color="Color.Default" /> <MudIconButton Icon="@Icons.Material.Filled.Person4" Color="Color.Default" OnClick="@context.ToggleAsync" />
} }
</ActivatorContent> </ActivatorContent>
<ChildContent> <ChildContent>
@@ -57,13 +57,13 @@ public partial class ProviderSelection : MSGComponentBase
#endregion #endregion
private async Task SelectionChanged(AIStudio.Settings.Provider provider) private async Task SelectionChanged(AIStudio.Settings.Provider? provider)
{ {
if (this.Disabled) if (this.Disabled)
return; return;
this.ProviderSettings = provider; this.ProviderSettings = provider ?? AIStudio.Settings.Provider.NONE;
await this.ProviderSettingsChanged.InvokeAsync(provider); await this.ProviderSettingsChanged.InvokeAsync(this.ProviderSettings);
} }
private IEnumerable<ProviderSelectionItem> GetAvailableProviderSelectionItems() private IEnumerable<ProviderSelectionItem> GetAvailableProviderSelectionItems()
@@ -247,9 +247,9 @@ public partial class ReadWebContent : MSGComponentBase
/// </remarks> /// </remarks>
private bool UrlIsValid => this.ValidateURL(this.URL) is null; private bool UrlIsValid => this.ValidateURL(this.URL) is null;
private async Task URLValueChanged(string url) private async Task URLValueChanged(string? url)
{ {
await this.URLChanged.InvokeAsync(url); await this.URLChanged.InvokeAsync(url ?? string.Empty);
} }
private async Task ShowWebContentReaderChanged(bool state) private async Task ShowWebContentReaderChanged(bool state)
@@ -44,10 +44,10 @@ public partial class SecretInputField : MSGComponentBase
private string ToggleVisibilityTooltip => this.isSecretVisible ? T("Hide content") : T("Show content"); private string ToggleVisibilityTooltip => this.isSecretVisible ? T("Hide content") : T("Show content");
private Task OnSecretChanged(string arg) private Task OnSecretChanged(string? arg)
{ {
this.Secret = arg; this.Secret = arg ?? string.Empty;
return this.SecretChanged.InvokeAsync(arg); return this.SecretChanged.InvokeAsync(this.Secret);
} }
private void ToggleVisibility() => this.isSecretVisible = !this.isSecretVisible; private void ToggleVisibility() => this.isSecretVisible = !this.isSecretVisible;
@@ -210,20 +210,20 @@ public partial class SettingsPanelEmbeddings : SettingsPanelProviderBase
// sentence below, which used to be the same one for a missing API key, an unreachable // sentence below, which used to be the same one for a missing API key, an unreachable
// provider and a provider which cannot embed anything at all: // provider and a provider which cannot embed anything at all:
// //
await this.DialogService.ShowMessageBox(T("Embedding Result"), exception.UserMessage, T("Close")); await this.DialogService.ShowMessageBoxAsync(T("Embedding Result"), exception.UserMessage, T("Close"));
return; return;
} }
if (embeddings.Count == 0) if (embeddings.Count == 0)
{ {
await this.DialogService.ShowMessageBox(T("Embedding Result"), T("No embedding was returned."), T("Close")); await this.DialogService.ShowMessageBoxAsync(T("Embedding Result"), T("No embedding was returned."), T("Close"));
return; return;
} }
var vector = embeddings.FirstOrDefault(); var vector = embeddings.FirstOrDefault();
if (vector is null || vector.Count == 0) if (vector is null || vector.Count == 0)
{ {
await this.DialogService.ShowMessageBox(T("Embedding Result"), T("No embedding was returned."), T("Close")); await this.DialogService.ShowMessageBoxAsync(T("Embedding Result"), T("No embedding was returned."), T("Close"));
return; return;
} }
@@ -9,7 +9,7 @@
Margin="Margin.Dense" Margin="Margin.Dense"
Lines="@this.Lines" Lines="@this.Lines"
MaxLines="@this.MaxLines" MaxLines="@this.MaxLines"
AutoGrow="@true" Sizing="InputSizing.Auto"
Adornment="@(string.IsNullOrEmpty(this.Icon) ? Adornment.None : Adornment.Start)" Adornment="@(string.IsNullOrEmpty(this.Icon) ? Adornment.None : Adornment.Start)"
AdornmentIcon="@this.Icon" AdornmentIcon="@this.Icon"
Style="@this.GetColor()" Style="@this.GetColor()"
@@ -91,7 +91,7 @@ public partial class WorkspaceNameField : MSGComponentBase
// Picking an existing workspace fills the name field. Clearing the select must not wipe a name // Picking an existing workspace fills the name field. Clearing the select must not wipe a name
// the user typed, though, so an empty selection is ignored: // the user typed, though, so an empty selection is ignored:
// //
private async Task SelectExistingWorkspace(string workspaceName) private async Task SelectExistingWorkspace(string? workspaceName)
{ {
if (string.IsNullOrWhiteSpace(workspaceName)) if (string.IsNullOrWhiteSpace(workspaceName))
return; return;
@@ -99,9 +99,9 @@ public partial class WorkspaceNameField : MSGComponentBase
await this.SetWorkspaceName(workspaceName); await this.SetWorkspaceName(workspaceName);
} }
private async Task SetWorkspaceName(string workspaceName) private async Task SetWorkspaceName(string? workspaceName)
{ {
this.WorkspaceName = workspaceName; this.WorkspaceName = workspaceName ?? string.Empty;
await this.WorkspaceNameChanged.InvokeAsync(workspaceName); await this.WorkspaceNameChanged.InvokeAsync(this.WorkspaceName);
} }
} }
@@ -54,7 +54,7 @@ else
case TreeItemData treeItem: case TreeItemData treeItem:
@if (treeItem.Type is TreeItemType.LOADING) @if (treeItem.Type is TreeItemType.LOADING)
{ {
<MudTreeViewItem T="ITreeItem" Icon="@this.GetTreeItemIcon(treeItem)" Value="@item.Value" Expanded="@item.Expanded" CanExpand="@false" Items="@(treeItem.Children!)"> <MudTreeViewItem T="ITreeItem" Icon="@this.GetTreeItemIcon(treeItem)" Value="@item.Value" Expanded="@item.Expanded" CanExpand="@false" Items="@treeItem.Children">
<BodyContent> <BodyContent>
<MudSkeleton Width="85%" Height="22px"/> <MudSkeleton Width="85%" Height="22px"/>
</BodyContent> </BodyContent>
@@ -62,7 +62,7 @@ else
} }
else if (treeItem.Type is TreeItemType.CHAT) else if (treeItem.Type is TreeItemType.CHAT)
{ {
<MudTreeViewItem T="ITreeItem" Icon="@this.GetTreeItemIcon(treeItem)" Value="@item.Value" Expanded="@item.Expanded" CanExpand="@treeItem.Expandable" Items="@(treeItem.Children!)" OnClick="@(() => this.LoadChatAsync(treeItem.Path, true))"> <MudTreeViewItem T="ITreeItem" Icon="@this.GetTreeItemIcon(treeItem)" Value="@item.Value" Expanded="@item.Expanded" CanExpand="@treeItem.Expandable" Items="@treeItem.Children" OnClick="@(() => this.LoadChatAsync(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="@this.GetChatTreeItemTextStyle(treeItem)"> <MudText Style="@this.GetChatTreeItemTextStyle(treeItem)">
@@ -99,7 +99,7 @@ else
} }
else if (treeItem.Type is TreeItemType.WORKSPACE) else if (treeItem.Type is TreeItemType.WORKSPACE)
{ {
<MudTreeViewItem T="ITreeItem" Icon="@this.GetTreeItemIcon(treeItem)" Value="@item.Value" Expanded="@item.Expanded" CanExpand="@treeItem.Expandable" Items="@(treeItem.Children!)" OnClick="@(() => this.OnWorkspaceClicked(treeItem))"> <MudTreeViewItem T="ITreeItem" Icon="@this.GetTreeItemIcon(treeItem)" Value="@item.Value" Expanded="@item.Expanded" CanExpand="@treeItem.Expandable" Items="@treeItem.Children" OnClick="@(() => this.OnWorkspaceClicked(treeItem))">
<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;">
@@ -127,7 +127,7 @@ else
} }
else else
{ {
<MudTreeViewItem T="ITreeItem" Icon="@this.GetTreeItemIcon(treeItem)" Value="@item.Value" Expanded="@item.Expanded" CanExpand="@treeItem.Expandable" Items="@(treeItem.Children!)"> <MudTreeViewItem T="ITreeItem" Icon="@this.GetTreeItemIcon(treeItem)" Value="@item.Value" Expanded="@item.Expanded" 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;"> <MudText Style="justify-self: start;">
@@ -536,9 +536,9 @@ public partial class Workspaces : MSGComponentBase
} }
} }
private async Task OnSearchTextChanged(string value) private async Task OnSearchTextChanged(string? value)
{ {
this.searchText = value; this.searchText = value ?? string.Empty;
if (string.IsNullOrWhiteSpace(this.searchText)) if (string.IsNullOrWhiteSpace(this.searchText))
{ {
await this.CancelSearchAsync(); await this.CancelSearchAsync();
@@ -6,7 +6,7 @@
@T("Review the assistant draft before AI Studio generates the Lua plugin. You can edit the Markdown draft if something should be changed.") @T("Review the assistant draft before AI Studio generates the Lua plugin. You can edit the Markdown draft if something should be changed.")
</MudJustifiedText> </MudJustifiedText>
<MudTabs Elevation="0" Rounded="true" ApplyEffectsToContainer="true" Outlined="true" PanelClass="pa-2" Class="mb-2"> <MudTabs Elevation="0" Rounded="true" ApplyEffectsToContainer="true" Outlined="true" TabPanelsClass="pa-2" Class="mb-2">
<MudTabPanel Text="@T("Preview")" Icon="@Icons.Material.Filled.Article"> <MudTabPanel Text="@T("Preview")" Icon="@Icons.Material.Filled.Article">
<MudField Variant="Variant.Outlined" AdornmentIcon="@Icons.Material.Filled.Visibility" Adornment="Adornment.Start" Label="@T("Assistant draft")" FullWidth="true" Class="ma-2 pe-4"> <MudField Variant="Variant.Outlined" AdornmentIcon="@Icons.Material.Filled.Visibility" Adornment="Adornment.Start" Label="@T("Assistant draft")" FullWidth="true" Class="ma-2 pe-4">
<div style="max-height: 58vh; overflow-y: auto;"> <div style="max-height: 58vh; overflow-y: auto;">
@@ -15,7 +15,7 @@
</MudField> </MudField>
</MudTabPanel> </MudTabPanel>
<MudTabPanel Text="@T("Edit")" Icon="@Icons.Material.Filled.Edit"> <MudTabPanel Text="@T("Edit")" Icon="@Icons.Material.Filled.Edit">
<MudTextField T="string" @bind-Text="@this.DraftMarkdown" AdornmentIcon="@Icons.Material.Filled.EditNote" Adornment="Adornment.Start" Label="@T("Assistant draft Markdown")" Variant="Variant.Outlined" Lines="16" AutoGrow="@true" MaxLines="32" Class="ma-2"/> <MudTextField T="string" @bind-Text="@this.DraftMarkdown" AdornmentIcon="@Icons.Material.Filled.EditNote" Adornment="Adornment.Start" Label="@T("Assistant draft Markdown")" Variant="Variant.Outlined" Lines="16" Sizing="InputSizing.Auto" MaxLines="32" Class="ma-2"/>
</MudTabPanel> </MudTabPanel>
</MudTabs> </MudTabs>
</DialogContent> </DialogContent>
@@ -25,7 +25,7 @@
Placeholder="@T("Add a field for the target audience and make the final answer shorter.")" Placeholder="@T("Add a field for the target audience and make the final answer shorter.")"
Variant="Variant.Outlined" Variant="Variant.Outlined"
Lines="5" Lines="5"
AutoGrow="true" Sizing="InputSizing.Auto"
MaxLines="12" MaxLines="12"
Immediate="true" Immediate="true"
Disabled="@(this.isGenerating || this.isApplying)" /> Disabled="@(this.isGenerating || this.isApplying)" />
@@ -50,7 +50,7 @@
Variant="Variant.Outlined" Variant="Variant.Outlined"
Lines="6" Lines="6"
MaxLines="12" MaxLines="12"
AutoGrow="@true" Sizing="InputSizing.Auto"
Class="mb-3" Class="mb-3"
UserAttributes="@SPELLCHECK_ATTRIBUTES" UserAttributes="@SPELLCHECK_ATTRIBUTES"
HelperText="@T("Tell the AI your system prompt.")" HelperText="@T("Tell the AI your system prompt.")"
@@ -81,7 +81,7 @@
Variant="Variant.Outlined" Variant="Variant.Outlined"
Lines="4" Lines="4"
MaxLines="12" MaxLines="12"
AutoGrow="@true" Sizing="InputSizing.Auto"
Class="mb-3" Class="mb-3"
UserAttributes="@SPELLCHECK_ATTRIBUTES" UserAttributes="@SPELLCHECK_ATTRIBUTES"
HelperText="@T("Tell the AI your predefined user input.")" HelperText="@T("Tell the AI your predefined user input.")"
@@ -259,7 +259,7 @@
@switch(context.Content) @switch(context.Content)
{ {
case ContentText textContent: case ContentText textContent:
<MudTextField AutoGrow="true" Value="@textContent.Text" Placeholder="@T("Enter a message")" ReadOnly="true" Variant="Variant.Text" Validation="@this.ValidateExampleTextMessage"/> <MudTextField Sizing="InputSizing.Auto" Value="@textContent.Text" Placeholder="@T("Enter a message")" ReadOnly="true" Variant="Variant.Text" Validation="@this.ValidateExampleTextMessage"/>
break; break;
case ContentImage { SourceType: ContentImageSource.URL or ContentImageSource.LOCAL_PATH } imageContent: case ContentImage { SourceType: ContentImageSource.URL or ContentImageSource.LOCAL_PATH } imageContent:
@@ -305,7 +305,7 @@
@switch(context.Content) @switch(context.Content)
{ {
case ContentText textContent: case ContentText textContent:
<MudTextField AutoGrow="true" @bind-Value="@textContent.Text" Label="@T("The message")" Required="true" Immediate="true" Placeholder="@T("Enter a message")" ReadOnly="@this.IsReadOnly"/> <MudTextField Sizing="InputSizing.Auto" @bind-Value="@textContent.Text" Label="@T("The message")" Required="true" Immediate="true" Placeholder="@T("Enter a message")" ReadOnly="@this.IsReadOnly"/>
break; break;
default: default:
@@ -195,7 +195,7 @@ public partial class ChatTemplateDialog : MSGComponentBase
// Reset the validation when not editing and on the first render. // Reset the validation when not editing and on the first render.
// We don't want to show validation errors when the user opens the dialog. // We don't want to show validation errors when the user opens the dialog.
if(!this.IsEditing && firstRender) if(!this.IsEditing && firstRender)
this.form.ResetValidation(); await this.form.ResetValidationAsync();
await base.OnAfterRenderAsync(firstRender); await base.OnAfterRenderAsync(firstRender);
} }
@@ -403,7 +403,7 @@ public partial class ChatTemplateDialog : MSGComponentBase
} }
} }
await this.form.Validate(); await this.form.ValidateAsync();
// When the data is not valid, we don't store it: // When the data is not valid, we don't store it:
if (!this.dataIsValid) if (!this.dataIsValid)
@@ -5,7 +5,7 @@
<MudJustifiedText Typo="Typo.body1" Class="mb-3"> <MudJustifiedText Typo="Typo.body1" Class="mb-3">
@T("Paste a configuration which was exported from AI Studio, for example by a colleague. AI Studio only reads its values and never runs the pasted text. You can review and change everything afterward.") @T("Paste a configuration which was exported from AI Studio, for example by a colleague. AI Studio only reads its values and never runs the pasted text. You can review and change everything afterward.")
</MudJustifiedText> </MudJustifiedText>
<MudTextField T="string" Text="@this.snippet" TextChanged="@this.SnippetChanged" Immediate="true" Label="@T("Exported configuration")" Lines="6" AutoGrow="true" MaxLines="14" Variant="Variant.Outlined" /> <MudTextField T="string" Text="@this.snippet" TextChanged="@this.SnippetChanged" Immediate="true" Label="@T("Exported configuration")" Lines="6" Sizing="InputSizing.Auto" MaxLines="14" Variant="Variant.Outlined" />
@if (!string.IsNullOrWhiteSpace(this.issue)) @if (!string.IsNullOrWhiteSpace(this.issue))
{ {
<MudAlert Severity="Severity.Error" Class="mt-3">@this.issue</MudAlert> <MudAlert Severity="Severity.Error" Class="mt-3">@this.issue</MudAlert>
@@ -28,10 +28,10 @@ public partial class ConfigurationSnippetImportDialog : MSGComponentBase
/// </summary> /// </summary>
private ConfigurationSnippetImportResult? importWithHints; private ConfigurationSnippetImportResult? importWithHints;
private void SnippetChanged(string text) private void SnippetChanged(string? text)
{ {
// The issue and the hints belong to the snippet they were found in: // The issue and the hints belong to the snippet they were found in:
this.snippet = text; this.snippet = text ?? string.Empty;
this.issue = string.Empty; this.issue = string.Empty;
this.importWithHints = null; this.importWithHints = null;
} }
@@ -147,7 +147,7 @@ public partial class DataSourceERI_V1Dialog : MSGComponentBase, ISecretId
{ {
this.dataSecret = string.Empty; this.dataSecret = string.Empty;
this.dataSecretStorageIssue = string.Format(T("Failed to load the auth. secret from the operating system. The message was: {0}. You might ignore this message and provide the secret again."), requestedSecret.Issue); this.dataSecretStorageIssue = string.Format(T("Failed to load the auth. secret from the operating system. The message was: {0}. You might ignore this message and provide the secret again."), requestedSecret.Issue);
await this.form.Validate(); await this.form.ValidateAsync();
} }
} }
@@ -172,7 +172,7 @@ public partial class DataSourceERI_V1Dialog : MSGComponentBase, ISecretId
// Reset the validation when not editing and on the first render. // Reset the validation when not editing and on the first render.
// We don't want to show validation errors when the user opens the dialog. // We don't want to show validation errors when the user opens the dialog.
if(!this.IsEditing && firstRender) if(!this.IsEditing && firstRender)
this.form.ResetValidation(); await this.form.ResetValidationAsync();
await base.OnAfterRenderAsync(firstRender); await base.OnAfterRenderAsync(firstRender);
} }
@@ -249,7 +249,7 @@ public partial class DataSourceERI_V1Dialog : MSGComponentBase, ISecretId
using var client = ERIClientFactory.Get(ERIVersion.V1, this.DataSource); using var client = ERIClientFactory.Get(ERIVersion.V1, this.DataSource);
if(client is null) if(client is null)
{ {
await this.form.Validate(); await this.form.ValidateAsync();
Array.Resize(ref this.dataIssues, this.dataIssues.Length + 1); Array.Resize(ref this.dataIssues, this.dataIssues.Length + 1);
this.dataIssues[^1] = T("Failed to connect to the ERI v1 server. The server is not supported."); this.dataIssues[^1] = T("Failed to connect to the ERI v1 server. The server is not supported.");
@@ -259,7 +259,7 @@ public partial class DataSourceERI_V1Dialog : MSGComponentBase, ISecretId
var authSchemes = await client.GetAuthMethodsAsync(cts.Token); var authSchemes = await client.GetAuthMethodsAsync(cts.Token);
if (!authSchemes.Successful) if (!authSchemes.Successful)
{ {
await this.form.Validate(); await this.form.ValidateAsync();
Array.Resize(ref this.dataIssues, this.dataIssues.Length + 1); Array.Resize(ref this.dataIssues, this.dataIssues.Length + 1);
this.dataIssues[^1] = authSchemes.Message; this.dataIssues[^1] = authSchemes.Message;
@@ -271,7 +271,7 @@ public partial class DataSourceERI_V1Dialog : MSGComponentBase, ISecretId
var loginResult = await client.AuthenticateAsync(this.RustService, this.dataSecret, cts.Token); var loginResult = await client.AuthenticateAsync(this.RustService, this.dataSecret, cts.Token);
if (!loginResult.Successful) if (!loginResult.Successful)
{ {
await this.form.Validate(); await this.form.ValidateAsync();
Array.Resize(ref this.dataIssues, this.dataIssues.Length + 1); Array.Resize(ref this.dataIssues, this.dataIssues.Length + 1);
this.dataIssues[^1] = loginResult.Message; this.dataIssues[^1] = loginResult.Message;
@@ -281,7 +281,7 @@ public partial class DataSourceERI_V1Dialog : MSGComponentBase, ISecretId
var securityRequirementsRequest = await client.GetSecurityRequirementsAsync(cts.Token); var securityRequirementsRequest = await client.GetSecurityRequirementsAsync(cts.Token);
if (!securityRequirementsRequest.Successful) if (!securityRequirementsRequest.Successful)
{ {
await this.form.Validate(); await this.form.ValidateAsync();
Array.Resize(ref this.dataIssues, this.dataIssues.Length + 1); Array.Resize(ref this.dataIssues, this.dataIssues.Length + 1);
this.dataIssues[^1] = securityRequirementsRequest.Message; this.dataIssues[^1] = securityRequirementsRequest.Message;
@@ -293,7 +293,7 @@ public partial class DataSourceERI_V1Dialog : MSGComponentBase, ISecretId
var retrievalInfoRequest = await client.GetRetrievalInfoAsync(cts.Token); var retrievalInfoRequest = await client.GetRetrievalInfoAsync(cts.Token);
if (!retrievalInfoRequest.Successful) if (!retrievalInfoRequest.Successful)
{ {
await this.form.Validate(); await this.form.ValidateAsync();
Array.Resize(ref this.dataIssues, this.dataIssues.Length + 1); Array.Resize(ref this.dataIssues, this.dataIssues.Length + 1);
this.dataIssues[^1] = retrievalInfoRequest.Message; this.dataIssues[^1] = retrievalInfoRequest.Message;
@@ -324,7 +324,7 @@ public partial class DataSourceERI_V1Dialog : MSGComponentBase, ISecretId
} }
catch (Exception e) catch (Exception e)
{ {
await this.form.Validate(); await this.form.ValidateAsync();
Array.Resize(ref this.dataIssues, this.dataIssues.Length + 1); Array.Resize(ref this.dataIssues, this.dataIssues.Length + 1);
this.dataIssues[^1] = string.Format(T("Failed to connect to the ERI v1 server. The message was: {0}"), e.Message); this.dataIssues[^1] = string.Format(T("Failed to connect to the ERI v1 server. The message was: {0}"), e.Message);
@@ -370,7 +370,7 @@ public partial class DataSourceERI_V1Dialog : MSGComponentBase, ISecretId
private async Task Store() private async Task Store()
{ {
await this.form.Validate(); await this.form.ValidateAsync();
var testConnectionValidation = this.dataSourceValidation.ValidateTestedConnection(); var testConnectionValidation = this.dataSourceValidation.ValidateTestedConnection();
if(testConnectionValidation is not null) if(testConnectionValidation is not null)
@@ -394,7 +394,7 @@ public partial class DataSourceERI_V1Dialog : MSGComponentBase, ISecretId
if (!storeResponse.Success) if (!storeResponse.Success)
{ {
this.dataSecretStorageIssue = string.Format(T("Failed to store the auth. secret in the operating system. The message was: {0}. Please try again."), storeResponse.Issue); this.dataSecretStorageIssue = string.Format(T("Failed to store the auth. secret in the operating system. The message was: {0}. Please try again."), storeResponse.Issue);
await this.form.Validate(); await this.form.ValidateAsync();
return; return;
} }
@@ -86,7 +86,7 @@
Variant="Variant.Outlined" Variant="Variant.Outlined"
Margin="Margin.Dense" Margin="Margin.Dense"
Lines="1" Lines="1"
AutoGrow="@true" Sizing="InputSizing.Auto"
MaxLines="@FilePatternSelection.MAX_FIELD_LINES" MaxLines="@FilePatternSelection.MAX_FIELD_LINES"
Class="pattern-text-field" Class="pattern-text-field"
/> />
@@ -133,7 +133,7 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
// Reset the validation when not editing and on the first render. // Reset the validation when not editing and on the first render.
// We don't want to show validation errors when the user opens the dialog. // We don't want to show validation errors when the user opens the dialog.
if(!this.IsEditing && firstRender) if(!this.IsEditing && firstRender)
this.form.ResetValidation(); await this.form.ResetValidationAsync();
// A check asked for in code waits until the fields hold their new values, cf. ToggleExpertSettings: // A check asked for in code waits until the fields hold their new values, cf. ToggleExpertSettings:
if (this.revalidateAfterRender) if (this.revalidateAfterRender)
@@ -267,7 +267,7 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
private async Task Store() private async Task Store()
{ {
await this.form.Validate(); await this.form.ValidateAsync();
// When the data is not valid, we don't store it: // When the data is not valid, we don't store it:
if (!this.dataIsValid) if (!this.dataIsValid)
@@ -124,7 +124,7 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
// Reset the validation when not editing and on the first render. // Reset the validation when not editing and on the first render.
// We don't want to show validation errors when the user opens the dialog. // We don't want to show validation errors when the user opens the dialog.
if(!this.IsEditing && firstRender) if(!this.IsEditing && firstRender)
this.form.ResetValidation(); await this.form.ResetValidationAsync();
// A check asked for in code waits until the fields hold their new values, cf. ToggleExpertSettings: // A check asked for in code waits until the fields hold their new values, cf. ToggleExpertSettings:
if (this.revalidateAfterRender) if (this.revalidateAfterRender)
@@ -251,7 +251,7 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
private async Task Store() private async Task Store()
{ {
await this.form.Validate(); await this.form.ValidateAsync();
// When the data is not valid, we don't store it: // When the data is not valid, we don't store it:
if (!this.dataIsValid) if (!this.dataIsValid)
@@ -207,7 +207,7 @@ public partial class DataSourceMailboxDialog : MSGComponentBase
// Reset the validation when not editing and on the first render. // Reset the validation when not editing and on the first render.
// We don't want to show validation errors when the user opens the dialog. // We don't want to show validation errors when the user opens the dialog.
if (!this.IsEditing && firstRender) if (!this.IsEditing && firstRender)
this.form.ResetValidation(); await this.form.ResetValidationAsync();
// A check asked for in code waits until the fields hold their new values, cf. ToggleExpertSettings: // A check asked for in code waits until the fields hold their new values, cf. ToggleExpertSettings:
if (this.revalidateAfterRender) if (this.revalidateAfterRender)
@@ -469,7 +469,7 @@ public partial class DataSourceMailboxDialog : MSGComponentBase
this.SelectProvider(GetProviderKey(this.organizationProviders[0])); this.SelectProvider(GetProviderKey(this.organizationProviders[0]));
} }
private void SelectProvider(string providerKey) private void SelectProvider(string? providerKey)
{ {
this.selectedOrganizationProvider = this.organizationProviders.FirstOrDefault(candidate => GetProviderKey(candidate) == providerKey); this.selectedOrganizationProvider = this.organizationProviders.FirstOrDefault(candidate => GetProviderKey(candidate) == providerKey);
this.selectedTemplate = MailboxProviderTemplates.ALL.FirstOrDefault(candidate => GetProviderKey(candidate) == providerKey); this.selectedTemplate = MailboxProviderTemplates.ALL.FirstOrDefault(candidate => GetProviderKey(candidate) == providerKey);
@@ -538,7 +538,7 @@ public partial class DataSourceMailboxDialog : MSGComponentBase
} }
await this.RecordSignInOutcomeAsync(settings, this.testFailure, serverAnswer); await this.RecordSignInOutcomeAsync(settings, this.testFailure, serverAnswer);
await this.form.Validate(); await this.form.ValidateAsync();
} }
private async Task<MailServerFolder?> CreateFolder(string parentFullName, string name) private async Task<MailServerFolder?> CreateFolder(string parentFullName, string name)
@@ -618,7 +618,7 @@ public partial class DataSourceMailboxDialog : MSGComponentBase
if (this.IsAddingNotAllowed) if (this.IsAddingNotAllowed)
return; return;
await this.form.Validate(); await this.form.ValidateAsync();
if (this.RequiresConnectionTest && this.dataSourceValidation.ValidateTestedConnection() is { } testIssue) if (this.RequiresConnectionTest && this.dataSourceValidation.ValidateTestedConnection() is { } testIssue)
{ {
@@ -654,7 +654,7 @@ public partial class DataSourceMailboxDialog : MSGComponentBase
if (!storeResponse.Success) if (!storeResponse.Success)
{ {
this.dataSecretStorageIssue = string.Format(T("Failed to store the password in the operating system. The message was: {0}. Please try again."), storeResponse.Issue); this.dataSecretStorageIssue = string.Format(T("Failed to store the password in the operating system. The message was: {0}. Please try again."), storeResponse.Issue);
await this.form.Validate(); await this.form.ValidateAsync();
return; return;
} }
} }
@@ -26,7 +26,7 @@
<MudPaper Class="pa-3 border-dashed border rounded-lg"> <MudPaper Class="pa-3 border-dashed border rounded-lg">
<MudTextField T="string" @bind-Text="@this.pluginName" Validation="@this.ValidatePluginName" AdornmentIcon="@Icons.Material.Filled.Extension" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Plugin name")" HelperText="@T("The name shown on the plugins page.")" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3" Disabled="@this.IsBusy"/> <MudTextField T="string" @bind-Text="@this.pluginName" Validation="@this.ValidatePluginName" AdornmentIcon="@Icons.Material.Filled.Extension" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Plugin name")" HelperText="@T("The name shown on the plugins page.")" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3" Disabled="@this.IsBusy"/>
<MudTextField T="string" @bind-Text="@this.title" Validation="@this.ValidateTitle" AdornmentIcon="@Icons.Material.Filled.Assistant" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Tile title")" HelperText="@T("The title shown on the tile.")" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3" Disabled="@this.IsBusy"/> <MudTextField T="string" @bind-Text="@this.title" Validation="@this.ValidateTitle" AdornmentIcon="@Icons.Material.Filled.Assistant" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Tile title")" HelperText="@T("The title shown on the tile.")" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3" Disabled="@this.IsBusy"/>
<MudTextField T="string" @bind-Text="@this.description" Validation="@this.ValidateDescription" AdornmentIcon="@Icons.Material.Filled.Notes" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Description")" HelperText="@T("Shown on the tile and on the plugins page.")" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="2" AutoGrow="@true" MaxLines="6" Class="mb-3" Disabled="@this.IsBusy"/> <MudTextField T="string" @bind-Text="@this.description" Validation="@this.ValidateDescription" AdornmentIcon="@Icons.Material.Filled.Notes" Adornment="Adornment.Start" IconSize="Size.Small" Label="@T("Description")" HelperText="@T("Shown on the tile and on the plugins page.")" Variant="Variant.Outlined" Margin="Margin.Dense" Lines="2" Sizing="InputSizing.Auto" MaxLines="6" Class="mb-3" Disabled="@this.IsBusy"/>
<DirectChatLauncherForm @bind-WorkspaceName="@this.workspaceName" <DirectChatLauncherForm @bind-WorkspaceName="@this.workspaceName"
@bind-ProviderId="@this.providerId" @bind-ProviderId="@this.providerId"
@bind-ProfileId="@this.profileId" @bind-ProfileId="@this.profileId"
@@ -47,7 +47,7 @@ public partial class DirectChatLauncherSettingsDialog : MSGComponentBase
private string providerId = string.Empty; private string providerId = string.Empty;
private string profileId = string.Empty; private string profileId = string.Empty;
private string chatTemplateId = string.Empty; private string chatTemplateId = string.Empty;
private IEnumerable<string> dataSourceIds = []; private IReadOnlyCollection<string> dataSourceIds = [];
private HashSet<string> toolIds = []; private HashSet<string> toolIds = [];
private string issue = string.Empty; private string issue = string.Empty;
private bool canEdit; private bool canEdit;
@@ -170,7 +170,7 @@ public partial class DirectChatLauncherSettingsDialog : MSGComponentBase
if (!this.CanSave || this.assistantPlugin is null || this.availablePlugin is null || this.form is null) if (!this.CanSave || this.assistantPlugin is null || this.availablePlugin is null || this.form is null)
return; return;
await this.form.Validate(); await this.form.ValidateAsync();
if (!this.form.IsValid) if (!this.form.IsValid)
return; return;
@@ -48,7 +48,7 @@
Label="@T("Embedding Description")" Label="@T("Embedding Description")"
HelperText="@T("A short description of the embedding method.")" HelperText="@T("A short description of the embedding method.")"
Lines="3" Lines="3"
AutoGrow="@true" Sizing="InputSizing.Auto"
MaxLines="6" MaxLines="6"
Immediate="@true" Immediate="@true"
Variant="Variant.Outlined" Variant="Variant.Outlined"
@@ -67,7 +67,7 @@
Label="@T("Used when")" Label="@T("Used when")"
HelperText="@T("When is this embedding used? When you define multiple embeddings, it is helpful to know when to use which one.")" HelperText="@T("When is this embedding used? When you define multiple embeddings, it is helpful to know when to use which one.")"
Lines="3" Lines="3"
AutoGrow="@true" Sizing="InputSizing.Auto"
MaxLines="6" MaxLines="6"
Immediate="@true" Immediate="@true"
Variant="Variant.Outlined" Variant="Variant.Outlined"
@@ -77,7 +77,7 @@ public partial class EmbeddingMethodDialog : MSGComponentBase
// Reset the validation when not editing and on the first render. // Reset the validation when not editing and on the first render.
// We don't want to show validation errors when the user opens the dialog. // We don't want to show validation errors when the user opens the dialog.
if(!this.IsEditing && firstRender) if(!this.IsEditing && firstRender)
this.form.ResetValidation(); await this.form.ResetValidationAsync();
await base.OnAfterRenderAsync(firstRender); await base.OnAfterRenderAsync(firstRender);
} }
@@ -127,7 +127,7 @@ public partial class EmbeddingMethodDialog : MSGComponentBase
private async Task Store() private async Task Store()
{ {
await this.form.Validate(); await this.form.ValidateAsync();
// When the data is not valid, we don't store it: // When the data is not valid, we don't store it:
if (!this.dataIsValid) if (!this.dataIsValid)
@@ -251,7 +251,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
if (this.DataLLMProvider is not LLMProviders.SELF_HOSTED && !this.IsEnterpriseConfiguration) if (this.DataLLMProvider is not LLMProviders.SELF_HOSTED && !this.IsEnterpriseConfiguration)
{ {
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); 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.ValidateAsync();
} }
} }
@@ -272,7 +272,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
// Reset the validation when not editing and on the first render. // Reset the validation when not editing and on the first render.
// We don't want to show validation errors when the user opens the dialog. // We don't want to show validation errors when the user opens the dialog.
if(!this.IsEditing && firstRender) if(!this.IsEditing && firstRender)
this.form.ResetValidation(); await this.form.ResetValidationAsync();
await base.OnAfterRenderAsync(firstRender); await base.OnAfterRenderAsync(firstRender);
} }
@@ -298,7 +298,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
this.dataStoreWasAttempted = true; this.dataStoreWasAttempted = true;
await this.dataTokenizerValidationTask; await this.dataTokenizerValidationTask;
await this.form.Validate(); await this.form.ValidateAsync();
this.dataAPIKeyStorageIssue = string.Empty; this.dataAPIKeyStorageIssue = string.Empty;
// Manually validate the model selection (needed when no models are loaded // Manually validate the model selection (needed when no models are loaded
@@ -343,7 +343,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
if (!response.Success) if (!response.Success)
{ {
this.dataCustomTokenizerValidationIssue = string.IsNullOrWhiteSpace(response.Message) ? string.Empty : response.Message; this.dataCustomTokenizerValidationIssue = string.IsNullOrWhiteSpace(response.Message) ? string.Empty : response.Message;
await this.form.Validate(); await this.form.ValidateAsync();
return; return;
} }
this.dataFilePath = response.StoredPath; this.dataFilePath = response.StoredPath;
@@ -358,7 +358,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
if (!storeResponse.Success) if (!storeResponse.Success)
{ {
this.dataAPIKeyStorageIssue = string.Format(T("Failed to store the API key in the operating system. The message was: {0}. Please try again."), storeResponse.Issue); 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.ValidateAsync();
return; return;
} }
@@ -372,7 +372,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
if (!deleteResponse.Success) if (!deleteResponse.Success)
{ {
this.dataAPIKeyStorageIssue = string.Format(T("Failed to remove the API key from the operating system. The message was: {0}. Please try again."), deleteResponse.Issue); this.dataAPIKeyStorageIssue = string.Format(T("Failed to remove the API key from the operating system. The message was: {0}. Please try again."), deleteResponse.Issue);
await this.form.Validate(); await this.form.ValidateAsync();
return; return;
} }
@@ -406,7 +406,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
if (!string.IsNullOrWhiteSpace(this.dataAPIKeyStorageIssue)) if (!string.IsNullOrWhiteSpace(this.dataAPIKeyStorageIssue))
{ {
this.dataAPIKeyStorageIssue = string.Empty; this.dataAPIKeyStorageIssue = string.Empty;
await this.form.Validate(); await this.form.ValidateAsync();
} }
} }
@@ -457,8 +457,9 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
await this.MessageBus.SendWarning(new(Icons.Material.Filled.Warning, T("Please drop a tokenizer file in the JSON format."))); await this.MessageBus.SendWarning(new(Icons.Material.Filled.Warning, T("Please drop a tokenizer file in the JSON format.")));
} }
private async Task OnDataFilePathChanged(string filePath) private async Task OnDataFilePathChanged(string? changedFilePath)
{ {
var filePath = changedFilePath ?? string.Empty;
this.dataFilePath = filePath; this.dataFilePath = filePath;
var validationRevision = ++this.dataTokenizerValidationRevision; var validationRevision = ++this.dataTokenizerValidationRevision;
this.dataTokenizerValidationTask = this.ValidateCustomTokenizer(filePath, validationRevision); this.dataTokenizerValidationTask = this.ValidateCustomTokenizer(filePath, validationRevision);
@@ -477,9 +478,9 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
this.dataTokenizerFingerprint = tokenizerFingerprint; this.dataTokenizerFingerprint = tokenizerFingerprint;
if (this.dataStoreWasAttempted) if (this.dataStoreWasAttempted)
await this.form.Validate(); await this.form.ValidateAsync();
else else
this.form.ResetValidation(); await this.form.ResetValidationAsync();
} }
private async Task ValidateCustomTokenizer(string filePath, int validationRevision) private async Task ValidateCustomTokenizer(string filePath, int validationRevision)
@@ -7,7 +7,7 @@
Text="@this.ResultText" Text="@this.ResultText"
Variant="Variant.Outlined" Variant="Variant.Outlined"
Lines="10" Lines="10"
AutoGrow="@true" Sizing="InputSizing.Auto"
MaxLines="25" MaxLines="25"
ReadOnly="true" ReadOnly="true"
Label="@this.ResultLabelText" Label="@this.ResultLabelText"
@@ -41,7 +41,7 @@
Label="@T("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" Sizing="InputSizing.Auto"
MaxLines="12" MaxLines="12"
UserAttributes="@SPELLCHECK_ATTRIBUTES" UserAttributes="@SPELLCHECK_ATTRIBUTES"
HelperText="@T("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?")"
@@ -59,7 +59,7 @@
Label="@T("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" Sizing="InputSizing.Auto"
MaxLines="12" MaxLines="12"
Class="mt-10" Class="mt-10"
UserAttributes="@SPELLCHECK_ATTRIBUTES" UserAttributes="@SPELLCHECK_ATTRIBUTES"
@@ -102,7 +102,7 @@ public partial class ProfileDialog : MSGComponentBase
// Reset the validation when not editing and on the first render. // Reset the validation when not editing and on the first render.
// We don't want to show validation errors when the user opens the dialog. // We don't want to show validation errors when the user opens the dialog.
if(!this.IsEditing && firstRender) if(!this.IsEditing && firstRender)
this.form.ResetValidation(); await this.form.ResetValidationAsync();
await base.OnAfterRenderAsync(firstRender); await base.OnAfterRenderAsync(firstRender);
} }
@@ -114,7 +114,7 @@ public partial class ProfileDialog : MSGComponentBase
if (this.IsReadOnly) if (this.IsReadOnly)
return; return;
await this.form.Validate(); await this.form.ValidateAsync();
// When the data is not valid, we don't store it: // When the data is not valid, we don't store it:
if (!this.dataIsValid) if (!this.dataIsValid)
@@ -311,7 +311,7 @@
<MudJustifiedText Typo="Typo.body2" Class="mb-4"> <MudJustifiedText Typo="Typo.body2" Class="mb-4">
@string.Format(T("The current model uses the {0}."), this.GetCurrentModelApiLabel()) @string.Format(T("The current model uses the {0}."), this.GetCurrentModelApiLabel())
</MudJustifiedText> </MudJustifiedText>
<MudTextField T="string" Label=@T("Additional API parameters") Variant="Variant.Outlined" Lines="4" AutoGrow="true" MaxLines="10" HelperText=@T("""Add the parameters in proper JSON formatting, e.g., "temperature": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.""") Placeholder="@GetPlaceholderExpertSettings" @bind-Value="@this.AdditionalJsonApiParameters" Immediate="true" Disabled="@this.IsEnterpriseConfiguration" Validation="@this.ValidateAdditionalJsonApiParameters" OnBlur="@this.OnInputChangeExpertSettings"/> <MudTextField T="string" Label=@T("Additional API parameters") Variant="Variant.Outlined" Lines="4" Sizing="InputSizing.Auto" MaxLines="10" HelperText=@T("""Add the parameters in proper JSON formatting, e.g., "temperature": 0.5. Remove trailing commas. The usual surrounding curly brackets {} must not be used, though.""") Placeholder="@GetPlaceholderExpertSettings" @bind-Value="@this.AdditionalJsonApiParameters" Immediate="true" Disabled="@this.IsEnterpriseConfiguration" Validation="@this.ValidateAdditionalJsonApiParameters" OnBlur="@this.OnInputChangeExpertSettings"/>
@if (this.ShowTokenizerSettings) @if (this.ShowTokenizerSettings)
{ {
<MudJustifiedText Typo="Typo.body1" Class="mt-4 mb-3"> <MudJustifiedText Typo="Typo.body1" Class="mt-4 mb-3">
@@ -300,7 +300,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
if (this.DataLLMProvider is not LLMProviders.SELF_HOSTED && !this.IsEnterpriseConfiguration) if (this.DataLLMProvider is not LLMProviders.SELF_HOSTED && !this.IsEnterpriseConfiguration)
{ {
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); 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.ValidateAsync();
} }
} }
@@ -321,7 +321,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
// Reset the validation when not editing and on the first render. // Reset the validation when not editing and on the first render.
// We don't want to show validation errors when the user opens the dialog. // We don't want to show validation errors when the user opens the dialog.
if(!this.IsEditing && firstRender) if(!this.IsEditing && firstRender)
this.form.ResetValidation(); await this.form.ResetValidationAsync();
await base.OnAfterRenderAsync(firstRender); await base.OnAfterRenderAsync(firstRender);
} }
@@ -347,7 +347,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
this.dataStoreWasAttempted = true; this.dataStoreWasAttempted = true;
await this.dataTokenizerValidationTask; await this.dataTokenizerValidationTask;
await this.form.Validate(); await this.form.ValidateAsync();
if (!string.IsNullOrWhiteSpace(this.dataAPIKeyStorageIssue)) if (!string.IsNullOrWhiteSpace(this.dataAPIKeyStorageIssue))
this.dataAPIKeyStorageIssue = string.Empty; this.dataAPIKeyStorageIssue = string.Empty;
@@ -376,7 +376,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
if (!string.IsNullOrWhiteSpace(this.dataFilePath)) if (!string.IsNullOrWhiteSpace(this.dataFilePath))
{ {
this.dataCustomTokenizerValidationIssue = tokenizerResponse.Message; this.dataCustomTokenizerValidationIssue = tokenizerResponse.Message;
await this.form.Validate(); await this.form.ValidateAsync();
return; return;
} }
@@ -395,7 +395,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
if (!storeResponse.Success) if (!storeResponse.Success)
{ {
this.dataAPIKeyStorageIssue = string.Format(T("Failed to store the API key in the operating system. The message was: {0}. Please try again."), storeResponse.Issue); 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.ValidateAsync();
return; return;
} }
@@ -409,7 +409,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
if (!deleteResponse.Success) if (!deleteResponse.Success)
{ {
this.dataAPIKeyStorageIssue = string.Format(T("Failed to remove the API key from the operating system. The message was: {0}. Please try again."), deleteResponse.Issue); this.dataAPIKeyStorageIssue = string.Format(T("Failed to remove the API key from the operating system. The message was: {0}. Please try again."), deleteResponse.Issue);
await this.form.Validate(); await this.form.ValidateAsync();
return; return;
} }
@@ -435,7 +435,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
if (!string.IsNullOrWhiteSpace(this.dataAPIKeyStorageIssue)) if (!string.IsNullOrWhiteSpace(this.dataAPIKeyStorageIssue))
{ {
this.dataAPIKeyStorageIssue = string.Empty; this.dataAPIKeyStorageIssue = string.Empty;
await this.form.Validate(); await this.form.ValidateAsync();
} }
} }
@@ -486,8 +486,9 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
await this.MessageBus.SendWarning(new(Icons.Material.Filled.Warning, T("Please drop a tokenizer file in the JSON format."))); await this.MessageBus.SendWarning(new(Icons.Material.Filled.Warning, T("Please drop a tokenizer file in the JSON format.")));
} }
private async Task OnDataFilePathChanged(string filePath) private async Task OnDataFilePathChanged(string? changedFilePath)
{ {
var filePath = changedFilePath ?? string.Empty;
this.dataFilePath = filePath; this.dataFilePath = filePath;
var validationRevision = ++this.dataTokenizerValidationRevision; var validationRevision = ++this.dataTokenizerValidationRevision;
this.dataTokenizerValidationTask = this.ValidateCustomTokenizer(filePath, validationRevision); this.dataTokenizerValidationTask = this.ValidateCustomTokenizer(filePath, validationRevision);
@@ -497,9 +498,9 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
return; return;
if (this.dataStoreWasAttempted) if (this.dataStoreWasAttempted)
await this.form.Validate(); await this.form.ValidateAsync();
else else
this.form.ResetValidation(); await this.form.ResetValidationAsync();
} }
private async Task ValidateCustomTokenizer(string filePath, int validationRevision) private async Task ValidateCustomTokenizer(string filePath, int validationRevision)
@@ -38,7 +38,7 @@
Label="@T("Retrieval Process Description")" Label="@T("Retrieval Process Description")"
HelperText="@T("A short description of the retrieval process.")" HelperText="@T("A short description of the retrieval process.")"
Lines="3" Lines="3"
AutoGrow="@true" Sizing="InputSizing.Auto"
MaxLines="6" MaxLines="6"
Immediate="@true" Immediate="@true"
Variant="Variant.Outlined" Variant="Variant.Outlined"
@@ -132,7 +132,7 @@
Label="@T("Parameter Description")" Label="@T("Parameter Description")"
HelperText="@T("A short description of the parameter. What data type is it? What is it used for? What are the possible values?")" HelperText="@T("A short description of the parameter. What data type is it? What is it used for? What are the possible values?")"
Lines="3" Lines="3"
AutoGrow="@true" Sizing="InputSizing.Auto"
MaxLines="6" MaxLines="6"
Immediate="@true" Immediate="@true"
Variant="Variant.Outlined" Variant="Variant.Outlined"
@@ -91,7 +91,7 @@ public partial class RetrievalProcessDialog : MSGComponentBase
// Reset the validation when not editing and on the first render. // Reset the validation when not editing and on the first render.
// We don't want to show validation errors when the user opens the dialog. // We don't want to show validation errors when the user opens the dialog.
if(!this.IsEditing && firstRender) if(!this.IsEditing && firstRender)
this.form.ResetValidation(); await this.form.ResetValidationAsync();
await base.OnAfterRenderAsync(firstRender); await base.OnAfterRenderAsync(firstRender);
} }
@@ -187,7 +187,7 @@ public partial class RetrievalProcessDialog : MSGComponentBase
private async Task Store() private async Task Store()
{ {
await this.form.Validate(); await this.form.ValidateAsync();
foreach (var parameter in this.retrievalParameters) foreach (var parameter in this.retrievalParameters)
{ {
if (this.ValidateParameter(parameter) is { } issue) if (this.ValidateParameter(parameter) is { } issue)
Loaded 100 of 625 files, more files were not shown because too many files have changed in this diff. Show more