The dialog for file attachments will only open once.

This commit is contained in:
hart_s3 2026-04-14 14:35:17 +02:00
parent 09258c7548
commit 3d03d36f0c
8 changed files with 146 additions and 78 deletions

View File

@ -21,6 +21,7 @@
<MudTooltip Text="@T("Number of attachments")" Placement="Placement.Bottom"> <MudTooltip Text="@T("Number of attachments")" Placement="Placement.Bottom">
<MudBadge Content="@this.Content.FileAttachments.Count" Color="Color.Primary" Overlap="true" BadgeClass="sources-card-header"> <MudBadge Content="@this.Content.FileAttachments.Count" Color="Color.Primary" Overlap="true" BadgeClass="sources-card-header">
<MudIconButton Icon="@Icons.Material.Filled.AttachFile" <MudIconButton Icon="@Icons.Material.Filled.AttachFile"
Disabled="@this.isOpeningAttachmentsDialog"
OnClick="@this.OpenAttachmentsDialog"/> OnClick="@this.OpenAttachmentsDialog"/>
</MudBadge> </MudBadge>
</MudTooltip> </MudTooltip>

View File

@ -102,6 +102,7 @@ public partial class ContentBlockComponent : MSGComponentBase, IAsyncDisposable
private ElementReference mathContentContainer; private ElementReference mathContentContainer;
private string lastMathRenderSignature = string.Empty; private string lastMathRenderSignature = string.Empty;
private bool hasActiveMathContainer; private bool hasActiveMathContainer;
private bool isOpeningAttachmentsDialog;
private bool isDisposed; private bool isDisposed;
#region Overrides of ComponentBase #region Overrides of ComponentBase
@ -599,10 +600,22 @@ public partial class ContentBlockComponent : MSGComponentBase, IAsyncDisposable
} }
private async Task OpenAttachmentsDialog() private async Task OpenAttachmentsDialog()
{
if (this.isOpeningAttachmentsDialog)
return;
this.isOpeningAttachmentsDialog = true;
try
{ {
var result = await ReviewAttachmentsDialog.OpenDialogAsync(this.DialogService, this.Content.FileAttachments.ToHashSet()); var result = await ReviewAttachmentsDialog.OpenDialogAsync(this.DialogService, this.Content.FileAttachments.ToHashSet());
this.Content.FileAttachments = result.ToList(); this.Content.FileAttachments = result.ToList();
} }
finally
{
this.isOpeningAttachmentsDialog = false;
}
}
public async ValueTask DisposeAsync() public async ValueTask DisposeAsync()
{ {

View File

@ -19,6 +19,7 @@
Typo="Typo.body2" Typo="Typo.body2"
Variant="Variant.Outlined" Variant="Variant.Outlined"
ReadOnly="true" ReadOnly="true"
Disabled="@(this.isOpeningFileDialog || this.isOpeningAttachmentsDialog)"
/> />
</MudLink> </MudLink>
</MudBadge> </MudBadge>
@ -35,6 +36,7 @@
<MudIconButton <MudIconButton
Icon="@Icons.Material.Filled.AttachFile" Icon="@Icons.Material.Filled.AttachFile"
Color="Color.Default" Color="Color.Default"
Disabled="@(this.isOpeningFileDialog || this.isOpeningAttachmentsDialog)"
OnClick="@this.AddFilesManually"/> OnClick="@this.AddFilesManually"/>
</MudBadge> </MudBadge>
</MudTooltip> </MudTooltip>
@ -45,6 +47,7 @@
<MudIconButton <MudIconButton
Icon="@Icons.Material.Filled.AttachFile" Icon="@Icons.Material.Filled.AttachFile"
Color="Color.Default" Color="Color.Default"
Disabled="@(this.isOpeningFileDialog || this.isOpeningAttachmentsDialog)"
OnClick="@this.AddFilesManually"/> OnClick="@this.AddFilesManually"/>
</MudTooltip> </MudTooltip>
} }
@ -60,6 +63,7 @@ else
Variant="Variant.Filled" Variant="Variant.Filled"
StartIcon="@Icons.Material.Filled.Add" StartIcon="@Icons.Material.Filled.Add"
Color="Color.Primary" Color="Color.Primary"
Disabled="@(this.isOpeningFileDialog || this.isOpeningAttachmentsDialog)"
OnClick="@(() => this.AddFilesManually())" OnClick="@(() => this.AddFilesManually())"
Style="vertical-align: top; margin-top: -2px;" Style="vertical-align: top; margin-top: -2px;"
Size="Size.Small"> Size="Size.Small">

View File

