diff --git a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua
index a56cc774..494f8cb5 100644
--- a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua
+++ b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua
@@ -3703,6 +3703,144 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T6617545
-- All files in this folder and its subfolders
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCECLOUDEMBEDDINGWARNING::T916879200"] = "All files in this folder and its subfolders"
+-- You might configure different data sources. A data source can include one file, all files in a directory, or data from your company. Later, you can incorporate these data sources as needed when the AI requires this data to complete a certain task.
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1084943026"] = "You might configure different data sources. A data source can include one file, all files in a directory, or data from your company. Later, you can incorporate these data sources as needed when the AI requires this data to complete a certain task."
+
+-- Automatic local data source refresh
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1208397349"] = "Automatic local data source refresh"
+
+-- Edit Local Directory Data Source
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1215599168"] = "Edit Local Directory Data Source"
+
+-- Refresh
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T135637716"] = "Refresh"
+
+-- Add Local Directory as Data Source
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1454193397"] = "Add Local Directory as Data Source"
+
+-- Delete
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1469573738"] = "Delete"
+
+-- Refresh all
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1503082343"] = "Refresh all"
+
+-- Kerberos/SSO ERI data sources cannot be exported yet. Please configure them manually in the configuration plugin.
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1577531115"] = "Kerberos/SSO ERI data sources cannot be exported yet. Please configure them manually in the configuration plugin."
+
+-- Cannot export this ERI data source because the authentication secret could not be encrypted.
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1592527757"] = "Cannot export this ERI data source because the authentication secret could not be encrypted."
+
+-- External (ERI)
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1652430727"] = "External (ERI)"
+
+-- Local File
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1687345358"] = "Local File"
+
+-- Delete Data Source
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T1849107431"] = "Delete Data Source"
+
+-- Local Directory Data Source Information
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2146756020"] = "Local Directory Data Source Information"
+
+-- Edit ERI v1 Data Source
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T221059217"] = "Edit ERI v1 Data Source"
+
+-- Indexed files
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2235289713"] = "Indexed files"
+
+-- Edit Local File Data Source
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2453292893"] = "Edit Local File Data Source"
+
+-- ERI v1 Data Source Information
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T26243729"] = "ERI v1 Data Source Information"
+
+-- Name
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T266367750"] = "Name"
+
+-- Not applicable
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2675917723"] = "Not applicable"
+
+-- No valid embedding
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2698203405"] = "No valid embedding"
+
+-- Embedding
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T2838542994"] = "Embedding"
+
+-- This data source is managed by your organization.
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3031462878"] = "This data source is managed by your organization."
+
+-- Edit
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3267849393"] = "Edit"
+
+-- Are you sure you want to delete the data source '{0}' of type '{1}'?
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3337072977"] = "Are you sure you want to delete the data source '{0}' of type '{1}'?"
+
+-- Add Data Source
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3387511033"] = "Add Data Source"
+
+-- Unknown
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3424652889"] = "Unknown"
+
+-- Close
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3448155331"] = "Close"
+
+-- Add Local File as Data Source
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3500365052"] = "Add Local File as Data Source"
+
+-- Type
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3512062061"] = "Type"
+
+-- Local File Data Source Information
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3525663993"] = "Local File Data Source Information"
+
+-- No data sources configured yet.
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3549650120"] = "No data sources configured yet."
+
+-- Export Access Token?
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3595669127"] = "Export Access Token?"
+
+-- Local data sources refresh when files change.
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3687976654"] = "Local data sources refresh when files change."
+
+-- Not available
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3706935413"] = "Not available"
+
+-- Export ERI Data Source
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3831281036"] = "Export ERI Data Source"
+
+-- Actions
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T3865031940"] = "Actions"
+
+-- This ERI data source has an access token configured. Do you want to include the encrypted access token in the export? Note: The recipient will need the same encryption secret to use the access token.
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T4027572258"] = "This ERI data source has an access token configured. Do you want to include the encrypted access token in the export? Note: The recipient will need the same encryption secret to use the access token."
+
+-- Waiting for indexing status
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T4108252513"] = "Waiting for indexing status"
+
+-- Information
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T4256323669"] = "Information"
+
+-- Add ERI v1 Data Source
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T590005498"] = "Add ERI v1 Data Source"
+
+-- Cannot export this ERI data source because no enterprise encryption secret is configured.
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T750361472"] = "Cannot export this ERI data source because no enterprise encryption secret is configured."
+
+-- External Data (ERI-Server v1)
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T774473996"] = "External Data (ERI-Server v1)"
+
+-- Cannot export this ERI data source because no authentication secret is configured. The issue was: {0}
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T782820095"] = "Cannot export this ERI data source because no authentication secret is configured. The issue was: {0}"
+
+-- {0} of {1}
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T825342513"] = "{0} of {1}"
+
+-- Local data sources refresh only when triggered manually.
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T854231603"] = "Local data sources refresh only when triggered manually."
+
+-- Local Directory
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCEMANAGEMENT::T926703547"] = "Local Directory"
+
-- Yes, let the AI decide which data sources are needed.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1031370894"] = "Yes, let the AI decide which data sources are needed."
@@ -4552,6 +4690,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T85322
-- Provider
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELCONFIDENCE::T900237532"] = "Provider"
+-- Configure Data Sources
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELDATASOURCES::T476193103"] = "Configure Data Sources"
+
-- Embedding Result
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELEMBEDDINGS::T1387042335"] = "Embedding Result"
@@ -7510,147 +7651,12 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCODING::T516498299"]
-- Assistant: Coding Options
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGCODING::T585868261"] = "Assistant: Coding Options"
--- You might configure different data sources. A data source can include one file, all files in a directory, or data from your company. Later, you can incorporate these data sources as needed when the AI requires this data to complete a certain task.
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1084943026"] = "You might configure different data sources. A data source can include one file, all files in a directory, or data from your company. Later, you can incorporate these data sources as needed when the AI requires this data to complete a certain task."
-
--- Automatic local data source refresh
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1208397349"] = "Automatic local data source refresh"
-
--- Edit Local Directory Data Source
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1215599168"] = "Edit Local Directory Data Source"
-
--- Refresh
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T135637716"] = "Refresh"
-
--- Add Local Directory as Data Source
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1454193397"] = "Add Local Directory as Data Source"
-
--- Delete
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1469573738"] = "Delete"
-
--- Refresh all
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1503082343"] = "Refresh all"
-
--- Kerberos/SSO ERI data sources cannot be exported yet. Please configure them manually in the configuration plugin.
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1577531115"] = "Kerberos/SSO ERI data sources cannot be exported yet. Please configure them manually in the configuration plugin."
-
--- Cannot export this ERI data source because the authentication secret could not be encrypted.
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1592527757"] = "Cannot export this ERI data source because the authentication secret could not be encrypted."
-
--- External (ERI)
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1652430727"] = "External (ERI)"
-
--- Local File
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1687345358"] = "Local File"
-
--- Delete Data Source
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T1849107431"] = "Delete Data Source"
-
--- Local Directory Data Source Information
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T2146756020"] = "Local Directory Data Source Information"
-
--- Edit ERI v1 Data Source
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T221059217"] = "Edit ERI v1 Data Source"
-
--- Indexed files
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T2235289713"] = "Indexed files"
-
--- Edit Local File Data Source
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T2453292893"] = "Edit Local File Data Source"
-
--- ERI v1 Data Source Information
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T26243729"] = "ERI v1 Data Source Information"
-
--- Name
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T266367750"] = "Name"
-
--- Not applicable
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T2675917723"] = "Not applicable"
-
--- No valid embedding
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T2698203405"] = "No valid embedding"
-
--- Embedding
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T2838542994"] = "Embedding"
-
--- This data source is managed by your organization.
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3031462878"] = "This data source is managed by your organization."
-
--- Edit
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3267849393"] = "Edit"
-
--- Are you sure you want to delete the data source '{0}' of type '{1}'?
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3337072977"] = "Are you sure you want to delete the data source '{0}' of type '{1}'?"
-
--- Add Data Source
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3387511033"] = "Add Data Source"
-
--- Unknown
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3424652889"] = "Unknown"
-
-- Close
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3448155331"] = "Close"
--- Add Local File as Data Source
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3500365052"] = "Add Local File as Data Source"
-
--- Type
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3512062061"] = "Type"
-
--- Local File Data Source Information
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3525663993"] = "Local File Data Source Information"
-
--- No data sources configured yet.
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3549650120"] = "No data sources configured yet."
-
--- Export Access Token?
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3595669127"] = "Export Access Token?"
-
--- Local data sources refresh when files change.
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3687976654"] = "Local data sources refresh when files change."
-
--- Not available
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3706935413"] = "Not available"
-
--- Export ERI Data Source
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3831281036"] = "Export ERI Data Source"
-
--- Actions
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T3865031940"] = "Actions"
-
--- This ERI data source has an access token configured. Do you want to include the encrypted access token in the export? Note: The recipient will need the same encryption secret to use the access token.
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T4027572258"] = "This ERI data source has an access token configured. Do you want to include the encrypted access token in the export? Note: The recipient will need the same encryption secret to use the access token."
-
--- Waiting for indexing status
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T4108252513"] = "Waiting for indexing status"
-
--- Information
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T4256323669"] = "Information"
-
-- Configured Data Sources
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T543942217"] = "Configured Data Sources"
--- Add ERI v1 Data Source
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T590005498"] = "Add ERI v1 Data Source"
-
--- Cannot export this ERI data source because no enterprise encryption secret is configured.
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T750361472"] = "Cannot export this ERI data source because no enterprise encryption secret is configured."
-
--- External Data (ERI-Server v1)
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T774473996"] = "External Data (ERI-Server v1)"
-
--- Cannot export this ERI data source because no authentication secret is configured. The issue was: {0}
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T782820095"] = "Cannot export this ERI data source because no authentication secret is configured. The issue was: {0}"
-
--- {0} of {1}
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T825342513"] = "{0} of {1}"
-
--- Local data sources refresh only when triggered manually.
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T854231603"] = "Local data sources refresh only when triggered manually."
-
--- Local Directory
-UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGDATASOURCES::T926703547"] = "Local Directory"
-
-- When enabled, you can preselect some ERI server options.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGERISERVER::T1280666275"] = "When enabled, you can preselect some ERI server options."
diff --git a/app/MindWork AI Studio/Components/DataSourceManagement.razor b/app/MindWork AI Studio/Components/DataSourceManagement.razor
new file mode 100644
index 00000000..c8d28ad1
--- /dev/null
+++ b/app/MindWork AI Studio/Components/DataSourceManagement.razor
@@ -0,0 +1,105 @@
+@using AIStudio.Settings
+@using AIStudio.Settings.DataModel
+@inherits MSGComponentBase
+
+
+ @T("You might configure different data sources. A data source can include one file, all files in a directory, or data from your company. Later, you can incorporate these data sources as needed when the AI requires this data to complete a certain task.")
+
+
+
+
+
+
+
+
+
+@{ var embeddingStatuses = this.DataSourceEmbeddingService.GetStatuses().ToDictionary(status => status.DataSourceId, StringComparer.OrdinalIgnoreCase); }
+
+
+
+
+
+
+
+
+
+
+ #
+ @T("Name")
+ @T("Type")
+ @T("Embedding")
+ @T("Indexed files")
+ @T("Actions")
+
+
+ @{ var embeddingStatus = embeddingStatuses.GetValueOrDefault(context.Id); }
+ @context.Num
+ @context.Name
+ @context.Type.GetDisplayName()
+ @this.GetEmbeddingName(context)
+
+ @if (context is IInternalDataSource)
+ {
+
+
+
+ @(embeddingStatus is null ? T("Not available") : string.Format(T("{0} of {1}"), embeddingStatus.IndexedFiles, embeddingStatus.TotalFiles))
+
+
+ }
+ else
+ {
+ @T("Not applicable")
+ }
+
+
+
+
+
+
+
+ @if (context.IsEnterpriseConfiguration)
+ {
+
+
+
+ }
+ else
+ {
+
+
+
+
+
+
+ @if (context is DataSourceERI_V1)
+ {
+
+ }
+
+
+
+ }
+
+
+
+
+
+@if (this.SettingsManager.ConfigurationData.DataSources.Count == 0)
+{
+
+ @T("No data sources configured yet.")
+
+}
+
+
+
+ @T("External Data (ERI-Server v1)")
+
+
+ @T("Local Directory")
+
+
+ @T("Local File")
+
+
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/DataSourceManagement.razor.cs b/app/MindWork AI Studio/Components/DataSourceManagement.razor.cs
new file mode 100644
index 00000000..46042fa5
--- /dev/null
+++ b/app/MindWork AI Studio/Components/DataSourceManagement.razor.cs
@@ -0,0 +1,435 @@
+using AIStudio.Dialogs;
+using AIStudio.Settings;
+using AIStudio.Settings.DataModel;
+using AIStudio.Tools.ERIClient.DataModel;
+using AIStudio.Tools.PluginSystem;
+using AIStudio.Tools.Services;
+
+using Microsoft.AspNetCore.Components;
+
+using DialogOptions = AIStudio.Dialogs.DialogOptions;
+
+namespace AIStudio.Components;
+
+///
+/// Manages the configured data sources. Used by the data source settings dialog, which the chat
+/// opens, and by the data source panel in the app settings.
+///
+public partial class DataSourceManagement : MSGComponentBase
+{
+ [Inject]
+ private DataSourceEmbeddingService DataSourceEmbeddingService { get; init; } = null!;
+
+ [Inject]
+ private IDialogService DialogService { get; init; } = null!;
+
+ [Inject]
+ private RustService RustService { get; init; } = null!;
+
+ private readonly List> availableEmbeddingProviders = new();
+
+ #region Overrides of ComponentBase
+
+ protected override async Task OnInitializedAsync()
+ {
+ await base.OnInitializedAsync();
+ this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED, Event.RAG_EMBEDDING_STATUS_CHANGED ]);
+ this.UpdateEmbeddingProviders();
+ }
+
+ #endregion
+
+ #region Overrides of MSGComponentBase
+
+ protected override Task ProcessIncomingMessage(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
+ {
+ switch (triggeredEvent)
+ {
+ case Event.CONFIGURATION_CHANGED:
+ case Event.PLUGINS_RELOADED:
+ this.UpdateEmbeddingProviders();
+ this.StateHasChanged();
+ break;
+
+ case Event.RAG_EMBEDDING_STATUS_CHANGED:
+ this.StateHasChanged();
+ break;
+ }
+
+ return Task.CompletedTask;
+ }
+
+ #endregion
+
+ private void UpdateEmbeddingProviders()
+ {
+ this.availableEmbeddingProviders.Clear();
+ foreach (var provider in this.SettingsManager.GetAllEmbeddingProviders())
+ this.availableEmbeddingProviders.Add(new (provider.Name, provider.Id));
+ }
+
+ private static Color GetIndexingStatusColor(DataSourceEmbeddingStatus? status)
+ {
+ if (status is null || status.State is DataSourceEmbeddingState.IDLE or DataSourceEmbeddingState.QUEUED or DataSourceEmbeddingState.RUNNING)
+ return Color.Warning;
+
+ return status.State is DataSourceEmbeddingState.FAILED || status.FailedFiles > 0
+ ? Color.Error
+ : Color.Success;
+ }
+
+ private string GetEmbeddingName(IDataSource dataSource)
+ {
+ if(dataSource is IInternalDataSource internalDataSource)
+ {
+ var matchedEmbedding = this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == internalDataSource.EmbeddingId);
+ if(matchedEmbedding == default)
+ return T("No valid embedding");
+
+ return matchedEmbedding.Name;
+ }
+
+ if(dataSource is IExternalDataSource)
+ return T("External (ERI)");
+
+ return T("Unknown");
+ }
+
+ private bool CanRefreshDataSource(IDataSource dataSource)
+ {
+ return this.DataSourceEmbeddingService.CanRefreshDataSource(dataSource);
+ }
+
+ private bool HasRefreshableDataSources()
+ {
+ return this.SettingsManager.ConfigurationData.DataSources.Any(this.CanRefreshDataSource);
+ }
+
+ private async Task AutomaticRefreshChanged(bool enabled)
+ {
+ this.SettingsManager.ConfigurationData.App.DataSourceIndexing.AutomaticRefresh = enabled;
+ await this.SettingsManager.StoreSettings();
+ this.DataSourceEmbeddingService.RefreshAutomaticWatchers();
+ await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
+ }
+
+ private async Task RefreshAllDataSources()
+ {
+ await this.DataSourceEmbeddingService.QueueAllInternalDataSourcesAsync();
+ await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
+ }
+
+ private async Task RefreshDataSource(IDataSource dataSource)
+ {
+ if (!this.CanRefreshDataSource(dataSource))
+ return;
+
+ await this.DataSourceEmbeddingService.QueueDataSourceAsync(dataSource);
+ await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
+ }
+
+ private async Task AddDataSource(DataSourceType type)
+ {
+ IDataSource? addedDataSource = null;
+ switch (type)
+ {
+ case DataSourceType.LOCAL_FILE:
+ var localFileDialogParameters = new DialogParameters
+ {
+ { x => x.IsEditing, false },
+ { x => x.AvailableEmbeddings, this.availableEmbeddingProviders }
+ };
+
+ var localFileDialogReference = await this.DialogService.ShowAsync(T("Add Local File as Data Source"), localFileDialogParameters, DialogOptions.FULLSCREEN);
+ var localFileDialogResult = await localFileDialogReference.Result;
+ if (localFileDialogResult is null || localFileDialogResult.Canceled)
+ return;
+
+ var localFile = (DataSourceLocalFile)localFileDialogResult.Data!;
+ localFile = localFile with { Num = this.SettingsManager.ConfigurationData.NextDataSourceNum++ };
+ addedDataSource = localFile;
+ break;
+
+ case DataSourceType.LOCAL_DIRECTORY:
+ var localDirectoryDialogParameters = new DialogParameters
+ {
+ { x => x.IsEditing, false },
+ { x => x.AvailableEmbeddings, this.availableEmbeddingProviders }
+ };
+
+ var localDirectoryDialogReference = await this.DialogService.ShowAsync(T("Add Local Directory as Data Source"), localDirectoryDialogParameters, DialogOptions.FULLSCREEN);
+ var localDirectoryDialogResult = await localDirectoryDialogReference.Result;
+ if (localDirectoryDialogResult is null || localDirectoryDialogResult.Canceled)
+ return;
+
+ var localDirectory = (DataSourceLocalDirectory)localDirectoryDialogResult.Data!;
+ localDirectory = localDirectory with { Num = this.SettingsManager.ConfigurationData.NextDataSourceNum++ };
+ addedDataSource = localDirectory;
+ break;
+
+ case DataSourceType.ERI_V1:
+ var eriDialogParameters = new DialogParameters
+ {
+ { x => x.IsEditing, false },
+ };
+
+ var eriDialogReference = await this.DialogService.ShowAsync(T("Add ERI v1 Data Source"), eriDialogParameters, DialogOptions.FULLSCREEN);
+ var eriDialogResult = await eriDialogReference.Result;
+ if (eriDialogResult is null || eriDialogResult.Canceled)
+ return;
+
+ var eriDataSource = (DataSourceERI_V1)eriDialogResult.Data!;
+ eriDataSource = eriDataSource with { Num = this.SettingsManager.ConfigurationData.NextDataSourceNum++ };
+ addedDataSource = eriDataSource;
+ break;
+ }
+
+ if(addedDataSource is null)
+ return;
+
+ this.SettingsManager.ConfigurationData.DataSources.Add(addedDataSource);
+ await this.SettingsManager.StoreSettings();
+ await this.DataSourceEmbeddingService.QueueDataSourceAsync(addedDataSource);
+ await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
+ }
+
+ private async Task ExportDataSource(IDataSource dataSource)
+ {
+ if (!this.SettingsManager.ConfigurationData.App.ShowAdminSettings)
+ return;
+
+ if (dataSource is not DataSourceERI_V1 eriDataSource)
+ return;
+
+ if (eriDataSource.AuthMethod is AuthMethod.KERBEROS)
+ {
+ await this.DialogService.ShowMessageBox(
+ T("Export ERI Data Source"),
+ T("Kerberos/SSO ERI data sources cannot be exported yet. Please configure them manually in the configuration plugin."),
+ T("Close"));
+ return;
+ }
+
+ var needsSecret = eriDataSource.AuthMethod is AuthMethod.TOKEN or AuthMethod.USERNAME_PASSWORD;
+ if (!needsSecret)
+ {
+ var publicLuaCode = eriDataSource.ExportAsConfigurationSection();
+ if (!string.IsNullOrWhiteSpace(publicLuaCode))
+ await this.RustService.CopyText2Clipboard(publicLuaCode);
+
+ return;
+ }
+
+ var secretResponse = await this.RustService.GetSecret(eriDataSource, SecretStoreType.DATA_SOURCE, isTrying: true);
+ if (!secretResponse.Success)
+ {
+ await this.DialogService.ShowMessageBox(
+ 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),
+ T("Close"));
+ return;
+ }
+
+ var encryption = PluginFactory.EnterpriseEncryption;
+ if (encryption?.IsAvailable != true)
+ {
+ await this.DialogService.ShowMessageBox(
+ T("Export ERI Data Source"),
+ T("Cannot export this ERI data source because no enterprise encryption secret is configured."),
+ T("Close"));
+ return;
+ }
+
+ var usernamePasswordMode = DataSourceERIUsernamePasswordMode.USER_MANAGED;
+ if (eriDataSource.AuthMethod is AuthMethod.TOKEN)
+ {
+ var dialogParameters = new DialogParameters
+ {
+ { x => x.Message, T("This ERI data source has an access token configured. Do you want to include the encrypted access token in the export? Note: The recipient will need the same encryption secret to use the access token.") },
+ };
+
+ var dialogReference = await this.DialogService.ShowAsync(T("Export Access Token?"), dialogParameters, DialogOptions.FULLSCREEN);
+ var dialogResult = await dialogReference.Result;
+ if (dialogResult is null || dialogResult.Canceled)
+ return;
+ }
+ else if (eriDataSource.AuthMethod is AuthMethod.USERNAME_PASSWORD)
+ {
+ var dialogParameters = new DialogParameters
+ {
+ { x => x.DataSource, eriDataSource },
+ };
+
+ var dialogReference = await this.DialogService.ShowAsync(T("Export ERI Data Source"), dialogParameters, DialogOptions.FULLSCREEN);
+ var dialogResult = await dialogReference.Result;
+ if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is not DataSourceERIV1UsernamePasswordExportDialogResult exportResult)
+ return;
+
+ usernamePasswordMode = exportResult.UsernamePasswordMode;
+ }
+
+ var decryptedSecret = await secretResponse.Secret.Decrypt(Program.ENCRYPTION);
+ if (!encryption.TryEncrypt(decryptedSecret, out var encryptedSecret))
+ {
+ await this.DialogService.ShowMessageBox(
+ T("Export ERI Data Source"),
+ T("Cannot export this ERI data source because the authentication secret could not be encrypted."),
+ T("Close"));
+ return;
+ }
+
+ var luaCode = eriDataSource.ExportAsConfigurationSection(
+ encryptedSecret,
+ usernamePasswordMode);
+ if (string.IsNullOrWhiteSpace(luaCode))
+ return;
+
+ await this.RustService.CopyText2Clipboard(luaCode);
+ }
+
+ private async Task EditDataSource(IDataSource dataSource)
+ {
+ if (dataSource.IsEnterpriseConfiguration)
+ return;
+
+ IDataSource? editedDataSource = null;
+ var lockDataSourceIdentity = dataSource is IInternalDataSource
+ && await this.DataSourceEmbeddingService.ShouldLockDataSourceIdentityAsync(dataSource.Id);
+ switch (dataSource)
+ {
+ case DataSourceLocalFile localFile:
+ var localFileDialogParameters = new DialogParameters
+ {
+ { x => x.IsEditing, true },
+ { x => x.DataSource, localFile },
+ { x => x.LockSourceAndEmbedding, lockDataSourceIdentity },
+ { x => x.AvailableEmbeddings, this.availableEmbeddingProviders }
+ };
+
+ var localFileDialogReference = await this.DialogService.ShowAsync(T("Edit Local File Data Source"), localFileDialogParameters, DialogOptions.FULLSCREEN);
+ var localFileDialogResult = await localFileDialogReference.Result;
+ if (localFileDialogResult is null || localFileDialogResult.Canceled)
+ return;
+
+ editedDataSource = (DataSourceLocalFile)localFileDialogResult.Data!;
+ break;
+
+ case DataSourceLocalDirectory localDirectory:
+ var localDirectoryDialogParameters = new DialogParameters
+ {
+ { x => x.IsEditing, true },
+ { x => x.DataSource, localDirectory },
+ { x => x.LockSourceAndEmbedding, lockDataSourceIdentity },
+ { x => x.AvailableEmbeddings, this.availableEmbeddingProviders }
+ };
+
+ var localDirectoryDialogReference = await this.DialogService.ShowAsync(T("Edit Local Directory Data Source"), localDirectoryDialogParameters, DialogOptions.FULLSCREEN);
+ var localDirectoryDialogResult = await localDirectoryDialogReference.Result;
+ if (localDirectoryDialogResult is null || localDirectoryDialogResult.Canceled)
+ return;
+
+ editedDataSource = (DataSourceLocalDirectory)localDirectoryDialogResult.Data!;
+ break;
+
+ case DataSourceERI_V1 eriDataSource:
+ var eriDialogParameters = new DialogParameters
+ {
+ { x => x.IsEditing, true },
+ { x => x.DataSource, eriDataSource },
+ };
+
+ var eriDialogReference = await this.DialogService.ShowAsync(T("Edit ERI v1 Data Source"), eriDialogParameters, DialogOptions.FULLSCREEN);
+ var eriDialogResult = await eriDialogReference.Result;
+ if (eriDialogResult is null || eriDialogResult.Canceled)
+ return;
+
+ editedDataSource = (DataSourceERI_V1)eriDialogResult.Data!;
+ break;
+ }
+
+ if(editedDataSource is null)
+ return;
+
+ this.SettingsManager.ConfigurationData.DataSources[this.SettingsManager.ConfigurationData.DataSources.IndexOf(dataSource)] = editedDataSource;
+
+ await this.SettingsManager.StoreSettings();
+ await this.DataSourceEmbeddingService.QueueDataSourceAsync(editedDataSource);
+ await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
+ }
+
+ private async Task DeleteDataSource(IDataSource dataSource)
+ {
+ if (dataSource.IsEnterpriseConfiguration)
+ return;
+
+ var dialogParameters = new DialogParameters
+ {
+ { x => x.Message, string.Format(T("Are you sure you want to delete the data source '{0}' of type '{1}'?"), dataSource.Name, dataSource.Type.GetDisplayName()) },
+ };
+
+ var dialogReference = await this.DialogService.ShowAsync(T("Delete Data Source"), dialogParameters, DialogOptions.FULLSCREEN);
+ var dialogResult = await dialogReference.Result;
+ if (dialogResult is null || dialogResult.Canceled)
+ return;
+
+ var applyChanges = dataSource is IInternalDataSource;
+
+ // External data sources may need a secret for authentication:
+ if (dataSource is IExternalDataSource externalDataSource)
+ {
+ // When the auth method is NONE or KERBEROS, we don't need to delete a secret.
+ // In the case of KERBEROS, we don't store the Kerberos ticket in the secret store.
+ if(dataSource is IERIDataSource { AuthMethod: AuthMethod.NONE or AuthMethod.KERBEROS })
+ applyChanges = true;
+
+ // All other auth methods require a secret, which we need to delete now:
+ else
+ {
+ var deleteSecretResponse = await this.RustService.DeleteSecret(externalDataSource, SecretStoreType.DATA_SOURCE);
+ if (deleteSecretResponse.Success)
+ applyChanges = true;
+ }
+ }
+
+ if(applyChanges)
+ {
+ this.SettingsManager.ConfigurationData.DataSources.Remove(dataSource);
+ await this.SettingsManager.StoreSettings();
+ await this.DataSourceEmbeddingService.RemoveDataSourceAsync(dataSource);
+ await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
+ }
+ }
+
+ private async Task ShowInformation(IDataSource dataSource)
+ {
+ switch (dataSource)
+ {
+ case DataSourceLocalFile localFile:
+ var localFileDialogParameters = new DialogParameters
+ {
+ { x => x.DataSource, localFile },
+ };
+
+ await this.DialogService.ShowAsync(T("Local File Data Source Information"), localFileDialogParameters, DialogOptions.FULLSCREEN);
+ break;
+
+ case DataSourceLocalDirectory localDirectory:
+ var localDirectoryDialogParameters = new DialogParameters
+ {
+ { x => x.DataSource, localDirectory },
+ };
+
+ await this.DialogService.ShowAsync(T("Local Directory Data Source Information"), localDirectoryDialogParameters, DialogOptions.FULLSCREEN);
+ break;
+
+ case DataSourceERI_V1 eriV1DataSource:
+ var eriV1DialogParameters = new DialogParameters
+ {
+ { x => x.DataSource, eriV1DataSource },
+ };
+
+ await this.DialogService.ShowAsync(T("ERI v1 Data Source Information"), eriV1DialogParameters, DialogOptions.FULLSCREEN);
+ break;
+ }
+ }
+}
diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelDataSources.razor b/app/MindWork AI Studio/Components/Settings/SettingsPanelDataSources.razor
new file mode 100644
index 00000000..9d0e92f0
--- /dev/null
+++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelDataSources.razor
@@ -0,0 +1,10 @@
+@using AIStudio.Settings.DataModel
+@inherits SettingsPanelBase
+
+@if (PreviewFeatures.PRE_RAG_2024.IsEnabled(this.SettingsManager))
+{
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelDataSources.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelDataSources.razor.cs
new file mode 100644
index 00000000..41fcc88b
--- /dev/null
+++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelDataSources.razor.cs
@@ -0,0 +1,3 @@
+namespace AIStudio.Components.Settings;
+
+public partial class SettingsPanelDataSources : SettingsPanelBase;
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogDataSources.razor b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogDataSources.razor
index ec707d1b..b278e115 100644
--- a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogDataSources.razor
+++ b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogDataSources.razor
@@ -1,5 +1,3 @@
-@using AIStudio.Settings
-@using AIStudio.Settings.DataModel
@inherits SettingsDialogBase
@@ -11,113 +9,11 @@
-
- @T("You might configure different data sources. A data source can include one file, all files in a directory, or data from your company. Later, you can incorporate these data sources as needed when the AI requires this data to complete a certain task.")
-
-
-
-
-
-
-
-
-
- @{ var embeddingStatuses = this.DataSourceEmbeddingService.GetStatuses().ToDictionary(status => status.DataSourceId, StringComparer.OrdinalIgnoreCase); }
-
-
-
-
-
-
-
-
-
-
- #
- @T("Name")
- @T("Type")
- @T("Embedding")
- @T("Indexed files")
- @T("Actions")
-
-
- @{ var embeddingStatus = embeddingStatuses.GetValueOrDefault(context.Id); }
- @context.Num
- @context.Name
- @context.Type.GetDisplayName()
- @this.GetEmbeddingName(context)
-
- @if (context is IInternalDataSource)
- {
-
-
-
- @(embeddingStatus is null ? T("Not available") : string.Format(T("{0} of {1}"), embeddingStatus.IndexedFiles, embeddingStatus.TotalFiles))
-
-
- }
- else
- {
- @T("Not applicable")
- }
-
-
-
-
-
-
-
- @if (context.IsEnterpriseConfiguration)
- {
-
-
-
- }
- else
- {
-
-
-
-
-
-
- @if (context is DataSourceERI_V1)
- {
-
- }
-
-
-
- }
-
-
-
-
-
- @if (this.SettingsManager.ConfigurationData.DataSources.Count == 0)
- {
-
- @T("No data sources configured yet.")
-
- }
-
+
-
-
-
- @T("External Data (ERI-Server v1)")
-
-
- @T("Local Directory")
-
-
- @T("Local File")
-
-
-
- @T("Close")
-
-
+
+ @T("Close")
+
-
+
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogDataSources.razor.cs b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogDataSources.razor.cs
index 25680fa9..995c1de2 100644
--- a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogDataSources.razor.cs
+++ b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogDataSources.razor.cs
@@ -1,392 +1,3 @@
-using AIStudio.Settings;
-using AIStudio.Settings.DataModel;
-using AIStudio.Tools.ERIClient.DataModel;
-using AIStudio.Tools.PluginSystem;
-using AIStudio.Tools.Services;
-using Microsoft.AspNetCore.Components;
-
namespace AIStudio.Dialogs.Settings;
-public partial class SettingsDialogDataSources : SettingsDialogBase
-{
- [Inject]
- private DataSourceEmbeddingService DataSourceEmbeddingService { get; init; } = null!;
-
- protected override async Task OnInitializedAsync()
- {
- await base.OnInitializedAsync();
- this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED, Event.RAG_EMBEDDING_STATUS_CHANGED ]);
- }
-
- protected override async Task ProcessIncomingMessage(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
- {
- await base.ProcessIncomingMessage(sendingComponent, triggeredEvent, data);
- if (triggeredEvent is Event.RAG_EMBEDDING_STATUS_CHANGED)
- this.StateHasChanged();
- }
-
- private static Color GetIndexingStatusColor(DataSourceEmbeddingStatus? status)
- {
- if (status is null || status.State is DataSourceEmbeddingState.IDLE or DataSourceEmbeddingState.QUEUED or DataSourceEmbeddingState.RUNNING)
- return Color.Warning;
-
- return status.State is DataSourceEmbeddingState.FAILED || status.FailedFiles > 0
- ? Color.Error
- : Color.Success;
- }
-
- private string GetEmbeddingName(IDataSource dataSource)
- {
- if(dataSource is IInternalDataSource internalDataSource)
- {
- var matchedEmbedding = this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == internalDataSource.EmbeddingId);
- if(matchedEmbedding == default)
- return T("No valid embedding");
-
- return matchedEmbedding.Name;
- }
-
- if(dataSource is IExternalDataSource)
- return T("External (ERI)");
-
- return T("Unknown");
- }
-
- private bool CanRefreshDataSource(IDataSource dataSource)
- {
- return this.DataSourceEmbeddingService.CanRefreshDataSource(dataSource);
- }
-
- private bool HasRefreshableDataSources()
- {
- return this.SettingsManager.ConfigurationData.DataSources.Any(this.CanRefreshDataSource);
- }
-
- private async Task AutomaticRefreshChanged(bool enabled)
- {
- this.SettingsManager.ConfigurationData.App.DataSourceIndexing.AutomaticRefresh = enabled;
- await this.SettingsManager.StoreSettings();
- this.DataSourceEmbeddingService.RefreshAutomaticWatchers();
- await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
- }
-
- private async Task RefreshAllDataSources()
- {
- await this.DataSourceEmbeddingService.QueueAllInternalDataSourcesAsync();
- await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
- }
-
- private async Task RefreshDataSource(IDataSource dataSource)
- {
- if (!this.CanRefreshDataSource(dataSource))
- return;
-
- await this.DataSourceEmbeddingService.QueueDataSourceAsync(dataSource);
- await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
- }
-
- private async Task AddDataSource(DataSourceType type)
- {
- IDataSource? addedDataSource = null;
- switch (type)
- {
- case DataSourceType.LOCAL_FILE:
- var localFileDialogParameters = new DialogParameters
- {
- { x => x.IsEditing, false },
- { x => x.AvailableEmbeddings, this.AvailableEmbeddingProviders }
- };
-
- var localFileDialogReference = await this.DialogService.ShowAsync(T("Add Local File as Data Source"), localFileDialogParameters, DialogOptions.FULLSCREEN);
- var localFileDialogResult = await localFileDialogReference.Result;
- if (localFileDialogResult is null || localFileDialogResult.Canceled)
- return;
-
- var localFile = (DataSourceLocalFile)localFileDialogResult.Data!;
- localFile = localFile with { Num = this.SettingsManager.ConfigurationData.NextDataSourceNum++ };
- addedDataSource = localFile;
- break;
-
- case DataSourceType.LOCAL_DIRECTORY:
- var localDirectoryDialogParameters = new DialogParameters
- {
- { x => x.IsEditing, false },
- { x => x.AvailableEmbeddings, this.AvailableEmbeddingProviders }
- };
-
- var localDirectoryDialogReference = await this.DialogService.ShowAsync(T("Add Local Directory as Data Source"), localDirectoryDialogParameters, DialogOptions.FULLSCREEN);
- var localDirectoryDialogResult = await localDirectoryDialogReference.Result;
- if (localDirectoryDialogResult is null || localDirectoryDialogResult.Canceled)
- return;
-
- var localDirectory = (DataSourceLocalDirectory)localDirectoryDialogResult.Data!;
- localDirectory = localDirectory with { Num = this.SettingsManager.ConfigurationData.NextDataSourceNum++ };
- addedDataSource = localDirectory;
- break;
-
- case DataSourceType.ERI_V1:
- var eriDialogParameters = new DialogParameters
- {
- { x => x.IsEditing, false },
- };
-
- var eriDialogReference = await this.DialogService.ShowAsync(T("Add ERI v1 Data Source"), eriDialogParameters, DialogOptions.FULLSCREEN);
- var eriDialogResult = await eriDialogReference.Result;
- if (eriDialogResult is null || eriDialogResult.Canceled)
- return;
-
- var eriDataSource = (DataSourceERI_V1)eriDialogResult.Data!;
- eriDataSource = eriDataSource with { Num = this.SettingsManager.ConfigurationData.NextDataSourceNum++ };
- addedDataSource = eriDataSource;
- break;
- }
-
- if(addedDataSource is null)
- return;
-
- this.SettingsManager.ConfigurationData.DataSources.Add(addedDataSource);
- await this.SettingsManager.StoreSettings();
- await this.DataSourceEmbeddingService.QueueDataSourceAsync(addedDataSource);
- await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
- }
-
- private async Task ExportDataSource(IDataSource dataSource)
- {
- if (!this.SettingsManager.ConfigurationData.App.ShowAdminSettings)
- return;
-
- if (dataSource is not DataSourceERI_V1 eriDataSource)
- return;
-
- if (eriDataSource.AuthMethod is AuthMethod.KERBEROS)
- {
- await this.DialogService.ShowMessageBox(
- T("Export ERI Data Source"),
- T("Kerberos/SSO ERI data sources cannot be exported yet. Please configure them manually in the configuration plugin."),
- T("Close"));
- return;
- }
-
- var needsSecret = eriDataSource.AuthMethod is AuthMethod.TOKEN or AuthMethod.USERNAME_PASSWORD;
- if (!needsSecret)
- {
- var publicLuaCode = eriDataSource.ExportAsConfigurationSection();
- if (!string.IsNullOrWhiteSpace(publicLuaCode))
- await this.RustService.CopyText2Clipboard(publicLuaCode);
-
- return;
- }
-
- var secretResponse = await this.RustService.GetSecret(eriDataSource, SecretStoreType.DATA_SOURCE, isTrying: true);
- if (!secretResponse.Success)
- {
- await this.DialogService.ShowMessageBox(
- 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),
- T("Close"));
- return;
- }
-
- var encryption = PluginFactory.EnterpriseEncryption;
- if (encryption?.IsAvailable != true)
- {
- await this.DialogService.ShowMessageBox(
- T("Export ERI Data Source"),
- T("Cannot export this ERI data source because no enterprise encryption secret is configured."),
- T("Close"));
- return;
- }
-
- var usernamePasswordMode = DataSourceERIUsernamePasswordMode.USER_MANAGED;
- if (eriDataSource.AuthMethod is AuthMethod.TOKEN)
- {
- var dialogParameters = new DialogParameters
- {
- { x => x.Message, T("This ERI data source has an access token configured. Do you want to include the encrypted access token in the export? Note: The recipient will need the same encryption secret to use the access token.") },
- };
-
- var dialogReference = await this.DialogService.ShowAsync(T("Export Access Token?"), dialogParameters, DialogOptions.FULLSCREEN);
- var dialogResult = await dialogReference.Result;
- if (dialogResult is null || dialogResult.Canceled)
- return;
- }
- else if (eriDataSource.AuthMethod is AuthMethod.USERNAME_PASSWORD)
- {
- var dialogParameters = new DialogParameters
- {
- { x => x.DataSource, eriDataSource },
- };
-
- var dialogReference = await this.DialogService.ShowAsync(T("Export ERI Data Source"), dialogParameters, DialogOptions.FULLSCREEN);
- var dialogResult = await dialogReference.Result;
- if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is not DataSourceERIV1UsernamePasswordExportDialogResult exportResult)
- return;
-
- usernamePasswordMode = exportResult.UsernamePasswordMode;
- }
-
- var decryptedSecret = await secretResponse.Secret.Decrypt(Program.ENCRYPTION);
- if (!encryption.TryEncrypt(decryptedSecret, out var encryptedSecret))
- {
- await this.DialogService.ShowMessageBox(
- T("Export ERI Data Source"),
- T("Cannot export this ERI data source because the authentication secret could not be encrypted."),
- T("Close"));
- return;
- }
-
- var luaCode = eriDataSource.ExportAsConfigurationSection(
- encryptedSecret,
- usernamePasswordMode);
- if (string.IsNullOrWhiteSpace(luaCode))
- return;
-
- await this.RustService.CopyText2Clipboard(luaCode);
- }
-
- private async Task EditDataSource(IDataSource dataSource)
- {
- if (dataSource.IsEnterpriseConfiguration)
- return;
-
- IDataSource? editedDataSource = null;
- var lockDataSourceIdentity = dataSource is IInternalDataSource
- && await this.DataSourceEmbeddingService.ShouldLockDataSourceIdentityAsync(dataSource.Id);
- switch (dataSource)
- {
- case DataSourceLocalFile localFile:
- var localFileDialogParameters = new DialogParameters
- {
- { x => x.IsEditing, true },
- { x => x.DataSource, localFile },
- { x => x.LockSourceAndEmbedding, lockDataSourceIdentity },
- { x => x.AvailableEmbeddings, this.AvailableEmbeddingProviders }
- };
-
- var localFileDialogReference = await this.DialogService.ShowAsync(T("Edit Local File Data Source"), localFileDialogParameters, DialogOptions.FULLSCREEN);
- var localFileDialogResult = await localFileDialogReference.Result;
- if (localFileDialogResult is null || localFileDialogResult.Canceled)
- return;
-
- editedDataSource = (DataSourceLocalFile)localFileDialogResult.Data!;
- break;
-
- case DataSourceLocalDirectory localDirectory:
- var localDirectoryDialogParameters = new DialogParameters
- {
- { x => x.IsEditing, true },
- { x => x.DataSource, localDirectory },
- { x => x.LockSourceAndEmbedding, lockDataSourceIdentity },
- { x => x.AvailableEmbeddings, this.AvailableEmbeddingProviders }
- };
-
- var localDirectoryDialogReference = await this.DialogService.ShowAsync(T("Edit Local Directory Data Source"), localDirectoryDialogParameters, DialogOptions.FULLSCREEN);
- var localDirectoryDialogResult = await localDirectoryDialogReference.Result;
- if (localDirectoryDialogResult is null || localDirectoryDialogResult.Canceled)
- return;
-
- editedDataSource = (DataSourceLocalDirectory)localDirectoryDialogResult.Data!;
- break;
-
- case DataSourceERI_V1 eriDataSource:
- var eriDialogParameters = new DialogParameters
- {
- { x => x.IsEditing, true },
- { x => x.DataSource, eriDataSource },
- };
-
- var eriDialogReference = await this.DialogService.ShowAsync(T("Edit ERI v1 Data Source"), eriDialogParameters, DialogOptions.FULLSCREEN);
- var eriDialogResult = await eriDialogReference.Result;
- if (eriDialogResult is null || eriDialogResult.Canceled)
- return;
-
- editedDataSource = (DataSourceERI_V1)eriDialogResult.Data!;
- break;
- }
-
- if(editedDataSource is null)
- return;
-
- this.SettingsManager.ConfigurationData.DataSources[this.SettingsManager.ConfigurationData.DataSources.IndexOf(dataSource)] = editedDataSource;
-
- await this.SettingsManager.StoreSettings();
- await this.DataSourceEmbeddingService.QueueDataSourceAsync(editedDataSource);
- await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
- }
-
- private async Task DeleteDataSource(IDataSource dataSource)
- {
- if (dataSource.IsEnterpriseConfiguration)
- return;
-
- var dialogParameters = new DialogParameters
- {
- { x => x.Message, string.Format(T("Are you sure you want to delete the data source '{0}' of type '{1}'?"), dataSource.Name, dataSource.Type.GetDisplayName()) },
- };
-
- var dialogReference = await this.DialogService.ShowAsync(T("Delete Data Source"), dialogParameters, DialogOptions.FULLSCREEN);
- var dialogResult = await dialogReference.Result;
- if (dialogResult is null || dialogResult.Canceled)
- return;
-
- var applyChanges = dataSource is IInternalDataSource;
-
- // External data sources may need a secret for authentication:
- if (dataSource is IExternalDataSource externalDataSource)
- {
- // When the auth method is NONE or KERBEROS, we don't need to delete a secret.
- // In the case of KERBEROS, we don't store the Kerberos ticket in the secret store.
- if(dataSource is IERIDataSource { AuthMethod: AuthMethod.NONE or AuthMethod.KERBEROS })
- applyChanges = true;
-
- // All other auth methods require a secret, which we need to delete now:
- else
- {
- var deleteSecretResponse = await this.RustService.DeleteSecret(externalDataSource, SecretStoreType.DATA_SOURCE);
- if (deleteSecretResponse.Success)
- applyChanges = true;
- }
- }
-
- if(applyChanges)
- {
- this.SettingsManager.ConfigurationData.DataSources.Remove(dataSource);
- await this.SettingsManager.StoreSettings();
- await this.DataSourceEmbeddingService.RemoveDataSourceAsync(dataSource);
- await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
- }
- }
-
- private async Task ShowInformation(IDataSource dataSource)
- {
- switch (dataSource)
- {
- case DataSourceLocalFile localFile:
- var localFileDialogParameters = new DialogParameters
- {
- { x => x.DataSource, localFile },
- };
-
- await this.DialogService.ShowAsync(T("Local File Data Source Information"), localFileDialogParameters, DialogOptions.FULLSCREEN);
- break;
-
- case DataSourceLocalDirectory localDirectory:
- var localDirectoryDialogParameters = new DialogParameters
- {
- { x => x.DataSource, localDirectory },
- };
-
- await this.DialogService.ShowAsync(T("Local Directory Data Source Information"), localDirectoryDialogParameters, DialogOptions.FULLSCREEN);
- break;
-
- case DataSourceERI_V1 eriV1DataSource:
- var eriV1DialogParameters = new DialogParameters
- {
- { x => x.DataSource, eriV1DataSource },
- };
-
- await this.DialogService.ShowAsync(T("ERI v1 Data Source Information"), eriV1DialogParameters, DialogOptions.FULLSCREEN);
- break;
- }
- }
-}
+public partial class SettingsDialogDataSources : SettingsDialogBase;
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Pages/Settings.razor b/app/MindWork AI Studio/Pages/Settings.razor
index 7718ba9b..90c5f6ff 100644
--- a/app/MindWork AI Studio/Pages/Settings.razor
+++ b/app/MindWork AI Studio/Pages/Settings.razor
@@ -13,6 +13,7 @@
@if (PreviewFeatures.PRE_RAG_2024.IsEnabled(this.SettingsManager))
{
+
}