mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-24 10:46:50 -06:00
Write comment and hyperlink maps with A1 keys so JSON save works (#126)
This commit is contained in:
@@ -1018,3 +1018,20 @@ fn malformed_xlsb_keeps_the_current_workbook() {
|
||||
assert_eq!(v(&s, "A1"), Value::from("Keep me"));
|
||||
assert!(s.doc().unwrap().is_dirty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn notes_comments_and_links_survive_a_json_save() {
|
||||
let mut s = s();
|
||||
s.execute("cell.set", json!({"cell": "A1", "input": "x"})).unwrap();
|
||||
s.execute("review.newNote", json!({"cell": "A1", "text": "note", "author": "Example"})).unwrap();
|
||||
s.execute("review.newComment", json!({"cell": "B2", "text": "comment", "author": "Example"})).unwrap();
|
||||
s.execute("insert.link", json!({"cell": "C3", "target": "Sheet1!A1", "tooltip": "jump"})).unwrap();
|
||||
let wb = &s.doc().unwrap().wb;
|
||||
let bytes = crate::io::save_bytes(wb, "book.json").unwrap();
|
||||
let (back, _) = crate::io::open_bytes("book.json", &bytes).unwrap();
|
||||
let (before, after) = (wb.active().unwrap(), back.active().unwrap());
|
||||
assert_eq!((before.comments.len(), before.hyperlinks.len()), (2, 1));
|
||||
assert_eq!(after.comments, before.comments);
|
||||
assert_eq!(after.hyperlinks, before.hyperlinks);
|
||||
assert_eq!(after.cells, before.cells);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
//! Serde helpers for maps keyed by `CellRef`. JSON object keys must be strings, so the keys are
|
||||
//! written as `A1`-style text.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use gridcraft_core::CellRef;
|
||||
use serde::de::Error;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
pub fn serialize<S: Serializer, V: Serialize>(map: &BTreeMap<CellRef, V>, s: S) -> Result<S::Ok, S::Error> {
|
||||
s.collect_map(map.iter().map(|(k, v)| (k.a1(), v)))
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D: Deserializer<'de>, V: Deserialize<'de>>(d: D) -> Result<BTreeMap<CellRef, V>, D::Error> {
|
||||
let raw = BTreeMap::<String, V>::deserialize(d)?;
|
||||
let mut out = BTreeMap::new();
|
||||
for (k, v) in raw {
|
||||
let cell = CellRef::parse(&k).ok_or_else(|| D::Error::custom(format!("invalid cell reference `{k}`")))?;
|
||||
out.insert(cell, v);
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{Comment, Hyperlink, Sheet};
|
||||
use gridcraft_core::CellRef;
|
||||
|
||||
#[test]
|
||||
fn comments_and_hyperlinks_survive_json() {
|
||||
let mut s = Sheet::new("S");
|
||||
let a1 = CellRef::new(0, 0);
|
||||
let c3 = CellRef::new(2, 2);
|
||||
s.comments.insert(
|
||||
a1,
|
||||
Comment {
|
||||
author: "Example".into(),
|
||||
text: "note".into(),
|
||||
replies: vec![("B".into(), "r".into())],
|
||||
threaded: true,
|
||||
resolved: false,
|
||||
visible: false,
|
||||
},
|
||||
);
|
||||
s.hyperlinks.insert(c3, Hyperlink { target: "Sheet1!A1".into(), tooltip: Some("jump".into()) });
|
||||
let json = serde_json::to_string(&s).expect("serialize");
|
||||
let back: Sheet = serde_json::from_str(&json).expect("deserialize");
|
||||
assert_eq!(back.comments, s.comments);
|
||||
assert_eq!(back.hyperlinks, s.hyperlinks);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
mod b64;
|
||||
pub mod cell;
|
||||
mod cellmap;
|
||||
pub mod features;
|
||||
pub mod sheet;
|
||||
pub mod store;
|
||||
|
||||
@@ -48,7 +48,9 @@ pub struct Sheet {
|
||||
pub validations: Vec<Validation>,
|
||||
pub tables: Vec<Table>,
|
||||
pub autofilter: Option<AutoFilter>,
|
||||
#[serde(with = "crate::cellmap")]
|
||||
pub comments: BTreeMap<CellRef, Comment>,
|
||||
#[serde(with = "crate::cellmap")]
|
||||
pub hyperlinks: BTreeMap<CellRef, Hyperlink>,
|
||||
pub charts: Vec<Chart>,
|
||||
pub images: Vec<Image>,
|
||||
|
||||
Reference in New Issue
Block a user