Fix saving a custom view or script when the stored list is not a JSON object (#517)

This commit is contained in:
MarekSpodBiedry
2026-10-12 08:37:04 +02:00
parent 3926d21aa9
commit 2d0fb534a2
2 changed files with 61 additions and 3 deletions
+13 -3
View File
@@ -701,6 +701,16 @@ fn stash_get(wb: &Workbook, key: &str) -> Json {
.unwrap_or(json!({}))
}
/// Like `stash_get`, for the name-keyed lists (views, scripts): a stored value that is not a JSON object is treated as empty.
fn stash_map(wb: &Workbook, key: &str) -> Json {
let v = stash_get(wb, key);
if v.is_object() {
v
} else {
json!({})
}
}
fn stash_set(wb: &mut Workbook, key: &str, v: &Json) {
let text = v.to_string();
let formula = format!("\"{}\"", text.replace('"', "\"\""));
@@ -723,7 +733,7 @@ pub(crate) fn keep_watch_list(from: &Workbook, to: &mut std::sync::Arc<Workbook>
fn custom_views(s: &mut Session, p: &Json) -> Result<Json> {
let d = s.doc()?;
let mut views = stash_get(&d.wb, VIEWS_NAME);
let mut views = stash_map(&d.wb, VIEWS_NAME);
if let Some(name) = str_param(p, "save") {
let sh = d.wb.active().ok_or(EngineError::NoDocument)?;
views[name] = json!({"sheet": d.wb.active_sheet, "selection": d.selection.a1(), "zoom": sh.zoom, "freeze": sh.freeze});
@@ -938,7 +948,7 @@ fn new_script(s: &mut Session, p: &Json) -> Result<Json> {
return Err(bad("automate.newScript", "`commands` must be an array"));
}
edit(s, |cx| {
let mut all = stash_get(&cx.wb, SCRIPTS_NAME);
let mut all = stash_map(&cx.wb, SCRIPTS_NAME);
all[name.as_str()] = cmds.clone();
stash_set(&mut cx.wb, SCRIPTS_NAME, &all);
Ok(json!({"name": name}))
@@ -977,7 +987,7 @@ fn run_script(s: &mut Session, p: &Json) -> Result<Json> {
fn delete_script(s: &mut Session, p: &Json) -> Result<Json> {
let name = str_param(p, "name").ok_or_else(|| bad("automate.deleteScript", "missing `name`"))?.to_string();
edit(s, |cx| {
let mut all = stash_get(&cx.wb, SCRIPTS_NAME);
let mut all = stash_map(&cx.wb, SCRIPTS_NAME);
if let Some(o) = all.as_object_mut() {
o.remove(&name);
}
+48
View File
@@ -0,0 +1,48 @@
use gridcraft_engine::Session;
use serde_json::json;
const NOT_OBJECTS: [&str; 4] = ["\"[1,2]\"", "\"7\"", "\"true\"", "\"\"\"hi\"\"\""];
fn with_name(name: &str, refers_to: &str) -> Session {
let mut s = Session::new();
s.new_workbook();
s.execute("formulas.defineName", json!({"name": name, "refersTo": refers_to})).unwrap();
s
}
#[test]
fn saving_a_view_works_when_stored_list_is_not_an_object() {
for text in NOT_OBJECTS {
let mut s = with_name("_sc_custom_views", text);
let out = s.execute("view.customViews", json!({"save": "v"})).unwrap();
assert!(out.get("v").is_some(), "{text}: {out}");
}
}
#[test]
fn saving_a_view_keeps_the_keys_of_a_stored_object() {
let mut s = with_name("_sc_custom_views", "\"{\"\"a\"\":1}\"");
let out = s.execute("view.customViews", json!({"save": "v"})).unwrap();
assert!(out.get("a").is_some() && out.get("v").is_some(), "{out}");
}
#[test]
fn creating_a_script_works_when_stored_list_is_not_an_object() {
for text in NOT_OBJECTS {
let mut s = with_name("_sc_scripts", text);
s.execute("automate.newScript", json!({"name": "s1", "commands": []})).unwrap();
let list = s.execute("automate.allScripts", json!({})).unwrap();
assert!(list.to_string().contains("s1"), "{text}: {list}");
}
}
#[test]
fn stopping_a_recording_works_when_stored_list_is_not_an_object() {
for text in NOT_OBJECTS {
let mut s = with_name("_sc_scripts", text);
s.execute("automate.recordActions", json!({})).unwrap();
s.execute("automate.recordActions", json!({"stop": true, "name": "s1"})).unwrap();
let list = s.execute("automate.allScripts", json!({})).unwrap();
assert!(list.to_string().contains("s1"), "{text}: {list}");
}
}