Limit a page to one drop zone per layer

This commit is contained in:
Thorsten Sommer 2026-09-09 17:34:22 +02:00
parent 3439b91c28
commit 29a9c0f35d
Signed by untrusted user who does not match committer: tsommer
GPG Key ID: 371BBA77A02C0108
2 changed files with 15 additions and 7 deletions

View File

@ -7,9 +7,7 @@
@T("Input") @T("Input")
</MudText> </MudText>
@* This page carries a second drop zone for the instructions, so neither of them catches all <SelectDirectory Label="@T("Folder containing your documents")" DirectoryDialogTitle="@T("Select the folder containing your documents")" @bind-Directory="@this.inputDirectory" Validation="@this.ValidateInputDirectory" Disabled="@this.isProcessingBatch"/>
documents: with two targets, only the one under the mouse may take the drop. *@
<SelectDirectory Label="@T("Folder containing your documents")" DirectoryDialogTitle="@T("Select the folder containing your documents")" @bind-Directory="@this.inputDirectory" Validation="@this.ValidateInputDirectory" Disabled="@this.isProcessingBatch" EnableDragDrop="true" Layer="@DropLayers.ASSISTANTS"/>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2" Class="mb-1"> <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2" Class="mb-1">
<MudTextField T="string" @bind-Text="@this.filePatterns" Validation="@this.ValidateFilePatterns" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("File patterns")" HelperText="@T("Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx")" AdornmentIcon="@Icons.Material.Filled.FilterAlt" Adornment="Adornment.Start" Variant="Variant.Outlined" Margin="Margin.Normal" Class="flex-grow-1" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.filePatterns" Validation="@this.ValidateFilePatterns" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("File patterns")" HelperText="@T("Which files should be processed? Separate multiple patterns with a semicolon, e.g., *.pdf;*.docx")" AdornmentIcon="@Icons.Material.Filled.FilterAlt" Adornment="Adornment.Start" Variant="Variant.Outlined" Margin="Margin.Normal" Class="flex-grow-1" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
@ -46,7 +44,7 @@
@if (this.promptSource is BatchProcessingPromptSource.FREE_PROMPT) @if (this.promptSource is BatchProcessingPromptSource.FREE_PROMPT)
{ {
<ReadFileContent Text="@T("Load prompt from file")" @bind-FileContent="@this.freePrompt" EnableDragDrop="true" Layer="@DropLayers.ASSISTANTS" Disabled="@this.isProcessingBatch"/> <ReadFileContent Text="@T("Load prompt from file")" @bind-FileContent="@this.freePrompt" EnableDragDrop="true" Layer="@DropLayers.ASSISTANTS" CatchAllDocuments="true" Disabled="@this.isProcessingBatch"/>
<MudTextField T="string" @bind-Text="@this.freePrompt" Validation="@this.ValidateFreePrompt" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("What should the AI do with each document?")" HelperText="@T("These instructions are applied to every single document of the batch run.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" AutoGrow="@true" MaxLines="26" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/> <MudTextField T="string" @bind-Text="@this.freePrompt" Validation="@this.ValidateFreePrompt" Immediate="@true" Disabled="@this.isProcessingBatch" Label="@T("What should the AI do with each document?")" HelperText="@T("These instructions are applied to every single document of the batch run.")" Variant="Variant.Outlined" Margin="Margin.Normal" Lines="5" AutoGrow="@true" MaxLines="26" Class="mb-3" UserAttributes="@USER_INPUT_ATTRIBUTES"/>
@ -54,7 +52,7 @@
} }
else if (this.promptSource is BatchProcessingPromptSource.FILE_IMPORT) else if (this.promptSource is BatchProcessingPromptSource.FILE_IMPORT)
{ {
<ReadFileContent Text="@T("Select the file with your instructions")" @bind-FileContent="@this.ImportedPrompt" Filter="@([FileTypes.MARKDOWN])" ShowAttachedDocumentState="@true" EnableDragDrop="true" Layer="@DropLayers.ASSISTANTS" Disabled="@this.isProcessingBatch"/> <ReadFileContent Text="@T("Select the file with your instructions")" @bind-FileContent="@this.ImportedPrompt" Filter="@([FileTypes.MARKDOWN])" ShowAttachedDocumentState="@true" EnableDragDrop="true" Layer="@DropLayers.ASSISTANTS" CatchAllDocuments="true" Disabled="@this.isProcessingBatch"/>
@if (!string.IsNullOrWhiteSpace(this.promptFilePath)) @if (!string.IsNullOrWhiteSpace(this.promptFilePath))
{ {

View File

@ -36,6 +36,15 @@ public partial class PathDropZone : MSGComponentBase
/// <summary> /// <summary>
/// Catch all documents that are hovered over the AI Studio window and not only over the drop zone. /// Catch all documents that are hovered over the AI Studio window and not only over the drop zone.
/// </summary> /// </summary>
/// <remarks>
/// Practically every zone needs this today. Hovering is detected through mouse events, and no
/// webview delivers those while a native drag is in progress, so a zone without this flag
/// hardly ever catches anything. The consequence is that two zones of the same layer cannot be
/// told apart: the one carrying this flag takes every drop, including the ones meant for the
/// other. A page may therefore hold only one zone per layer. Lifting that limit needs the
/// cursor position, which the runtime receives from Tauri and currently discards in
/// app_window.rs.
/// </remarks>
[Parameter] [Parameter]
public bool CatchAllDocuments { get; set; } public bool CatchAllDocuments { get; set; }
@ -149,8 +158,9 @@ public partial class PathDropZone : MSGComponentBase
if(this.Disabled || this.numDropAreasAboveThis > 0) if(this.Disabled || this.numDropAreasAboveThis > 0)
return; return;
// The webview gets no DOM drag events while a native drag is in progress, so the mouse is // A native drag delivers no DOM events at all, mouse events included. This fires before a
// what tells us whether the user is aiming at this zone: // drag begins, while the pointer still moves freely, which makes it a hint about where the
// user is aiming rather than a reliable signal. See the remarks on CatchAllDocuments:
this.isComponentHovered = true; this.isComponentHovered = true;
this.SetDragClass(); this.SetDragClass();
this.StateHasChanged(); this.StateHasChanged();