mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-31 14:24:26 +00:00
Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
116 lines
3.8 KiB
C#
116 lines
3.8 KiB
C#
using Microsoft.AspNetCore.Components;
|
|
|
|
namespace AIStudio.Components;
|
|
|
|
/// <summary>
|
|
/// A compact, two-group editor for the exclusion string shared by folder-based features.
|
|
/// </summary>
|
|
public partial class FileExclusionEditor : MSGComponentBase
|
|
{
|
|
private static readonly Dictionary<string, object?> INPUT_ATTRIBUTES = new()
|
|
{
|
|
["spellcheck"] = false,
|
|
["autocorrect"] = "off",
|
|
["autocapitalize"] = "off",
|
|
};
|
|
|
|
[Parameter]
|
|
public string? Text { get; set; } = string.Empty;
|
|
|
|
[Parameter]
|
|
public EventCallback<string> TextChanged { get; set; }
|
|
|
|
[Parameter]
|
|
public string Label { get; set; } = string.Empty;
|
|
|
|
[Parameter]
|
|
public bool Disabled { get; set; }
|
|
|
|
[Parameter]
|
|
public bool ShowReset { get; set; } = true;
|
|
|
|
[Parameter]
|
|
public bool ShowHelp { get; set; } = true;
|
|
|
|
[Parameter]
|
|
public string ResetValue { get; set; } = FileExclusions.DEFAULT_PATTERNS;
|
|
|
|
[Parameter]
|
|
public string ResetButtonText { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Immediately persists the combined value after restoring just one of its groups.
|
|
/// Ordinary edits continue through TextChanged.
|
|
/// </summary>
|
|
[Parameter]
|
|
public EventCallback<string> ResetRequested { get; set; }
|
|
|
|
private readonly FileExclusionEditorState state = new();
|
|
private readonly string folderInputId = $"exclusion-folders-{Guid.NewGuid():N}";
|
|
private readonly string fileInputId = $"exclusion-files-{Guid.NewGuid():N}";
|
|
private bool showHelp;
|
|
|
|
/// <summary>
|
|
/// False while a field holds an invalid draft. The editor keeps such a draft to itself, so the
|
|
/// bound text is still the last valid one and cannot tell.
|
|
/// </summary>
|
|
public bool IsValid => this.state.IsValid;
|
|
|
|
private string EditorLabel => string.IsNullOrWhiteSpace(this.Label) ? T("Excluded files and folders") : this.Label;
|
|
|
|
private string RestoreLabel => string.IsNullOrWhiteSpace(this.ResetButtonText) ? T("Restore default") : this.ResetButtonText;
|
|
|
|
private string FolderRestoreLabel => $"{this.RestoreLabel}: {T("Folders")}";
|
|
|
|
private string FileRestoreLabel => $"{this.RestoreLabel}: {T("Files")}";
|
|
|
|
protected override void OnParametersSet()
|
|
{
|
|
this.state.Receive(this.Text, discardDraft: this.Disabled);
|
|
base.OnParametersSet();
|
|
}
|
|
|
|
protected Task ChangeFoldersAsync(string text) => this.ChangePatternsAsync(text, folders: true);
|
|
|
|
protected Task ChangeFilesAsync(string text) => this.ChangePatternsAsync(text, folders: false);
|
|
|
|
private async Task ChangePatternsAsync(string text, bool folders)
|
|
{
|
|
if (this.Disabled)
|
|
return;
|
|
|
|
var previousText = this.state.Text;
|
|
var wasValid = this.state.IsValid;
|
|
if (folders)
|
|
this.state.EditFolders(text);
|
|
else
|
|
this.state.EditFiles(text);
|
|
|
|
// Moving a rule to the correct field can keep the combined text identical. It must still
|
|
// publish the now-valid draft, because the previous, invalid arrangement was not sent.
|
|
if (this.state.IsValid && (!wasValid || !string.Equals(previousText, this.state.Text, StringComparison.Ordinal)))
|
|
await this.TextChanged.InvokeAsync(this.state.Text);
|
|
}
|
|
|
|
protected async Task RestoreDefaultsAsync(bool folders)
|
|
{
|
|
if (this.Disabled || !this.ShowReset)
|
|
return;
|
|
|
|
if (folders)
|
|
this.state.RestoreFolders(this.ResetValue);
|
|
else
|
|
this.state.RestoreFiles(this.ResetValue);
|
|
|
|
if (!this.state.IsValid)
|
|
return;
|
|
|
|
if (this.ResetRequested.HasDelegate)
|
|
await this.ResetRequested.InvokeAsync(this.state.Text);
|
|
else
|
|
await this.TextChanged.InvokeAsync(this.state.Text);
|
|
}
|
|
|
|
private void ToggleHelp() => this.showHelp = !this.showHelp;
|
|
}
|