diff --git a/app/MindWork AI Studio/Chat/ContentBlockComponent.razor b/app/MindWork AI Studio/Chat/ContentBlockComponent.razor
index 8d0689da..8ea977ce 100644
--- a/app/MindWork AI Studio/Chat/ContentBlockComponent.razor
+++ b/app/MindWork AI Studio/Chat/ContentBlockComponent.razor
@@ -21,6 +21,7 @@
@@ -149,4 +150,4 @@
}
}
-
+
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs b/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs
index 0dcb910c..ba909338 100644
--- a/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs
+++ b/app/MindWork AI Studio/Chat/ContentBlockComponent.razor.cs
@@ -102,6 +102,7 @@ public partial class ContentBlockComponent : MSGComponentBase, IAsyncDisposable
private ElementReference mathContentContainer;
private string lastMathRenderSignature = string.Empty;
private bool hasActiveMathContainer;
+ private bool isOpeningAttachmentsDialog;
private bool isDisposed;
#region Overrides of ComponentBase
@@ -600,8 +601,20 @@ public partial class ContentBlockComponent : MSGComponentBase, IAsyncDisposable
private async Task OpenAttachmentsDialog()
{
- var result = await ReviewAttachmentsDialog.OpenDialogAsync(this.DialogService, this.Content.FileAttachments.ToHashSet());
- this.Content.FileAttachments = result.ToList();
+ if (this.isOpeningAttachmentsDialog)
+ return;
+
+ this.isOpeningAttachmentsDialog = true;
+
+ try
+ {
+ var result = await ReviewAttachmentsDialog.OpenDialogAsync(this.DialogService, this.Content.FileAttachments.ToHashSet());
+ this.Content.FileAttachments = result.ToList();
+ }
+ finally
+ {
+ this.isOpeningAttachmentsDialog = false;
+ }
}
public async ValueTask DisposeAsync()
@@ -613,4 +626,4 @@ public partial class ContentBlockComponent : MSGComponentBase, IAsyncDisposable
await this.DisposeMathContainerIfNeededAsync();
this.Dispose();
}
-}
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/AttachDocuments.razor b/app/MindWork AI Studio/Components/AttachDocuments.razor
index bc66f9c2..aec9af94 100644
--- a/app/MindWork AI Studio/Components/AttachDocuments.razor
+++ b/app/MindWork AI Studio/Components/AttachDocuments.razor
@@ -6,11 +6,11 @@
@if (this.isDraggingOver)
{
+ Content="@this.DocumentPaths.Count"
+ Color="Color.Primary"
+ Overlap="true"
+ Class="cursor-pointer"
+ OnClick="@this.OpenAttachmentsDialog">
@@ -35,6 +36,7 @@
@@ -45,6 +47,7 @@
}
@@ -60,6 +63,7 @@ else
Variant="Variant.Filled"
StartIcon="@Icons.Material.Filled.Add"
Color="Color.Primary"
+ Disabled="@(this.isOpeningFileDialog || this.isOpeningAttachmentsDialog)"
OnClick="@(() => this.AddFilesManually())"
Style="vertical-align: top; margin-top: -2px;"
Size="Size.Small">
diff --git a/app/MindWork AI Studio/Components/AttachDocuments.razor.cs b/app/MindWork AI Studio/Components/AttachDocuments.razor.cs
index acfc0dd2..23496b31 100644
--- a/app/MindWork AI Studio/Components/AttachDocuments.razor.cs
+++ b/app/MindWork AI Studio/Components/AttachDocuments.razor.cs
@@ -78,6 +78,8 @@ public partial class AttachDocuments : MSGComponentBase
private uint numDropAreasAboveThis;
private bool isComponentHovered;
private bool isDraggingOver;
+ private bool isOpeningFileDialog;
+ private bool isOpeningAttachmentsDialog;
#region Overrides of MSGComponentBase
@@ -202,40 +204,64 @@ public partial class AttachDocuments : MSGComponentBase
private async Task AddFilesManually()
{
+ if (this.isOpeningFileDialog)
+ return;
+
+ this.isOpeningFileDialog = true;
+
+ try
+ {
// Ensure that Pandoc is installed and ready:
- var pandocState = await this.PandocAvailabilityService.EnsureAvailabilityAsync(
- showSuccessMessage: false,
- showDialog: true);
+ var pandocState = await this.PandocAvailabilityService.EnsureAvailabilityAsync(
+ showSuccessMessage: false,
+ showDialog: true);
// If Pandoc is not available (user cancelled installation), abort file selection:
- if (!pandocState.IsAvailable)
- {
- this.Logger.LogWarning("The user cancelled the Pandoc installation or Pandoc is not available. Aborting file selection.");
- return;
+ if (!pandocState.IsAvailable)
+ {
+ this.Logger.LogWarning("The user cancelled the Pandoc installation or Pandoc is not available. Aborting file selection.");
+ return;
+ }
+
+ var selectFiles = await this.RustService.SelectFiles(T("Select files to attach"));
+ if (selectFiles.UserCancelled)
+ return;
+
+ foreach (var selectedFilePath in selectFiles.SelectedFilePaths)
+ {
+ if (!File.Exists(selectedFilePath))
+ continue;
+
+ if (!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(FileExtensionValidation.UseCase.ATTACHING_CONTENT, selectedFilePath, this.ValidateMediaFileTypes, this.Provider))
+ continue;
+
+ this.DocumentPaths.Add(FileAttachment.FromPath(selectedFilePath));
+ }
+
+ await this.DocumentPathsChanged.InvokeAsync(this.DocumentPaths);
+ await this.OnChange(this.DocumentPaths);
}
-
- var selectFiles = await this.RustService.SelectFiles(T("Select files to attach"));
- if (selectFiles.UserCancelled)
- return;
-
- foreach (var selectedFilePath in selectFiles.SelectedFilePaths)
+ finally
{
- if (!File.Exists(selectedFilePath))
- continue;
-
- if (!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(FileExtensionValidation.UseCase.ATTACHING_CONTENT, selectedFilePath, this.ValidateMediaFileTypes, this.Provider))
- continue;
-
- this.DocumentPaths.Add(FileAttachment.FromPath(selectedFilePath));
+ this.isOpeningFileDialog = false;
}
-
- await this.DocumentPathsChanged.InvokeAsync(this.DocumentPaths);
- await this.OnChange(this.DocumentPaths);
}
private async Task OpenAttachmentsDialog()
{
- this.DocumentPaths = await ReviewAttachmentsDialog.OpenDialogAsync(this.DialogService, this.DocumentPaths);
+ if (this.isOpeningAttachmentsDialog)
+ return;
+
+ this.isOpeningAttachmentsDialog = true;
+
+ try
+ {
+ this.DocumentPaths = await ReviewAttachmentsDialog.OpenDialogAsync(this.DialogService, this.DocumentPaths);
+ }
+ finally
+ {
+ this.isOpeningAttachmentsDialog = false;
+ }
}
private async Task ClearAllFiles()
diff --git a/app/MindWork AI Studio/Components/ReadFileContent.razor b/app/MindWork AI Studio/Components/ReadFileContent.razor
index 302224de..652e8610 100644
--- a/app/MindWork AI Studio/Components/ReadFileContent.razor
+++ b/app/MindWork AI Studio/Components/ReadFileContent.razor
@@ -1,5 +1,5 @@
@inherits MSGComponentBase
-
+
@if (string.IsNullOrWhiteSpace(this.Text))
{
@T("Use file content as input")
@@ -8,4 +8,4 @@
{
@this.Text
}
-
+
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/ReadFileContent.razor.cs b/app/MindWork AI Studio/Components/ReadFileContent.razor.cs
index d3248937..1ce488a9 100644
--- a/app/MindWork AI Studio/Components/ReadFileContent.razor.cs
+++ b/app/MindWork AI Studio/Components/ReadFileContent.razor.cs
@@ -30,53 +30,64 @@ public partial class ReadFileContent : MSGComponentBase
[Inject]
private PandocAvailabilityService PandocAvailabilityService { get; init; } = null!;
+
+ private bool isSelectingFile;
private async Task SelectFile()
{
- if (this.Disabled)
+ if (this.Disabled || this.isSelectingFile)
return;
- // Ensure that Pandoc is installed and ready:
- var pandocState = await this.PandocAvailabilityService.EnsureAvailabilityAsync(
- showSuccessMessage: false,
- showDialog: true);
-
- // Check if Pandoc is available after the check / installation:
- if (!pandocState.IsAvailable)
- {
- this.Logger.LogWarning("The user cancelled the Pandoc installation or Pandoc is not available. Aborting file selection.");
- return;
- }
-
- var selectedFile = await this.RustService.SelectFile(T("Select file to read its content"));
- if (selectedFile.UserCancelled)
- {
- this.Logger.LogInformation("User cancelled the file selection");
- return;
- }
-
- if(!File.Exists(selectedFile.SelectedFilePath))
- {
- this.Logger.LogWarning("Selected file does not exist: '{FilePath}'", selectedFile.SelectedFilePath);
- return;
- }
-
- if (!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(FileExtensionValidation.UseCase.DIRECTLY_LOADING_CONTENT, selectedFile.SelectedFilePath))
- {
- this.Logger.LogWarning("User attempted to load unsupported file: {FilePath}", selectedFile.SelectedFilePath);
- return;
- }
+ this.isSelectingFile = true;
try
{
- var fileContent = await UserFile.LoadFileData(selectedFile.SelectedFilePath, this.RustService, this.DialogService);
- await this.FileContentChanged.InvokeAsync(fileContent);
- this.Logger.LogInformation("Successfully loaded file content: {FilePath}", selectedFile.SelectedFilePath);
+ // Ensure that Pandoc is installed and ready:
+ var pandocState = await this.PandocAvailabilityService.EnsureAvailabilityAsync(
+ showSuccessMessage: false,
+ showDialog: true);
+
+ // Check if Pandoc is available after the check / installation:
+ if (!pandocState.IsAvailable)
+ {
+ this.Logger.LogWarning("The user cancelled the Pandoc installation or Pandoc is not available. Aborting file selection.");
+ return;
+ }
+
+ var selectedFile = await this.RustService.SelectFile(T("Select file to read its content"));
+ if (selectedFile.UserCancelled)
+ {
+ this.Logger.LogInformation("User cancelled the file selection");
+ return;
+ }
+
+ if(!File.Exists(selectedFile.SelectedFilePath))
+ {
+ this.Logger.LogWarning("Selected file does not exist: '{FilePath}'", selectedFile.SelectedFilePath);
+ return;
+ }
+
+ if (!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(FileExtensionValidation.UseCase.DIRECTLY_LOADING_CONTENT, selectedFile.SelectedFilePath))
+ {
+ this.Logger.LogWarning("User attempted to load unsupported file: {FilePath}", selectedFile.SelectedFilePath);
+ return;
+ }
+
+ try
+ {
+ var fileContent = await UserFile.LoadFileData(selectedFile.SelectedFilePath, this.RustService, this.DialogService);
+ await this.FileContentChanged.InvokeAsync(fileContent);
+ this.Logger.LogInformation("Successfully loaded file content: {FilePath}", selectedFile.SelectedFilePath);
+ }
+ catch (Exception ex)
+ {
+ this.Logger.LogError(ex, "Failed to load file content: {FilePath}", selectedFile.SelectedFilePath);
+ await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Error, T("Failed to load file content")));
+ }
}
- catch (Exception ex)
+ finally
{
- this.Logger.LogError(ex, "Failed to load file content: {FilePath}", selectedFile.SelectedFilePath);
- await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Error, T("Failed to load file content")));
+ this.isSelectingFile = false;
}
}
-}
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/SelectFile.razor b/app/MindWork AI Studio/Components/SelectFile.razor
index de3971e5..bf05dfec 100644
--- a/app/MindWork AI Studio/Components/SelectFile.razor
+++ b/app/MindWork AI Studio/Components/SelectFile.razor
@@ -13,7 +13,7 @@
Variant="Variant.Outlined"
/>
-
+
@T("Choose File")
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/SelectFile.razor.cs b/app/MindWork AI Studio/Components/SelectFile.razor.cs
index 91c7a667..4c7eb166 100644
--- a/app/MindWork AI Studio/Components/SelectFile.razor.cs
+++ b/app/MindWork AI Studio/Components/SelectFile.razor.cs
@@ -35,6 +35,7 @@ public partial class SelectFile : MSGComponentBase
protected ILogger Logger { get; init; } = null!;
private static readonly Dictionary SPELLCHECK_ATTRIBUTES = new();
+ private bool isOpeningFileDialog;
#region Overrides of ComponentBase
@@ -55,10 +56,22 @@ public partial class SelectFile : MSGComponentBase
private async Task OpenFileDialog()
{
- var response = await this.RustService.SelectFile(this.FileDialogTitle, this.Filter, string.IsNullOrWhiteSpace(this.File) ? null : this.File);
- this.Logger.LogInformation($"The user selected the file '{response.SelectedFilePath}'.");
+ if (this.Disabled || this.isOpeningFileDialog)
+ return;
- if (!response.UserCancelled)
- this.InternalFileChanged(response.SelectedFilePath);
+ this.isOpeningFileDialog = true;
+
+ try
+ {
+ var response = await this.RustService.SelectFile(this.FileDialogTitle, this.Filter, string.IsNullOrWhiteSpace(this.File) ? null : this.File);
+ this.Logger.LogInformation($"The user selected the file '{response.SelectedFilePath}'.");
+
+ if (!response.UserCancelled)
+ this.InternalFileChanged(response.SelectedFilePath);
+ }
+ finally
+ {
+ this.isOpeningFileDialog = false;
+ }
}
}
\ No newline at end of file