Fixed duplicate native file dialogs on Windows by parenting them (#735)
Some checks are pending
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,deb,updater, appimage,deb) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,deb,updater, appimage,deb) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions

This commit is contained in:
Thorsten Sommer 2026-04-15 18:19:53 +02:00 committed by GitHub
parent d56eb5b4ea
commit 446f344162
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 49 additions and 19 deletions

View File

@ -186,6 +186,7 @@ Multi-level confidence scheme allows users to control which providers see which
- **File changes require Write/Edit tools** - Never use bash commands like `cat <<EOF` or `echo >` - **File changes require Write/Edit tools** - Never use bash commands like `cat <<EOF` or `echo >`
- **End of file formatting** - Do not append an extra empty line at the end of files. - **End of file formatting** - Do not append an extra empty line at the end of files.
- **No automated formatting for Rust or .NET files** - Never run automated formatters on Rust files (`.rs`) or .NET files (`.cs`, `.razor`, `.csproj`, etc.). Only make the minimal manual formatting changes required for the specific edit.
- **Spaces in paths** - Always quote paths with spaces in bash commands - **Spaces in paths** - Always quote paths with spaces in bash commands
- **Agent-run .NET builds** - Do not run `.NET` builds from an agent. Ask the user to run the build locally in their IDE, preferably via `cd app/Build && dotnet run build` in an IDE terminal, then wait for their feedback before continuing. - **Agent-run .NET builds** - Do not run `.NET` builds from an agent. Ask the user to run the build locally in their IDE, preferably via `cd app/Build && dotnet run build` in an IDE terminal, then wait for their feedback before continuing.
- **Debug environment** - Reads `startup.env` file with IPC credentials - **Debug environment** - Reads `startup.env` file with IPC credentials

View File

@ -32,6 +32,7 @@
- Fixed an issue with chat templates that could stop working because the stored validation result for attached files was reused. AI Studio now checks attached files again when you use a chat template. - Fixed an issue with chat templates that could stop working because the stored validation result for attached files was reused. AI Studio now checks attached files again when you use a chat template.
- Fixed an issue with voice recording where AI Studio could log errors and keep the feature available even though required parts failed to initialize. Voice recording is now disabled automatically for the current session in that case. - Fixed an issue with voice recording where AI Studio could log errors and keep the feature available even though required parts failed to initialize. Voice recording is now disabled automatically for the current session in that case.
- Fixed an issue where the app could turn white or appear invisible in certain chats after HTML-like content was shown. Thanks, Inga, for reporting this issue and providing some context on how to reproduce it. - Fixed an issue where the app could turn white or appear invisible in certain chats after HTML-like content was shown. Thanks, Inga, for reporting this issue and providing some context on how to reproduce it.
- Fixed an issue where file and folder selection dialogs could open more than once on Windows. Thanks to Bernhard for reporting this bug.
- Fixed an issue where exporting to Word could fail when the message contained certain formatting. - Fixed an issue where exporting to Word could fail when the message contained certain formatting.
- Fixed security issues in the native app runtime by strengthening how AI Studio creates and protects the secret values used for its internal secure connection. - Fixed security issues in the native app runtime by strengthening how AI Studio creates and protects the secret values used for its internal secure connection.
- Updated several security-sensitive Rust dependencies in the native runtime to address known vulnerabilities. - Updated several security-sensitive Rust dependencies in the native runtime to address known vulnerabilities.

View File

