diff --git a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingAssistant.razor.Versions.cs b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingAssistant.razor.Versions.cs index 2add24cc..fc7ce120 100644 --- a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingAssistant.razor.Versions.cs +++ b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingAssistant.razor.Versions.cs @@ -111,7 +111,7 @@ public partial class VisualBriefingAssistant var response = await this.RustService.SaveFile( T("Export visual briefing"), [FileTypes.VISUAL_BRIEFING_HTML], - $"{SafeFileName(this.selectedBriefing.Name)}.html"); + $"{SafeFileName(this.projectName)}.html"); if (response.UserCancelled) return; diff --git a/runtime/src/file_actions.rs b/runtime/src/file_actions.rs index b917158f..4cc77563 100644 --- a/runtime/src/file_actions.rs +++ b/runtime/src/file_actions.rs @@ -46,7 +46,7 @@ pub struct SelectFileOptions { #[derive(Clone, Deserialize)] pub struct SaveFileOptions { title: String, - name_file: Option, + previous_file: Option, filter: Option, } @@ -275,10 +275,15 @@ pub async fn save_file(_token: APIToken, payload: Json) -> Json // Set the file type filter if provided: file_dialog = apply_filter(file_dialog, &payload.filter); - // Set the previous file path if provided: - if let Some(previous) = &payload.name_file { - let previous_path = previous.file_path.as_str(); - file_dialog = file_dialog.set_directory(previous_path); + // Set the initial directory and file name if provided: + if let Some(previous) = &payload.previous_file { + let (directory, file_name) = split_save_file_path(&previous.file_path); + if let Some(directory) = directory { + file_dialog = file_dialog.set_directory(directory); + } + if let Some(file_name) = file_name { + file_dialog = file_dialog.set_file_name(file_name); + } } // Displays the file dialogue box and select the file: @@ -396,6 +401,21 @@ fn apply_filter(file_dialog: FileDialogBuilder, filter: &O } } +fn split_save_file_path(file_path: &str) -> (Option, Option) { + let path = Path::new(file_path); + let directory = path + .parent() + .filter(|parent| !parent.as_os_str().is_empty()) + .map(Path::to_path_buf); + + let file_name = path + .file_name() + .map(|name| name.to_string_lossy().into_owned()) + .filter(|name| !name.is_empty()); + + (directory, file_name) +} + #[derive(Debug, PartialEq, Eq)] struct FileManagerTarget { path: PathBuf, @@ -529,6 +549,39 @@ mod tests { use super::*; use std::fs; + #[test] + fn save_file_options_accept_the_previous_file_contract() { + let options: SaveFileOptions = serde_json::from_str( + r#"{"title":"Export visual briefing","previous_file":{"file_path":"Quarterly briefing.html"}}"#, + ) + .unwrap(); + + assert_eq!(options.title, "Export visual briefing"); + assert_eq!( + options.previous_file.unwrap().file_path, + "Quarterly briefing.html", + ); + } + + #[test] + fn save_file_name_without_directory_is_preserved() { + let (directory, file_name) = split_save_file_path("Quarterly briefing.html"); + + assert_eq!(directory, None); + assert_eq!(file_name.as_deref(), Some("Quarterly briefing.html")); + } + + #[test] + fn save_file_path_is_split_into_directory_and_name() { + let temp_dir = tempfile::tempdir().unwrap(); + let initial_path = temp_dir.path().join("Quarterly briefing.html"); + + let (directory, file_name) = split_save_file_path(initial_path.to_str().unwrap()); + + assert_eq!(directory.as_deref(), Some(temp_dir.path())); + assert_eq!(file_name.as_deref(), Some("Quarterly briefing.html")); + } + #[test] fn existing_file_is_revealed_and_falls_back_to_its_parent() { let temp_dir = tempfile::tempdir().unwrap(); @@ -575,4 +628,4 @@ mod tests { assert!(resolve_file_manager_target(&invalid_path).is_none()); } -} +} \ No newline at end of file