UI: recover persisted docking without resetting workspace preferences

This commit is contained in:
skylar taylor-barrick committed 2026-10-10 18:49:16 -06:00
1 parent 58a8494f98
commit a3f43a700f
1 file changed
+36 -1
+36 -1
View File
@@ -78,7 +78,17 @@ fn read(path: &Path) -> Result<Option<UiState>, String> {
}
let workspace =
value.get("workspace").filter(|value| value.is_object()).ok_or_else(|| format!("{}: missing workspace object", path.display()))?;
let mut ui: UiState = serde_json::from_value(workspace.clone()).map_err(|error| format!("{}: invalid workspace: {error}", path.display()))?;
// Dock schemas can evolve independently of the other saved workspace preferences.
// Recover only this optional field; runtime UiState deserialization remains strict.
let mut fields = workspace.clone();
let docking = fields.as_object_mut().and_then(|fields| fields.remove("docking"));
let mut ui: UiState = serde_json::from_value(fields).map_err(|error| format!("{}: invalid workspace: {error}", path.display()))?;
if let Some(docking) = docking
&& let Ok(docking) = serde_json::from_value::<cadcraft_ui_egui::docking::Workspace>(docking)
&& docking.validate().is_ok()
{
ui.docking = docking;
}
// Old or hand-edited files cannot reopen a dialog or replace the active drawing view.
ui.dialog = None;
ui.start_tab = false;
@@ -268,6 +278,31 @@ mod tests {
fs::remove_dir_all(directory).unwrap();
}
#[test]
fn unsupported_docking_preserves_other_workspace_preferences() {
let directory = temp_dir();
let path = directory.join("workspace.json");
for docking in [
json!({"layout":{"root":{"FuturePanelGroup":{}}},"hidden":[]}),
json!({"layout":false,"hidden":[]}),
json!({"layout":{"root":null,"floating":[]},"hidden":[["futurePanel",{}]]}),
] {
let workspace = json!({"showToolbar":false,"showPalettes":false,"toolsetTab":"Modeling", "collapsedGroups":["Draw"], "historyLines":7,"docking":docking});
assert!(serde_json::from_value::<UiState>(workspace.clone()).is_err(), "runtime state must stay strict");
fs::write(&path, serde_json::to_vec(&json!({"version":1,"workspace":workspace})).unwrap()).unwrap();
let (_, restored, error) = Workspace::at(Some(path.clone()));
assert!(error.is_none());
let restored = restored.unwrap();
assert!(!restored.show_toolbar);
assert!(!restored.show_palettes);
assert_eq!(restored.toolset_tab, "Modeling");
assert_eq!(restored.collapsed_groups, ["Draw"]);
assert_eq!(restored.history_lines, 7);
assert_eq!(serde_json::to_value(restored.docking).unwrap(), serde_json::to_value(UiState::default().docking).unwrap());
}
fs::remove_dir_all(directory).unwrap();
}
#[test]
fn invalid_update_cannot_replace_last_good_workspace() {
let directory = temp_dir();