@ -78,6 +78,8 @@ public partial class AttachDocuments : MSGComponentBase
private uint numDropAreasAboveThis; private uint numDropAreasAboveThis;
private bool isComponentHovered; private bool isComponentHovered;
private bool isDraggingOver; private bool isDraggingOver;
private bool isOpeningFileDialog;
private bool isOpeningAttachmentsDialog;
#region Overrides of MSGComponentBase #region Overrides of MSGComponentBase
@ -201,6 +203,13 @@ public partial class AttachDocuments : MSGComponentBase
private string dragClass = DEFAULT_DRAG_CLASS; private string dragClass = DEFAULT_DRAG_CLASS;
private async Task AddFilesManually() private async Task AddFilesManually()
{
if (this.isOpeningFileDialog)
return;
this.isOpeningFileDialog = true;
try
{ {
// Ensure that Pandoc is installed and ready: // Ensure that Pandoc is installed and ready:
var pandocState = await this.PandocAvailabilityService.EnsureAvailabilityAsync( var pandocState = await this.PandocAvailabilityService.EnsureAvailabilityAsync(
@ -232,11 +241,28 @@ public partial class AttachDocuments : MSGComponentBase
await this.DocumentPathsChanged.InvokeAsync(this.DocumentPaths); await this.DocumentPathsChanged.InvokeAsync(this.DocumentPaths);
await this.OnChange(this.DocumentPaths); await this.OnChange(this.DocumentPaths);
} }
finally
{
this.isOpeningFileDialog = false;
}
}
private async Task OpenAttachmentsDialog() private async Task OpenAttachmentsDialog()
{
if (this.isOpeningAttachmentsDialog)
return;
this.isOpeningAttachmentsDialog = true;
try
{ {
this.DocumentPaths = await ReviewAttachmentsDialog.OpenDialogAsync(this.DialogService, this.DocumentPaths); this.DocumentPaths = await ReviewAttachmentsDialog.OpenDialogAsync(this.DialogService, this.DocumentPaths);
} }
finally
{
this.isOpeningAttachmentsDialog = false;
}
}
private async Task ClearAllFiles() private async Task ClearAllFiles()
{ {

View File

@ -1,5 +1,5 @@
@inherits MSGComponentBase @inherits MSGComponentBase
<MudButton StartIcon="@Icons.Material.Filled.Description" OnClick="@(async () => await this.SelectFile())" Variant="Variant.Filled" Class="mb-3" Disabled="@this.Disabled"> <MudButton StartIcon="@Icons.Material.Filled.Description" OnClick="@(async () => await this.SelectFile())" Variant="Variant.Filled" Class="mb-3" Disabled="@(this.Disabled || this.isSelectingFile)">
@if (string.IsNullOrWhiteSpace(this.Text)) @if (string.IsNullOrWhiteSpace(this.Text))
{ {
@T("Use file content as input") @T("Use file content as input")

View File

@ -31,11 +31,17 @@ public partial class ReadFileContent : MSGComponentBase
[Inject] [Inject]
private PandocAvailabilityService PandocAvailabilityService { get; init; } = null!; private PandocAvailabilityService PandocAvailabilityService { get; init; } = null!;
private bool isSelectingFile;
private async Task SelectFile() private async Task SelectFile()
{ {
if (this.Disabled) if (this.Disabled || this.isSelectingFile)
return; return;
this.isSelectingFile = true;
try
{
// Ensure that Pandoc is installed and ready: // Ensure that Pandoc is installed and ready:
var pandocState = await this.PandocAvailabilityService.EnsureAvailabilityAsync( var pandocState = await this.PandocAvailabilityService.EnsureAvailabilityAsync(
showSuccessMessage: false, showSuccessMessage: false,
@ -79,4 +85,9 @@ public partial class ReadFileContent : MSGComponentBase
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Error, T("Failed to load file content"))); await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Error, T("Failed to load file content")));
} }
} }
finally
{
this.isSelectingFile = false;
}
}
} }

View File

@ -13,7 +13,7 @@
Variant="Variant.Outlined" Variant="Variant.Outlined"
/> />
<MudButton StartIcon="@Icons.Material.Filled.FolderOpen" Variant="Variant.Outlined" Color="Color.Primary" Disabled="this.Disabled" OnClick="@this.OpenFileDialog"> <MudButton StartIcon="@Icons.Material.Filled.FolderOpen" Variant="Variant.Outlined" Color="Color.Primary" Disabled="@(this.Disabled || this.isOpeningFileDialog)" OnClick="@this.OpenFileDialog">
@T("Choose File") @T("Choose File")
</MudButton> </MudButton>
</MudStack> </MudStack>

View File

@ -35,6 +35,7 @@ public partial class SelectFile : MSGComponentBase
protected ILogger<SelectFile> Logger { get; init; } = null!; protected ILogger<SelectFile> Logger { get; init; } = null!;
private static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new(); private static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new();
private bool isOpeningFileDialog;
#region Overrides of ComponentBase #region Overrides of ComponentBase
@ -54,6 +55,13 @@ public partial class SelectFile : MSGComponentBase
} }
private async Task OpenFileDialog() private async Task OpenFileDialog()
{
if (this.Disabled || this.isOpeningFileDialog)
return;
this.isOpeningFileDialog = true;
try
{ {
var response = await this.RustService.SelectFile(this.FileDialogTitle, this.Filter, string.IsNullOrWhiteSpace(this.File) ? null : this.File); 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}'."); this.Logger.LogInformation($"The user selected the file '{response.SelectedFilePath}'.");
@ -61,4 +69,9 @@ public partial class SelectFile : MSGComponentBase
if (!response.UserCancelled) if (!response.UserCancelled)
this.InternalFileChanged(response.SelectedFilePath); this.InternalFileChanged(response.SelectedFilePath);
} }
finally
{
this.isOpeningFileDialog = false;
}
}
} }