mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-14 13:13:48 +00:00
Improve Linux clipboard support and file handling (#872)
This commit is contained in:
1 parent
f666760415
commit
8fa0c4db01
16 files changed
+343
-166
No files matched your search
@@ -102,13 +102,14 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
private uint numDropAreasAboveThis;
|
||||
private bool isComponentHovered;
|
||||
private bool isDraggingOver;
|
||||
private bool isFileDialogOpen;
|
||||
private MediaImportOwner EffectiveImportOwner => this.OwnerChat is not null
|
||||
? MediaImportOwner.ForChat(this.OwnerChat.ChatId)
|
||||
: this.ImportOwner ?? this.fallbackMediaImportOwner;
|
||||
|
||||
private MediaImportTarget EffectiveMediaImportTarget => new(this.EffectiveImportOwner, string.IsNullOrWhiteSpace(this.Name) ? "attachments" : this.Name);
|
||||
|
||||
private bool IsUnavailable => this.Disabled || this.MediaTranscriptionService.IsBusy(this.EffectiveImportOwner);
|
||||
private bool IsUnavailable => this.Disabled || this.isFileDialogOpen || this.MediaTranscriptionService.IsBusy(this.EffectiveImportOwner);
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
@@ -310,13 +311,21 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
if (this.IsUnavailable)
|
||||
return;
|
||||
|
||||
var selectFiles = await this.RustService.SelectFiles(T("Select files to attach"));
|
||||
if (selectFiles.UserCancelled)
|
||||
return;
|
||||
this.isFileDialogOpen = true;
|
||||
try
|
||||
{
|
||||
var selectFiles = await this.RustService.SelectFiles(T("Select files to attach"));
|
||||
if (selectFiles.UserCancelled)
|
||||
return;
|
||||
|
||||
await this.AddFileBatchAsync(selectFiles.SelectedFilePaths);
|
||||
await this.DocumentPathsChanged.InvokeAsync(this.DocumentPaths);
|
||||
await this.OnChange(this.DocumentPaths);
|
||||
await this.AddFileBatchAsync(selectFiles.SelectedFilePaths);
|
||||
await this.DocumentPathsChanged.InvokeAsync(this.DocumentPaths);
|
||||
await this.OnChange(this.DocumentPaths);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.isFileDialogOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OpenAttachmentsDialog()
|
||||
@@ -397,7 +406,17 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
|
||||
private async Task AddFileBatchAsync(IEnumerable<string> paths)
|
||||
{
|
||||
var existingPaths = paths.Where(File.Exists).ToList();
|
||||
var pathList = paths.ToList();
|
||||
var inaccessiblePaths = pathList.Where(path => !File.Exists(path)).ToList();
|
||||
if (inaccessiblePaths.Count > 0)
|
||||
{
|
||||
this.Logger.LogWarning("Could not access {Count} dropped or selected file(s): {Paths}", inaccessiblePaths.Count, string.Join(", ", inaccessiblePaths));
|
||||
await this.MessageBus.SendWarning(new(
|
||||
Icons.Material.Filled.Warning,
|
||||
this.T("Some files could not be accessed. Please select them with the file chooser instead.")));
|
||||
}
|
||||
|
||||
var existingPaths = pathList.Except(inaccessiblePaths).ToList();
|
||||
var mediaPaths = existingPaths.Where(IsTranscribableMedia).ToList();
|
||||
var regularPaths = existingPaths.Except(mediaPaths).ToList();
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Small"
|
||||
Disabled="@this.IsDisabled"
|
||||
Disabled="@(this.IsDisabled || this.isFileDialogOpen)"
|
||||
Class="mb-1"
|
||||
OnClick="@this.OpenFileDialog">
|
||||
@T("Choose File")
|
||||
|
||||
@@ -49,6 +49,7 @@ public partial class ConfigurationFile : ConfigurationBaseCore
|
||||
private RustService RustService { get; init; } = null!;
|
||||
|
||||
private string internalText = string.Empty;
|
||||
private bool isFileDialogOpen;
|
||||
private readonly Timer timer = new(TimeSpan.FromMilliseconds(500))
|
||||
{
|
||||
AutoReset = false
|
||||
@@ -90,13 +91,24 @@ public partial class ConfigurationFile : ConfigurationBaseCore
|
||||
|
||||
private async Task OpenFileDialog()
|
||||
{
|
||||
var response = await this.RustService.SelectFile(this.FileDialogTitle, this.Filter, string.IsNullOrWhiteSpace(this.internalText) ? null : this.internalText);
|
||||
if (response.UserCancelled)
|
||||
if (this.isFileDialogOpen)
|
||||
return;
|
||||
|
||||
this.timer.Stop();
|
||||
this.internalText = response.SelectedFilePath;
|
||||
await this.OptionChanged(response.SelectedFilePath);
|
||||
this.isFileDialogOpen = true;
|
||||
try
|
||||
{
|
||||
var response = await this.RustService.SelectFile(this.FileDialogTitle, this.Filter, string.IsNullOrWhiteSpace(this.internalText) ? null : this.internalText);
|
||||
if (response.UserCancelled)
|
||||
return;
|
||||
|
||||
this.timer.Stop();
|
||||
this.internalText = response.SelectedFilePath;
|
||||
await this.OptionChanged(response.SelectedFilePath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.isFileDialogOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OptionChanged(string updatedText)
|
||||
|
||||
@@ -74,9 +74,10 @@ public partial class ReadFileContent : MSGComponentBase
|
||||
private string dragClass = DEFAULT_DRAG_CLASS;
|
||||
private uint numDropAreasAboveThis;
|
||||
private bool isComponentHovered;
|
||||
private bool isFileDialogOpen;
|
||||
private bool IsCurrentTargetBusy => this.MediaTranscriptionService.GetSnapshot(this.EffectiveImportOwner) is { IsBusy: true } snapshot
|
||||
&& snapshot.Target == this.EffectiveMediaImportTarget;
|
||||
private bool IsUnavailable => this.Disabled || this.MediaTranscriptionService.IsBusy(this.EffectiveImportOwner);
|
||||
private bool IsUnavailable => this.Disabled || this.isFileDialogOpen || this.MediaTranscriptionService.IsBusy(this.EffectiveImportOwner);
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
@@ -217,14 +218,22 @@ public partial class ReadFileContent : MSGComponentBase
|
||||
if (this.IsUnavailable)
|
||||
return;
|
||||
|
||||
var selectedFile = await this.RustService.SelectFile(T("Select file to read its content"));
|
||||
if (selectedFile.UserCancelled)
|
||||
this.isFileDialogOpen = true;
|
||||
try
|
||||
{
|
||||
this.Logger.LogInformation("User cancelled the 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;
|
||||
}
|
||||
|
||||
await this.LoadFileIfValid(selectedFile.SelectedFilePath);
|
||||
await this.LoadFileIfValid(selectedFile.SelectedFilePath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.isFileDialogOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> EnsurePandocAvailability()
|
||||
@@ -246,6 +255,15 @@ public partial class ReadFileContent : MSGComponentBase
|
||||
|
||||
private async Task LoadFirstValidFile(List<string> paths)
|
||||
{
|
||||
var inaccessiblePaths = paths.Where(path => !File.Exists(path)).ToList();
|
||||
if (inaccessiblePaths.Count > 0)
|
||||
{
|
||||
this.Logger.LogWarning("Could not access {Count} dropped file(s): {Paths}", inaccessiblePaths.Count, string.Join(", ", inaccessiblePaths));
|
||||
await this.MessageBus.SendWarning(new(
|
||||
Icons.Material.Filled.Warning,
|
||||
this.T("Some dropped files could not be accessed. Please select them with the file chooser instead.")));
|
||||
}
|
||||
|
||||
foreach (var path in paths)
|
||||
{
|
||||
if (await this.LoadFileIfValid(path))
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
Variant="Variant.Outlined"
|
||||
/>
|
||||
|
||||
<MudButton StartIcon="@Icons.Material.Filled.FolderOpen" Variant="Variant.Outlined" Color="Color.Primary" Disabled="this.Disabled" OnClick="@this.OpenDirectoryDialog">
|
||||
<MudButton StartIcon="@Icons.Material.Filled.FolderOpen" Variant="Variant.Outlined" Color="Color.Primary" Disabled="@(this.Disabled || this.isDirectoryDialogOpen)" OnClick="@this.OpenDirectoryDialog">
|
||||
@T("Choose Directory")
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
@@ -31,6 +31,7 @@ public partial class SelectDirectory : MSGComponentBase
|
||||
protected ILogger<SelectDirectory> Logger { get; init; } = null!;
|
||||
|
||||
private static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new();
|
||||
private bool isDirectoryDialogOpen;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
@@ -51,10 +52,21 @@ public partial class SelectDirectory : MSGComponentBase
|
||||
|
||||
private async Task OpenDirectoryDialog()
|
||||
{
|
||||
var response = await this.RustService.SelectDirectory(this.DirectoryDialogTitle, string.IsNullOrWhiteSpace(this.Directory) ? null : this.Directory);
|
||||
this.Logger.LogInformation($"The user selected the directory '{response.SelectedDirectory}'.");
|
||||
if (this.isDirectoryDialogOpen)
|
||||
return;
|
||||
|
||||
if (!response.UserCancelled)
|
||||
this.InternalDirectoryChanged(response.SelectedDirectory);
|
||||
this.isDirectoryDialogOpen = true;
|
||||
try
|
||||
{
|
||||
var response = await this.RustService.SelectDirectory(this.DirectoryDialogTitle, string.IsNullOrWhiteSpace(this.Directory) ? null : this.Directory);
|
||||
this.Logger.LogInformation("The user selected the directory '{SelectedDirectory}'.", response.SelectedDirectory);
|
||||
|
||||
if (!response.UserCancelled)
|
||||
this.InternalDirectoryChanged(response.SelectedDirectory);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.isDirectoryDialogOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
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.isFileDialogOpen)" OnClick="@this.OpenFileDialog">
|
||||
@T("Choose File")
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
@@ -35,6 +35,7 @@ public partial class SelectFile : MSGComponentBase
|
||||
protected ILogger<SelectFile> Logger { get; init; } = null!;
|
||||
|
||||
private static readonly Dictionary<string, object?> SPELLCHECK_ATTRIBUTES = new();
|
||||
private bool isFileDialogOpen;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
|
||||
@@ -55,10 +56,21 @@ 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.isFileDialogOpen)
|
||||
return;
|
||||
|
||||
if (!response.UserCancelled)
|
||||
this.InternalFileChanged(response.SelectedFilePath);
|
||||
this.isFileDialogOpen = 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 '{SelectedFilePath}'.", response.SelectedFilePath);
|
||||
|
||||
if (!response.UserCancelled)
|
||||
this.InternalFileChanged(response.SelectedFilePath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.isFileDialogOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user