diff --git a/crates/ui-egui/src/menus/invoke.rs b/crates/ui-egui/src/menus/invoke.rs index 75f7462c7..382c730aa 100644 --- a/crates/ui-egui/src/menus/invoke.rs +++ b/crates/ui-egui/src/menus/invoke.rs @@ -256,8 +256,8 @@ fn open_view_dialog(app: &mut VectorcraftApp, id: &str, p: &Value) -> bool { false } -/// The dialogs the selection, raster, wrap, blend and Expand commands open when called without params; whether `id` -/// was one of them. +/// The dialogs the selection, raster, wrap, blend and Expand commands open, and the panel the Asset Export commands +/// open, when called without params; whether `id` was one of them. fn open_object_dialog(app: &mut VectorcraftApp, id: &str, p: &Value) -> bool { // Save Selection…: a name dialog, starting from the first free "Selection N". if id == "select.save" && p.as_object().is_none_or(|o| o.is_empty()) { @@ -315,5 +315,14 @@ fn open_object_dialog(app: &mut VectorcraftApp, id: &str, p: &Value) -> bool { } return true; } + // Export Assets, Remove, Rename and Asset Export Settings with no params, as the command + // palette runs them (#4864): the Asset Export panel, where each one is done. A panel that already + // shows stays open. + if matches!(id, "assets.export" | "assets.remove" | "assets.rename" | "assets.settings.set") && p.as_object().is_none_or(|o| o.is_empty()) { + if let Err(e) = crate::panel_docking::reveal_panel(app, crate::panels::asset_export::ID) { + app.status(e); + } + return true; + } false } diff --git a/crates/ui-egui/src/palette.rs b/crates/ui-egui/src/palette.rs index a6cc61e23..f7728f4c3 100644 --- a/crates/ui-egui/src/palette.rs +++ b/crates/ui-egui/src/palette.rs @@ -199,6 +199,31 @@ mod tests { assert_eq!((st.selection.len(), st.selection.key), (2, None), "both objects stay selected, without a key"); } + /// #4864: a pick of an Asset Export command, which the palette runs with no params, opens the + /// Asset Export panel instead of failing on the missing params or exporting nowhere. + #[test] + fn a_pick_of_an_asset_export_command_opens_its_panel() { + let ids = ["assets.export", "assets.remove", "assets.rename", "assets.settings.set"]; + for id in ids { + assert!(items().iter().any(|(_, item, _)| item == id), "{id} is in the palette"); + let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), crate::Services::default()); + app.run("file.new", json!({"width": 200, "height": 200})).unwrap(); + app.ui.status.clear(); + assert!(!crate::panel_docking::showing(&app.ui, crate::panels::asset_export::ID), "{id}"); + // Run a pick the way `show` runs it. + menus::invoke(&mut app, id, json!({})); + assert!(crate::panel_docking::showing(&app.ui, crate::panels::asset_export::ID), "{id}: {}", app.ui.status); + assert!(!app.ui.status.contains("invalid parameters"), "{id}: {}", app.ui.status); + // A second pick leaves the open panel open, docked or floating. + menus::invoke(&mut app, id, json!({})); + assert!(crate::panel_docking::showing(&app.ui, crate::panels::asset_export::ID), "{id}: picked twice"); + app.run("window.panel.float", json!({"panel": crate::panels::asset_export::ID})).unwrap(); + assert!(crate::panel_docking::showing(&app.ui, crate::panels::asset_export::ID), "{id}: floating"); + menus::invoke(&mut app, id, json!({})); + assert!(crate::panel_docking::showing(&app.ui, crate::panels::asset_export::ID), "{id}: floating, picked again"); + } + } + /// #1757: Up and Down move the highlighted result, wrapping at the ends; a new query starts /// from the first again. #[test]