Merge PR #2142: PivotTable Fields pane: scan the source once per change, not every frame

This commit is contained in:
aiongg
2026-10-22 02:36:33 +00:00
3 changed files with 34 additions and 4 deletions
+3
View File
@@ -134,6 +134,9 @@ pub struct GridState {
pub ink: Vec<[f32; 2]>,
/// Page ranges for Page Break Preview, cached per (doc uid, revision, sheet).
pub pages: Option<((u64, u64, usize), Vec<(RangeRef, u32)>)>,
/// The PivotTable Fields pane's `pivot.fields` answer, cached per (doc uid, revision, pivot):
/// it scans the whole source list, far too slow to repeat every frame (#2113).
pub pivot_fields: Option<((u64, u64, String), serde_json::Value)>,
pub header_menu: Option<(Pos2, bool)>,
/// Page Layout view pagination, cached per (doc uid, revision, sheet, rows, columns).
pub paper: Option<crate::paper_view::PaperCache>,
+9 -4
View File
@@ -21,10 +21,15 @@ pub fn show(app: &mut SheetApp, ui: &mut Ui) {
let Some(name) = active_pivot(app) else { return };
let t = Tokens::get(ui.ctx());
let lang = i18n::current(ui.ctx());
let info = match app.session.run("pivot.fields", json!({"pivot": name})) {
Ok(v) => v,
Err(_) => return,
};
let Some(key) = app.session.active().map(|d| (d.uid, d.revision, name.clone())) else { return };
if app.grid.pivot_fields.as_ref().is_none_or(|(k, _)| *k != key) {
let info = match app.session.run("pivot.fields", json!({"pivot": name})) {
Ok(v) => v,
Err(_) => return,
};
app.grid.pivot_fields = Some((key, info));
}
let Some((_, info)) = app.grid.pivot_fields.clone() else { return };
egui::Panel::right("pivot_pane").default_size(280.0).resizable(true).frame(egui::Frame::NONE.fill(t.ribbon).inner_margin(10)).show(ui, |ui| {
ui.label(egui::RichText::new(lang.tr("PivotTable Fields")).font(theme::ui_bold(15.0)));
ui.label(egui::RichText::new(lang.tr("Choose fields to add to report:")).small().color(t.text_dim));
+22
View File
@@ -403,6 +403,28 @@ fn pivot_fields_pane_follows_the_interface_language() {
assert!(h.query_by_label("Remove Field").is_none());
}
#[test]
fn pivot_fields_pane_reuses_its_field_list_until_the_workbook_changes() {
// #2113: the pane ran `pivot.fields`, a scan of the whole source list, on every frame.
let mut h = harness(blank());
h.state_mut().run("range.setValues", json!({"range": "A1:B3", "values": [["Region", "Sales"], ["North", 10], ["South", 20]]})).unwrap();
h.state_mut().run("insert.pivotTable", json!({"source": "Sheet1!$A$1:$B$3", "rows": ["Region"], "destination": "Sheet1!D1"})).unwrap();
h.run_steps(2);
assert!(h.query_by_label("Sales").is_some(), "the pane lists the source fields");
let (key, mut info) = h.state().grid.pivot_fields.clone().expect("the pane keeps its field list");
info["fields"][1]["name"] = json!("Cached");
h.state_mut().grid.pivot_fields = Some((key, info));
h.run_steps(2);
assert!(h.query_by_label("Cached").is_some(), "repaints reuse the kept list instead of scanning the source again");
h.state_mut().run("cell.set", json!({"cell": "B1", "input": "Revenue"})).unwrap();
h.run_steps(2);
assert!(h.query_by_label("Cached").is_none(), "an edit drops the kept list");
assert!(h.query_by_label("Revenue").is_some(), "the pane shows the edited source");
h.state_mut().run("edit.undo", json!({})).unwrap();
h.run_steps(2);
assert!(h.query_by_label("Sales").is_some(), "undo brings the previous field list back");
}
#[test]
fn format_cells_draws_its_labels_in_the_interface_language() {
let mut h = harness(blank());