@ -133,7 +133,7 @@ pub fn start_tauri() {
if !matches!(event, RunEvent::MainEventsCleared) { if !matches!(event, RunEvent::MainEventsCleared) {
debug!(Source = "Tauri"; "Tauri event received: location=app event handler , event={event:?}"); debug!(Source = "Tauri"; "Tauri event received: location=app event handler , event={event:?}");
} }
match event { match event {
RunEvent::WindowEvent { event, label, .. } => { RunEvent::WindowEvent { event, label, .. } => {
match event { match event {
@ -476,23 +476,23 @@ pub async fn install_update(_token: APIToken) {
/// Let the user select a directory. /// Let the user select a directory.
#[post("/select/directory?<title>", data = "<previous_directory>")] #[post("/select/directory?<title>", data = "<previous_directory>")]
pub fn select_directory(_token: APIToken, title: &str, previous_directory: Option<Json<PreviousDirectory>>) -> Json<DirectorySelectionResponse> { pub fn select_directory(
_token: APIToken,
title: &str,
previous_directory: Option<Json<PreviousDirectory>>,
) -> Json<DirectorySelectionResponse> {
let folder_path = match previous_directory { let folder_path = match previous_directory {
Some(previous) => { Some(previous) => {
let previous_path = previous.path.as_str(); let previous_path = previous.path.as_str();
FileDialogBuilder::new() create_file_dialog()
.set_title(title) .set_title(title)
.set_directory(previous_path) .set_directory(previous_path)
.pick_folder() .pick_folder()
}, },
None => { None => create_file_dialog().set_title(title).pick_folder(),
FileDialogBuilder::new()
.set_title(title)
.pick_folder()
},
}; };
match folder_path { match folder_path {
Some(path) => { Some(path) => {
info!("User selected directory: {path:?}"); info!("User selected directory: {path:?}");
@ -545,10 +545,12 @@ pub struct DirectorySelectionResponse {
/// Let the user select a file. /// Let the user select a file.
#[post("/select/file", data = "<payload>")] #[post("/select/file", data = "<payload>")]
pub fn select_file(_token: APIToken, payload: Json<SelectFileOptions>) -> Json<FileSelectionResponse> { pub fn select_file(
_token: APIToken,
payload: Json<SelectFileOptions>,
) -> Json<FileSelectionResponse> {
// Create a new file dialog builder: // Create a new file dialog builder:
let file_dialog = FileDialogBuilder::new(); let file_dialog = create_file_dialog();
// Set the title of the file dialog: // Set the title of the file dialog:
let file_dialog = file_dialog.set_title(&payload.title); let file_dialog = file_dialog.set_title(&payload.title);
@ -589,10 +591,12 @@ pub fn select_file(_token: APIToken, payload: Json<SelectFileOptions>) -> Json<F
/// Let the user select some files. /// Let the user select some files.
#[post("/select/files", data = "<payload>")] #[post("/select/files", data = "<payload>")]
pub fn select_files(_token: APIToken, payload: Json<SelectFileOptions>) -> Json<FilesSelectionResponse> { pub fn select_files(
_token: APIToken,
payload: Json<SelectFileOptions>,
) -> Json<FilesSelectionResponse> {
// Create a new file dialog builder: // Create a new file dialog builder:
let file_dialog = FileDialogBuilder::new(); let file_dialog = create_file_dialog();
// Set the title of the file dialog: // Set the title of the file dialog:
let file_dialog = file_dialog.set_title(&payload.title); let file_dialog = file_dialog.set_title(&payload.title);
@ -617,7 +621,10 @@ pub fn select_files(_token: APIToken, payload: Json<SelectFileOptions>) -> Json<
info!("User selected {} files.", paths.len()); info!("User selected {} files.", paths.len());
Json(FilesSelectionResponse { Json(FilesSelectionResponse {
user_cancelled: false, user_cancelled: false,
selected_file_paths: paths.iter().map(|p| p.to_str().unwrap().to_string()).collect(), selected_file_paths: paths
.iter()
.map(|p| p.to_str().unwrap().to_string())
.collect(),
}) })
} }
@ -633,9 +640,8 @@ pub fn select_files(_token: APIToken, payload: Json<SelectFileOptions>) -> Json<
#[post("/save/file", data = "<payload>")] #[post("/save/file", data = "<payload>")]
pub fn save_file(_token: APIToken, payload: Json<SaveFileOptions>) -> Json<FileSaveResponse> { pub fn save_file(_token: APIToken, payload: Json<SaveFileOptions>) -> Json<FileSaveResponse> {
// Create a new file dialog builder: // Create a new file dialog builder:
let file_dialog = FileDialogBuilder::new(); let file_dialog = create_file_dialog();
// Set the title of the file dialog: // Set the title of the file dialog:
let file_dialog = file_dialog.set_title(&payload.title); let file_dialog = file_dialog.set_title(&payload.title);
@ -679,6 +685,28 @@ pub struct PreviousFile {
file_path: String, file_path: String,
} }
/// Creates a file dialog builder and assigns the main window as parent where supported.
fn create_file_dialog() -> FileDialogBuilder {
let file_dialog = FileDialogBuilder::new();
#[cfg(any(windows, target_os = "macos"))]
{
let main_window_lock = MAIN_WINDOW.lock().unwrap();
match main_window_lock.as_ref() {
Some(window) => file_dialog.set_parent(window),
None => {
warn!(Source = "Tauri"; "Cannot assign parent window to file dialog: main window not available.");
file_dialog
}
}
}
#[cfg(not(any(windows, target_os = "macos")))]
{
file_dialog
}
}
/// Applies an optional file type filter to a FileDialogBuilder. /// Applies an optional file type filter to a FileDialogBuilder.
fn apply_filter(file_dialog: FileDialogBuilder, filter: &Option<FileTypeFilter>) -> FileDialogBuilder { fn apply_filter(file_dialog: FileDialogBuilder, filter: &Option<FileTypeFilter>) -> FileDialogBuilder {
match filter { match filter {
@ -804,7 +832,7 @@ pub fn register_shortcut(_token: APIToken, payload: Json<RegisterShortcutRequest
error_message: "Cannot register NONE shortcut".to_string(), error_message: "Cannot register NONE shortcut".to_string(),
}); });
} }
info!(Source = "Tauri"; "Registering global shortcut '{}' with key '{new_shortcut}'.", id); info!(Source = "Tauri"; "Registering global shortcut '{}' with key '{new_shortcut}'.", id);
// Get the main window to access the global shortcut manager: // Get the main window to access the global shortcut manager: