mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-28 03:57:57 -06:00
#1508: a refused backup from the menu says why
The menu bar turned a command's error into a toast only for exports, so File ▸ Back Up Library… did nothing visible when the host refused (changes still unsaved, or nothing stored in this browser); the refusal reached only the control channel (found in a real-browser check of PR #1987). Backup and restore refusals are toasted too. Menu items are registered for automation as `menuitem:<command id>`, and a headless test clicks File ▸ Back Up Library… against a refusing host and reads the toast. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AbegtYaPuwqZ81pGfELsFK
This commit is contained in:
@@ -962,9 +962,10 @@ pub fn show_in_window(app: &mut LightcraftApp, ui: &mut egui::Ui, max_width: f32
|
||||
}
|
||||
if let Some((id, params)) = clicked {
|
||||
let r = run_item(app, &id, params);
|
||||
// an export that can't start (e.g. no folder) says why instead of doing nothing
|
||||
// an export that can't start (e.g. no folder), or a backup / restore the host refuses
|
||||
// (changes still unsaved, nothing stored in this browser), says why instead of doing nothing
|
||||
if let Err(e) = r
|
||||
&& matches!(id.as_str(), "app.export" | "app.exportPrevious")
|
||||
&& matches!(id.as_str(), "app.export" | "app.exportPrevious" | "file.backupLibrary" | "file.restoreLibrary")
|
||||
{
|
||||
app.toast(ui.ctx(), e);
|
||||
}
|
||||
@@ -1044,6 +1045,7 @@ fn nodes_ui(ui: &mut egui::Ui, nodes: &[MenuNode], mac: bool, clicked: &mut Opti
|
||||
b = b.shortcut_text(shortcut_text(sc, mac));
|
||||
}
|
||||
let r = ui.add_enabled(*enabled, b);
|
||||
crate::widgets::register(ui.ctx(), format!("menuitem:{id}"), r.rect);
|
||||
if *checked == Some(true) {
|
||||
let t = crate::theme::Tokens::get(ui.ctx());
|
||||
let c = egui::Rect::from_center_size(egui::pos2(r.rect.left() + 11.0, r.rect.center().y), egui::vec2(13.0, 13.0));
|
||||
@@ -1390,6 +1392,30 @@ mod tests {
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// A backup the host refuses (changes still unsaved, issue #1508) says why when started from
|
||||
/// the menu, as a refused export does; the refusal used to reach only the control channel.
|
||||
#[test]
|
||||
fn a_refused_backup_from_the_menu_shows_why() {
|
||||
// the host refuses, as the web one does while changes are still unsaved (issue #1508)
|
||||
let refusal = "Backup not started: 1 change could not be saved to browser storage yet";
|
||||
let services = crate::Services {
|
||||
backup_library: Some(Box::new(move |_: &mut lightcraft_engine::Session| Err(refusal.to_string()))),
|
||||
..Default::default()
|
||||
};
|
||||
let app = LightcraftApp::new(lightcraft_engine::Session::with_demo(), services);
|
||||
let mut h = crate::headless::Headless::new(app, [1400.0, 900.0], 1.0);
|
||||
let t = std::time::Duration::from_secs(30);
|
||||
h.settle(t);
|
||||
for id in ["menu:File", "menuitem:file.backupLibrary"] {
|
||||
let r = h.request("ui.clickWidget", json!({"id": id}), t);
|
||||
assert_eq!(r["ok"], true, "{id}: {r}");
|
||||
h.step();
|
||||
}
|
||||
// (read at once: a toast keeps the UI repainting until it expires, so settling would outlive it)
|
||||
let toast = h.app.ui.toast.as_ref().map(|t| t.0.clone()).unwrap_or_default();
|
||||
assert!(toast.contains(refusal), "the refusal is shown: {toast:?}");
|
||||
}
|
||||
|
||||
/// #1528: `file.findMissing` with `wait: true` must propagate folder validation and search
|
||||
/// failures as errors instead of returning `Ok(null)`.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user