feat: add records mode (long-format view) for drill-down

Implement records mode (long-format view) when drilling into aggregated cells.

Key changes:
- DrillIntoCell now creates views with _Index on Row and _Dim on Column
- GridLayout detects records mode and builds a records list instead of
  cross-product row/col items
- Added records_display() to render individual cell values in records mode
- GridWidget and CSV export updated to handle records mode rendering
- category_names() now includes virtual categories (_Index, _Dim)
- Tests updated to reflect virtual categories counting toward limits

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
This commit is contained in:
Edward Langley
2026-04-05 11:10:41 -07:00
parent 67041dd4a5
commit 19645a34cf
5 changed files with 166 additions and 71 deletions

View File

@ -291,16 +291,27 @@ impl<'a> GridWidget<'a> {
break;
}
let key = match layout.cell_key(ri, ci) {
Some(k) => k,
None => {
x += COL_WIDTH;
continue;
}
let (cell_str, value) = if layout.is_records_mode() {
let s = layout.records_display(ri, ci).unwrap_or_default();
// In records mode the value is a string, not aggregated
let v = if !s.is_empty() {
Some(crate::model::cell::CellValue::Text(s.clone()))
} else {
None
};
(s, v)
} else {
let key = match layout.cell_key(ri, ci) {
Some(k) => k,
None => {
x += COL_WIDTH;
continue;
}
};
let value = self.model.evaluate_aggregated(&key, &layout.none_cats);
let s = format_value(value.as_ref(), fmt_comma, fmt_decimals);
(s, value)
};
let value = self.model.evaluate_aggregated(&key, &layout.none_cats);
let cell_str = format_value(value.as_ref(), fmt_comma, fmt_decimals);
let is_selected = ri == sel_row && ci == sel_col;
let is_search_match = !self.search_query.is_empty()
&& cell_str