mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-10 20:40:05 -06:00
#2120: clearing links and notes respects sheet protection
Addresses review comment 4455670315: - Clear Hyperlinks and Clear Comments removed links and notes on locked cells of a protected sheet: protection compares stored cells only, so their removal went unseen (for stored cells too, and now for unstored ones since the whole range is cleared). `clear` now refuses a locked cell's note or link with locked_cell_error, which keeps Allow Edit Ranges and session-unlocked ranges. - A removed note or link on a cell with nothing stored wasn't added to the changed cells, so a recorded macro's footprint missed it. Tests: engine tests::clearing_links_and_notes_respects_sheet_protection, tests::clearing_links_and_notes_records_their_cells. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
58e876a4d8
commit
dfb3b1224b
@@ -244,6 +244,25 @@ fn clear(s: &mut Session, p: &Json, what: &str) -> Result<Json> {
|
||||
})
|
||||
})
|
||||
};
|
||||
// Notes and links aren't cell contents, so the cell comparison that guards a protected sheet
|
||||
// doesn't see them go: a locked cell's are refused here, stored cell or not.
|
||||
if matches!(what, "all" | "comments" | "hyperlinks") {
|
||||
let d = s.doc()?;
|
||||
if let Some(sh) = d.wb.sheet(sheet).filter(|sh| sh.is_protected()) {
|
||||
for &whole in &ranges {
|
||||
let skip = filtered_rows(sh, whole);
|
||||
let notes = matches!(what, "all" | "comments").then(|| sh.comments.keys()).into_iter().flatten();
|
||||
let links = matches!(what, "all" | "hyperlinks").then(|| sh.hyperlinks.keys()).into_iter().flatten();
|
||||
for &c in notes.chain(links).filter(|c| whole.contains(**c) && !skip.contains(&c.row)) {
|
||||
if d.wb.styles.get(sh.style_id(c)).protection.locked
|
||||
&& let Some(m) = locked_cell_error(sh, c, &d.unlocked_ranges)
|
||||
{
|
||||
return Err(EngineError::Other(m));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
edit(s, |cx| {
|
||||
for &whole in &ranges {
|
||||
// Cells are only stored inside the used range. Notes and links are kept apart from
|
||||
@@ -274,6 +293,18 @@ fn clear(s: &mut Session, p: &Json, what: &str) -> Result<Json> {
|
||||
}
|
||||
}
|
||||
}
|
||||
let cleared = |c: CellRef| whole.contains(c) && !skip.contains(&c.row);
|
||||
// A removed note or link changes its cell even with nothing stored there.
|
||||
let metadata: Vec<CellRef> = cx
|
||||
.wb
|
||||
.sheet(sheet)
|
||||
.map(|sh| {
|
||||
let notes = matches!(what, "all" | "comments").then(|| sh.comments.keys()).into_iter().flatten();
|
||||
let links = matches!(what, "all" | "hyperlinks").then(|| sh.hyperlinks.keys()).into_iter().flatten();
|
||||
notes.chain(links).copied().filter(|c| cleared(*c)).collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
cx.changed.extend(metadata.into_iter().map(|c| (sheet, c)));
|
||||
let sh = cx.sheet_mut(sheet)?;
|
||||
for (c, mut cell) in cells {
|
||||
match what {
|
||||
@@ -290,7 +321,6 @@ fn clear(s: &mut Session, p: &Json, what: &str) -> Result<Json> {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let cleared = |c: CellRef| whole.contains(c) && !skip.contains(&c.row);
|
||||
if matches!(what, "all" | "comments") {
|
||||
sh.comments.retain(|c, _| !cleared(*c));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user