From 2ecc4881119e9e108ac4c2ff6b8a15940739c0d8 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sun, 18 Oct 2026 10:22:04 -0700 Subject: [PATCH] =?UTF-8?q?Variables:=20Import=20and=20Export=20Data=20Set?= =?UTF-8?q?s=E2=80=A6=20show=20file=20dialogs=20on=20macOS=20and=20keep=20?= =?UTF-8?q?the=20window=20running?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Variables panel menu called import_datasets and export_datasets directly, so their file dialogs were asked for outside an entry and shown in line. macOS shows no dialog in line, so the two items did nothing there. On Linux the dialog held the window until it closed. Both items now go through picks::button, as the Libraries panel menu's Import Library… and Export Library… do. When the dialog answers, the item runs again with the picked path. Errors still go to the status bar. variables_panel_data_sets_ask_off_the_ui_thread clicks both items with dialogs shown as sheets, as on macOS, imports a CSV and exports the data sets to the path the dialog answers. --- crates/ui-egui/src/panels/variables.rs | 4 ++-- crates/ui-egui/src/tests_picks.rs | 27 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/panels/variables.rs b/crates/ui-egui/src/panels/variables.rs index 160d0fe0a..ca1fc29f6 100644 --- a/crates/ui-egui/src/panels/variables.rs +++ b/crates/ui-egui/src/panels/variables.rs @@ -317,10 +317,10 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut Ui) { } ui.separator(); if widgets::menu_item(ui, tl!("Import Data Sets…"), true, false) { - import_datasets(app); + crate::picks::button(app, import_datasets); } if widgets::menu_item(ui, tl!("Export Data Sets…"), !vars.is_empty(), false) { - export_datasets(app); + crate::picks::button(app, export_datasets); } ui.separator(); // What the highlighted variable drives, selected — its bindings are left alone. diff --git a/crates/ui-egui/src/tests_picks.rs b/crates/ui-egui/src/tests_picks.rs index 2c071fa2f..e2198699a 100644 --- a/crates/ui-egui/src/tests_picks.rs +++ b/crates/ui-egui/src/tests_picks.rs @@ -221,6 +221,33 @@ fn load_profile_asks_off_the_ui_thread() { assert!(app.ui.status.contains("/no/such/profile.icc"), "color.loadProfile ran on the path: {}", app.ui.status); } +/// The Variables panel menu's Import Data Sets… and Export Data Sets… ask off the UI thread: the +/// data sets in the file picked are loaded, and the data sets are written to the path the dialog +/// answers. +#[test] +fn variables_panel_data_sets_ask_off_the_ui_thread() { + let (mut app, shown, _) = app(); + app.run("file.new", json!({"width": 100, "height": 80})).unwrap(); + let dir = std::env::temp_dir().join(format!("vc-picks-data-sets-{}", std::process::id())); + std::fs::create_dir_all(&dir).unwrap(); + let (csv, out) = (dir.join("sets.csv"), dir.join("out.csv")); + std::fs::write(&csv, "name,Name\nB,y\n").unwrap(); + let sets = |app: &VectorcraftApp| app.session.doc().unwrap().doc.variables.datasets.iter().map(|d| d.name.clone()).collect::>(); + + click(&mut app, "Import Data Sets…", crate::panels::variables::menu); + assert!(matches!(shown.requests().as_slice(), [PickRequest::Open(_)])); + shown.answer(&[&csv.to_string_lossy()]); + poll(&mut app); + assert_eq!(sets(&app), ["B"], "{}", app.ui.status); + + click(&mut app, "Export Data Sets…", crate::panels::variables::menu); + assert!(matches!(shown.requests().as_slice(), [PickRequest::Save(_)])); + shown.answer(&[&out.to_string_lossy()]); + poll(&mut app); + assert!(std::fs::read_to_string(&out).is_ok_and(|text| text.starts_with("name,Name\n")), "{}", app.ui.status); + let _ = std::fs::remove_dir_all(dir); +} + /// The Swatches libraries menu's Other Library… asks off the UI thread; the file picked (another /// document) loads as a library and opens in the library panel. #[test]