mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-24 10:46:50 -06:00
sheet-navigation: keep boundary navigation on visible worksheets
This commit is contained in:
+3
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
**Stage: alpha** · next: beta, ~25 points of "ready for real work" and ~160–240 h away
|
||||
|
||||
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-11 · **Change:** minor (password-encrypted workbooks open, #11) · **Target:** Microsoft Excel (Microsoft 365)
|
||||
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-12 · **Change:** minor (sheet navigation stays on visible worksheets at boundaries) · **Target:** Microsoft Excel (Microsoft 365)
|
||||
|
||||
GridCraft aims at full Microsoft Excel parity, and at being better in places: faster, open (XLSX
|
||||
is the native format), fully scriptable by agents (MCP, control channel, CLI), and on the web.
|
||||
@@ -132,6 +132,7 @@ Ranked; estimates in Opus 5.5 agent-hours. Detail and the full beta-gate list in
|
||||
|
||||
| Date | What landed |
|
||||
|---|---|
|
||||
| 2026-10-12 | Next/previous sheet navigation stops at the first/last visible worksheet instead of activating a hidden boundary sheet; the current selection is retained |
|
||||
| 2026-10-11 | Command-sequence fuzzing: random command sequences checked against undo/redo, XLSX round-trip and full recalculation; fixes for the table, legacy-array, spill, AutoSum, Watch Window and sheet-copy bugs it found |
|
||||
| 2026-10-11 | Password-protected workbooks open: GridCraft asks for the password and decrypts Agile and Standard encryption (#11) |
|
||||
| 2026-10-11 | Text boxes keep their formatting: run size, bold, italic, typeface, text colour and outline, alignment, vertical anchor and "no outline" (#377) |
|
||||
@@ -177,6 +178,7 @@ Ranked; estimates in Opus 5.5 agent-hours. Detail and the full beta-gate list in
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-12 | minor | Progress log: hidden-sheet navigation at workbook boundaries |
|
||||
| 2026-10-11 | minor | Password-encrypted workbooks open (#11); progress log row |
|
||||
| 2026-10-11 | minor | Forecast Sheet (#322); progress log row |
|
||||
| 2026-10-11 | minor | Worksheet functions 505 / 523 (ODD* bond functions); progress log row |
|
||||
|
||||
@@ -890,17 +890,18 @@ fn activate(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
Ok(json!({"sheet": i, "name": d.wb.active().map(|s| s.name.clone())}))
|
||||
}
|
||||
|
||||
fn step_sheet(s: &mut Session, dir: i64) -> Result<Json> {
|
||||
fn step_sheet(s: &mut Session, dir: isize) -> Result<Json> {
|
||||
let d = s.doc()?;
|
||||
let n = d.wb.sheets.len() as i64;
|
||||
let mut i = d.wb.active_sheet as i64;
|
||||
for _ in 0..n {
|
||||
i = (i + dir).clamp(0, n - 1);
|
||||
if d.wb.sheet(i as usize).is_some_and(|s| s.visibility == Visibility::Visible) {
|
||||
break;
|
||||
let mut i = d.wb.active_sheet;
|
||||
while let Some(next) = i.checked_add_signed(dir) {
|
||||
let Some(sheet) = d.wb.sheet(next) else { break };
|
||||
if sheet.visibility == Visibility::Visible {
|
||||
s.doc_mut()?.wb_switch_sheet(next);
|
||||
return ok();
|
||||
}
|
||||
i = next;
|
||||
}
|
||||
s.doc_mut()?.wb_switch_sheet(i as usize);
|
||||
// No visible sheet in this direction: keep the current sheet and its selection.
|
||||
ok()
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
//! Sheet navigation must never activate hidden sheets when it reaches a workbook boundary.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use gridcraft_engine::{Session, model::Visibility};
|
||||
use serde_json::json;
|
||||
|
||||
fn workbook(hidden: &[usize], active: usize) -> Session {
|
||||
let mut session = Session::new();
|
||||
session.new_workbook();
|
||||
for name in ["Second", "Third", "Fourth"] {
|
||||
session.execute("home.insertSheet", json!({"name": name})).unwrap();
|
||||
}
|
||||
for sheet in hidden {
|
||||
session.execute("sheet.hide", json!({"sheet": sheet})).unwrap();
|
||||
}
|
||||
session.execute("sheet.activate", json!({"sheet": active})).unwrap();
|
||||
session.execute("selection.set", json!({"cell": "C7"})).unwrap();
|
||||
session
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn next_stays_on_the_last_visible_sheet() {
|
||||
let mut session = workbook(&[2, 3], 1);
|
||||
for _ in 0..2 {
|
||||
session.execute("sheet.next", json!({})).unwrap();
|
||||
let doc = session.active().unwrap();
|
||||
assert_eq!(doc.wb.active_sheet, 1);
|
||||
assert_eq!(doc.selection.active.a1(), "C7");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn previous_stays_on_the_first_visible_sheet() {
|
||||
let mut session = workbook(&[0, 1], 2);
|
||||
for _ in 0..2 {
|
||||
session.execute("sheet.previous", json!({})).unwrap();
|
||||
let doc = session.active().unwrap();
|
||||
assert_eq!(doc.wb.active_sheet, 2);
|
||||
assert_eq!(doc.selection.active.a1(), "C7");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn navigation_skips_hidden_sheets_in_both_directions() {
|
||||
let mut session = workbook(&[1, 2], 0);
|
||||
session.execute("sheet.next", json!({})).unwrap();
|
||||
assert_eq!(session.active().unwrap().wb.active_sheet, 3);
|
||||
session.execute("sheet.previous", json!({})).unwrap();
|
||||
let doc = session.active().unwrap();
|
||||
assert_eq!(doc.wb.active_sheet, 0);
|
||||
assert_eq!(doc.selection.active.a1(), "C7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn navigation_with_one_visible_sheet_is_a_noop() {
|
||||
let mut session = workbook(&[0, 2, 3], 1);
|
||||
for command in ["sheet.previous", "sheet.next"] {
|
||||
session.execute(command, json!({})).unwrap();
|
||||
let doc = session.active().unwrap();
|
||||
assert_eq!(doc.wb.active_sheet, 1);
|
||||
assert_eq!(doc.selection.active.a1(), "C7");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn very_hidden_sheets_are_skipped_at_interior_and_boundary_positions() {
|
||||
let mut session = workbook(&[1, 3], 0);
|
||||
// VeryHidden is an imported XLSX state; sheet.hide only creates Hidden sheets.
|
||||
let wb = Arc::make_mut(&mut session.active_mut().unwrap().wb);
|
||||
for index in [1, 3] {
|
||||
Arc::make_mut(&mut wb.sheets[index]).visibility = Visibility::VeryHidden;
|
||||
}
|
||||
for (command, expected) in [("sheet.next", 2), ("sheet.next", 2), ("sheet.previous", 0)] {
|
||||
session.execute(command, json!({})).unwrap();
|
||||
assert_eq!(session.active().unwrap().wb.active_sheet, expected);
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -1,6 +1,6 @@
|
||||
# Gaps
|
||||
|
||||
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-11 · **Change:** minor (§6: iterative calculation landed) · **Target:** Microsoft Excel (Microsoft 365)
|
||||
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-12 · **Change:** minor (§9: hidden-sheet navigation at workbook boundaries fixed) · **Target:** Microsoft Excel (Microsoft 365)
|
||||
|
||||
Every known shortfall against Excel, one entry each, ranked by user impact (what blocks someone
|
||||
using GridCraft for real work first). This is the work list: pick from the top, check the open
|
||||
@@ -84,6 +84,8 @@ No alpha blockers: every core workflow passes the [alpha gate](roadmap.md#alpha-
|
||||
- **Estimate:** 20–30 h for beta (25–40 h full).
|
||||
|
||||
### 9. Keyboard-first users: key tips, shortcuts, context menus (U)
|
||||
- Next/previous sheet navigation now skips Hidden and VeryHidden worksheets without activating a
|
||||
hidden sheet at the workbook boundary. Other keyboard gaps below remain.
|
||||
- **Evidence:** #33, #49 (key tips: initial Home-tab support landed in #43 on 10-10, the rest of the ribbon not yet), #110, #28 (selection),
|
||||
59 command shortcuts vs Excel's 200+.
|
||||
- **Estimate:** 12–20 h. [ui-parity.md](ui-parity.md)
|
||||
@@ -160,6 +162,7 @@ No alpha blockers: every core workflow passes the [alpha gate](roadmap.md#alpha-
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-12 | minor | §9: next/previous sheet commands retain the current visible sheet and selection when there is no visible destination |
|
||||
| 2026-10-11 | minor | §6: iterative calculation for circular references landed (Maximum Iterations, Maximum Change) |
|
||||
| 2026-10-11 | minor | §15: trim-reference operators (`A1:.E10`, `A1.:E10`, `A1.:.E10`) parse and evaluate |
|
||||
| 2026-10-11 | minor | §4: trendlines (six types, forecast, equation and R²) read, written and drawn |
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
# UI parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (AutoFit reserves filter dropdown space, observed against Windows Excel) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (next/previous sheet navigation stops at visible-sheet boundaries) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4
|
||||
|
||||
Interaction, controls and feel, against Excel. Part of [target-app-parity.md](target-app-parity.md).
|
||||
**UI/UX fidelity: ~55% ready, 50–80 h** (estimated). Ribbon command coverage is measured
|
||||
@@ -21,7 +21,7 @@ Sources: `crates/ui-egui/src` (ribbon, grid, editor, formula bar, dialogs, panes
|
||||
| Ribbon collapse, simplified ribbon, customize ribbon/QAT | yes | partial | customization missing |
|
||||
| Key tips (Alt / F10 then letters) | yes, every ribbon control | **initial** (#43, 10-10): Alt or F10 shows key tips on Home for alignment, Paste Special and AutoFit plus legacy Alt sequences; other tabs and controls not yet (#33, #49) | 3–5 h |
|
||||
| Formula bar with Name Box, expand, function hints | yes | yes | done |
|
||||
| Sheet tabs: rename, reorder, colour, hide, scroll | yes | yes | rename focus bug on macOS (#145) |
|
||||
| Sheet tabs: rename, reorder, colour, hide, scroll | yes | yes | next/previous skips Hidden and VeryHidden sheets and retains the current sheet and selection when no visible destination exists; rename focus bug on macOS (#145) |
|
||||
| Status bar: Sum/Count/Average and more, view buttons, zoom | yes | yes | customizable statistics partial |
|
||||
| Task panes (Format Chart, Comments, Watch, Selection, PivotTable fields) | yes | yes | element-level Format pane for shapes and pictures missing |
|
||||
| Backstage (File) view: Info, New with templates, Open recent, Export, Options | yes | partial | Options dialog and template gallery missing |
|
||||
@@ -160,6 +160,7 @@ scrollbar bugs 2–4 · pixel/feel pass against observed Excel 7–12.
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-12 | minor | Next/previous sheet navigation no longer activates hidden worksheets at either workbook boundary; command tests cover Hidden, VeryHidden and selection retention |
|
||||
| 2026-10-11 | minor | AutoFit accounts for table and ordinary filter dropdowns, including low zoom; header text excludes the button area |
|
||||
| 2026-10-11 | minor | Outline band for grouped rows and columns, Show / Hide Detail on the Data tab, numpad navigation keys in shortcuts (#373) |
|
||||
| 2026-10-11 | minor | Shift+Space / Ctrl+Space no longer start an edit; Control+Space selects the column on Mac (#338) |
|
||||
|
||||
Reference in New Issue
Block a user