diff --git a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor
index e69de29b..327350bb 100644
--- a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor
+++ b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor
@@ -0,0 +1,79 @@
+
+
+
+ @* ReSharper disable once CSharpWarnings::CS8974 *@
+
+
+
+ Select a root directory for this data source. All data in this directory and all
+ its subdirectories will be processed for this data source.
+
+
+
+
+ In order for the AI to be able to determine the appropriate data at any time, you must
+ choose an embedding method.
+
+
+ @foreach (var embedding in this.AvailableEmbeddings)
+ {
+ @embedding.Name
+ }
+
+
+ @if (!string.IsNullOrWhiteSpace(this.dataEmbeddingId))
+ {
+ if (this.SelectedCloudEmbedding)
+ {
+
+ @if (string.IsNullOrWhiteSpace(this.dataPath))
+ {
+ @: Please note: the embedding you selected runs in the cloud. All your data will be sent to the cloud.
+ @: Please confirm that you have read and understood this.
+ }
+ else
+ {
+ @: Please note: the embedding you selected runs in the cloud. All your data from the
+ @: folder '@this.dataPath' and all its subdirectories will be sent to the cloud. Please
+ @: confirm that you have read and understood this.
+ }
+
+
+ }
+ else
+ {
+
+ The embedding you selected runs locally or in your organization. Your data is not sent to the cloud.
+
+ }
+ }
+
+
+
+
+ Cancel
+
+ @if(this.IsEditing)
+ {
+ @:Update
+ }
+ else
+ {
+ @:Add
+ }
+
+
+
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor.cs b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor.cs
index b45c70ab..2210e908 100644
--- a/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor.cs
+++ b/app/MindWork AI Studio/Dialogs/DataSourceLocalDirectoryDialog.razor.cs
@@ -1,3 +1,4 @@
+using AIStudio.Settings;
using AIStudio.Settings.DataModel;
using Microsoft.AspNetCore.Components;
@@ -6,9 +7,140 @@ namespace AIStudio.Dialogs;
public partial class DataSourceLocalDirectoryDialog : ComponentBase
{
+ [CascadingParameter]
+ private MudDialogInstance MudDialog { get; set; } = null!;
+
[Parameter]
public bool IsEditing { get; set; }
[Parameter]
public DataSourceLocalDirectory DataSource { get; set; }
+
+ [Parameter]
+ public IReadOnlyList> AvailableEmbeddings { get; set; } = [];
+
+ [Inject]
+ private SettingsManager SettingsManager { get; init; } = null!;
+
+ private static readonly Dictionary SPELLCHECK_ATTRIBUTES = new();
+
+ ///
+ /// The list of used data source names. We need this to check for uniqueness.
+ ///
+ private List UsedDataSourcesNames { get; set; } = [];
+
+ private bool dataIsValid;
+ private string[] dataIssues = [];
+ private string dataEditingPreviousInstanceName = string.Empty;
+
+ private uint dataNum;
+ private string dataId = Guid.NewGuid().ToString();
+ private string dataName = string.Empty;
+ private bool dataUserAcknowledgedCloudEmbedding;
+ private string dataEmbeddingId = string.Empty;
+ private string dataPath = string.Empty;
+
+ // We get the form reference from Blazor code to validate it manually:
+ private MudForm form = null!;
+
+ #region Overrides of ComponentBase
+
+ protected override async Task OnInitializedAsync()
+ {
+ // Configure the spellchecking for the instance name input:
+ this.SettingsManager.InjectSpellchecking(SPELLCHECK_ATTRIBUTES);
+
+ // Load the used instance names:
+ this.UsedDataSourcesNames = this.SettingsManager.ConfigurationData.DataSources.Select(x => x.Name.ToLowerInvariant()).ToList();
+
+ // When editing, we need to load the data:
+ if(this.IsEditing)
+ {
+ this.dataEditingPreviousInstanceName = this.DataSource.Name.ToLowerInvariant();
+ this.dataNum = this.DataSource.Num;
+ this.dataId = this.DataSource.Id;
+ this.dataName = this.DataSource.Name;
+ this.dataEmbeddingId = this.DataSource.EmbeddingId;
+ this.dataPath = this.DataSource.Path;
+ }
+
+ await base.OnInitializedAsync();
+ }
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ // 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.
+ if(!this.IsEditing && firstRender)
+ this.form.ResetValidation();
+
+ await base.OnAfterRenderAsync(firstRender);
+ }
+
+ #endregion
+
+ private string? ValidateName(string value)
+ {
+ if(string.IsNullOrWhiteSpace(value))
+ return "The name must not be empty.";
+
+ if (value.Length > 40)
+ return "The name must not exceed 40 characters.";
+
+ var lowerName = value.ToLowerInvariant();
+ if(lowerName != this.dataEditingPreviousInstanceName && this.UsedDataSourcesNames.Contains(lowerName))
+ return "The name is already used by another data source. Please choose a different name.";
+
+ return null;
+ }
+
+ private string? ValidatePath(string value)
+ {
+ if(string.IsNullOrWhiteSpace(value))
+ return "The path must not be empty. Please select a directory.";
+
+ return null;
+ }
+
+ private string? ValidateEmbeddingId(string value)
+ {
+ if(string.IsNullOrWhiteSpace(value))
+ return "Please select an embedding provider.";
+
+ return null;
+ }
+
+ private string? ValidateUserAcknowledgedCloudEmbedding(bool value)
+ {
+ if(this.SelectedCloudEmbedding && !value)
+ return "Please acknowledge that you are aware of the cloud embedding implications.";
+
+ return null;
+ }
+
+ private bool SelectedCloudEmbedding => !this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId).IsSelfHosted;
+
+ private DataSourceLocalDirectory CreateDataSource() => new()
+ {
+ Id = this.dataId,
+ Num = this.dataNum,
+ Name = this.dataName,
+ Type = DataSourceType.LOCAL_DIRECTORY,
+ EmbeddingId = this.dataEmbeddingId,
+ Path = this.dataPath,
+ };
+
+ private async Task Store()
+ {
+ await this.form.Validate();
+
+ // When the data is not valid, we don't store it:
+ if (!this.dataIsValid)
+ return;
+
+ var addedDataSource = this.CreateDataSource();
+ this.MudDialog.Close(DialogResult.Ok(addedDataSource));
+ }
+
+ private void Cancel() => this.MudDialog.Cancel();
}
\ No newline at end of file