Commit Graph
370 Commits
Author SHA1 Message Date
neilcawseandClaude Opus 5.5 1f7fd07c0d PivotTables: values on rows (Σ Values in Rows, dataOnRows)
With two or more value fields the Σ Values pseudo-field can sit in Rows
as well as Columns, at any position among the row fields. The model
records it (`PivotTable.values_on_rows`, `values_position`) and the
engine lays it out like Excel in compact, outline and tabular form: one
row item per value field at the Σ Values level, per-value subtotals
("East Sum of Sales") and grand totals ("Total Sum of Sales").

XLSX reads `dataOnRows` and the `-2` field's place in rowFields or
colFields and writes them back; the "values on rows are shown on
columns" warning is gone. `pivot.moveField` moves "Σ Values" between
Rows and Columns or within one, axis field moves keep it in place, and
the PivotTable Fields pane lists it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 12:06:30 -04:00
jonathanwxh-cell d4874373a4 #551: preserve editable ink through XLSX round trips 2026-10-12 23:54:44 +08:00
Isaac Levine 746a1e0364 File: Export as PDF in the File menu, and the palette asks for a path (#407) 2026-10-12 11:03:13 -04:00
RichardandClaude Opus 5.5 ae54c84bc9 Key the cached Top 10 cutoff by criterion, not column (#661)
Two Top 10 criteria on one column (possible in native JSON files) shared one
cache entry, so the last cutoff overwrote the first. Reported by @derechopiano.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ut3hr3a13szpQdQ7gbYbfc
2026-10-13 00:10:54 +11:00
RichardandClaude Opus 5.5 bf9a202222 Compute the Top 10 filter threshold once per column, not once per row (#661)
apply_filter cloned and sorted the column's numbers for every row it tested,
O(n^2 log n). The threshold is now computed once per criterion with the other
column stats. Adds a test for top/bottom items and percent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ut3hr3a13szpQdQ7gbYbfc
2026-10-12 20:29:00 +11:00
MarekSpodBiedry 7d9c0a4dd9 Center Across Selection: center text over the empty cells to its right (#479) 2026-10-12 08:41:31 +02:00
MarekSpodBiedry 9da1814cdf Refuse a PivotTable that cannot fit before aggregating all column groups (#515) 2026-10-12 08:39:35 +02:00
MarekSpodBiedry 5334ae5cbc Keep manually hidden and collapsed rows when removing an AutoFilter (#508) 2026-10-12 08:39:12 +02:00
MarekSpodBiedry 5fbd726a11 Treat non-object params as empty in themeColors, background and drawBorder (#516) 2026-10-12 08:38:11 +02:00
MarekSpodBiedry c20f4c2fcb Fail Web Page export on sheets taller than its row limit instead of dropping cells (#514) 2026-10-12 08:38:04 +02:00
MarekSpodBiedry baac184ed8 Reject row/column insert counts past the worksheet and clamp delete counts instead of overflowing (#531) 2026-10-12 08:37:46 +02:00
MarekSpodBiedry 3846376937 Refuse Total Row on a table that ends on the last worksheet row (#533) 2026-10-12 08:37:37 +02:00
MarekSpodBiedry 2d0fb534a2 Fix saving a custom view or script when the stored list is not a JSON object (#517) 2026-10-12 08:37:04 +02:00
MarekSpodBiedry 7464ce6e6e Return an error when a weekday fill runs past the supported dates (#535) 2026-10-12 08:36:31 +02:00
MarekSpodBiedry 125f460cef Paste Special: copy the validation rule with the Validation and All options (#562) 2026-10-12 08:36:13 +02:00
MarekSpodBiedry 76d3879a94 Fix data.filterBy inside a table installing the sheet AutoFilter instead of toggling the table button (#547) 2026-10-12 08:35:51 +02:00
MarekSpodBiedry 0ae1eafc9b Open files by their content, not a mismatched extension (#569) 2026-10-12 08:34:52 +02:00
MarekSpodBiedry ff14224ff9 Convert TODAY and NOW to the workbook date system in 1904 workbooks (#578) 2026-10-12 08:34:40 +02:00
MarekSpodBiedry 8427681d7c Tables: names with a hyphen or other operator characters are rejected (#576) 2026-10-12 08:34:22 +02:00
MarekSpodBiedry 40dfdd8331 Restore frozen panes when showing a custom view (#577) 2026-10-12 08:33:43 +02:00
MarekSpodBiedry 34e1d373bf fix(engine): CSV named History keeps a valid sheet name (#570) 2026-10-12 08:33:17 +02:00
MarekSpodBiedry c13cda2229 Column sort rejects a zero row key with a parameter error instead of panicking (#534) 2026-10-12 08:31:04 +02:00
MarekSpodBiedry b5827f4198 Spelling: skip suggestions for words longer than 64 characters (#532) 2026-10-12 08:30:19 +02:00
MarekSpodBiedry 1f16c2e268 fix(calc): recalculate dependents of a cleared spill past 65536 cells (#558) 2026-10-12 08:29:06 +02:00
MarekSpodBiedry 593776f0de Keep a defined name that shares a table's name when the table is renamed (#574) 2026-10-12 08:28:36 +02:00
MarekSpodBiedry c5d43a33e6 Reject table.resize to a range that does not overlap the table (#575) 2026-10-12 08:27:34 +02:00
MarekSpodBiedry a4c6ac3eff Reject out-of-range numeric filterBy columns instead of overflowing (#573) 2026-10-12 08:27:08 +02:00
prxnvt 019d5de98e Data: Solver Answer and Limits reports
Builds on the Solver of #327. data.solver takes reports: [answer, limits]
and writes them on new sheets before the model's sheet once a solution
is found. The Answer report lists the objective and variable cells with
their original and final values and each constraint's value, formula,
status (Binding or Not Binding) and slack; cells are named by the
nearest labels to their left and above. The Limits report minimises and
maximises each variable with the others held at the solution, under the
model's constraints, and gives the objective at both ends (Simplex LP
and GRG Nonlinear, without integer constraints).

data.solverReport writes the reports for a given solution and model,
so data.solver's result (which now carries the original values and the
model) can be passed to it as is. The Solver Results dialog offers the
two reports; they are written after Keep Solver Solution or Restore
Original Values.
2026-10-11 22:25:08 -04:00
prxnvt fa2b9566fb Data: Solver Evolutionary method
Builds on the Solver of #327. method: evolutionary runs a genetic search
for models that aren't smooth: tournament selection, blend crossover and
Gaussian mutation inside the variable bounds, feasibility-first ranking
and integer rounding, then a compass search around the best member. It
stops when the population converges, when the best member stops
improving for a number of generations, or at the evaluation budget. A
seeded generator makes runs repeatable. Population size, mutation rate,
random seed, convergence and Require Bounds are options; the method and
its options are saved in the hidden solver_* names. The Solver
Parameters dialog offers the method.
2026-10-11 22:09:10 -04:00
webdevtodayjason fb7bcefaa4 OFFSET: huge offsets and sizes give #REF! instead of overflowing 2026-10-11 20:50:23 -05:00
skylar taylor-barrick 587d879f13 Print: adopt craft-print with native settings and job feedback 2026-10-12 03:25:47 +02:00
SteamSmithandClaude Opus 5.5 3424229ee3 io: remove the .sctmp temporary file when a save fails
write_file writes `<path>.sctmp` and renames it over the workbook. When the
write or the rename failed (a full disk, or the target locked by another
app such as Excel or a sync client), the temporary file was left beside the
user's workbook. Remove it on either failure and report the same error.

Adds io::tests::failed_save_leaves_no_temporary_file, which fails before
this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:59:42 -04:00
Brandon Thomas 3b19cb80e6 Merge pull request #412 from jsymes21-byte/keytips-table-refactor
Keytips: full Excel sequential Alt table — 364 sequences, badges on every control, generated tests (fixes #33, #49)

# Conflicts:
#	contributors/people.toml
2026-10-11 18:06:06 -04:00
Brandon Thomas a34fe4a7af Merge pull request #436 from LloydNicholson/feat/open-encrypted
Open password-encrypted workbooks (Agile and Standard encryption) (#11)

# Conflicts:
#	ROADMAP.md
#	docs/file-format-parity.md
#	docs/gaps.md
#	docs/target-app-parity.md
2026-10-11 18:06:04 -04:00
Brandon Thomas 0a54876e2c Merge pull request #425 from neilcawse/test/command-sequence-fuzz
Engine: command-sequence fuzz harness (undo/redo, XLSX round-trip, full-recalc invariants) and the bugs it found
2026-10-11 18:06:03 -04:00
Brandon Thomas 69b5f78e86 Merge pull request #424 from neilcawse/fix/trendlines
Charts: read, write and draw trendlines

# Conflicts:
#	docs/gaps.md
2026-10-11 18:06:01 -04:00
Brandon Thomas dcd469d12e Merge pull request #419 from neilcawse/fix/function-fixes
Functions: MODE/VALUE/SUMPRODUCT text args, ADDRESS [Book]Sheet, Excel-style lookup bisection, SUBTOTAL skips filtered rows

# Conflicts:
#	docs/file-format-parity.md
#	docs/function-parity.md
2026-10-11 18:05:41 -04:00
Brandon Thomas 80c2efe0f1 Merge pull request #421 from neilcawse/fix/iterative-calc
Calc: iterative calculation for circular references (Maximum Iterations, Maximum Change)

# Conflicts:
#	docs/function-parity.md
2026-10-11 18:05:39 -04:00
Brandon Thomas 74d57ea9fd Merge pull request #422 from neilcawse/fix/csv-display
File formats: CSV/TSV export writes displayed values; templates and .xlsm saved with their own content types

# Conflicts:
#	crates/engine/src/io.rs
#	crates/xlsx/src/tests/roundtrip.rs
#	docs/file-format-parity.md
2026-10-11 18:05:33 -04:00
Brandon Thomas a96f19f02b Merge pull request #409 from shrshk/fix/formula-arg-count-363
Refuse formulas with the wrong argument count on entry (#363)
2026-10-11 18:05:18 -04:00
Brandon Thomas 5432419cd5 Merge pull request #427 from vedran-dobos/csv-keep-delimiter
CSV: saving keeps the separator the file was opened with (#426)
2026-10-11 18:05:14 -04:00
Vedran DobosandClaude Opus 5.5 b13ea3e2f3 CSV: saving keeps the separator the file was opened with (#426)
A `;`-separated CSV (the usual CSV where `,` is the decimal separator) was
rewritten with `,` on save: read_csv sniffed the delimiter but the result was
dropped, and save_bytes passed a hard-coded b','. file.save, Save As .csv,
file.exportCsv, file.saveBytes and gridcraft-cli convert all went through it.

The workbook now remembers the separator it was read with
(Workbook::csv_delimiter, set by read_csv) and a CSV save writes it back.
Workbooks not read from CSV, and .tsv/.txt sources saved as .csv, keep `,`.

Regression tests: `;`, `,` and tab .csv round trips byte for byte, new and
.xlsx-origin workbooks save with `,`, and open-by-path + edit + file.save on a
`;` file keeps `;` (also through exportCsv and saveBytes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:46:27 -07:00
Brandon Thomas e6773dac3c Merge pull request #433 from derechopiano/fix/autofit-filter-button-spacing
Fix AutoFit width for table and AutoFilter dropdowns
2026-10-11 18:05:13 -04:00
MarekSpodBiedry 88df1670ba Scatter charts of two unlabelled columns plot the first as X for one series (#428) 2026-10-11 23:38:27 +02:00
lloydandClaude Opus 5.5 1532349227 Encrypted workbooks no password opens are named before asking for one (#11)
gridcraft_xlsx::check_encryption parses EncryptionInfo without a
password, so RC4, Extensible, certificate-only and rights-management
(IRM) files, and damaged ones, get their real message instead of a
password prompt first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:29:28 +02:00
lloydandClaude Opus 5.5 aad58d4c75 Engine: file.open decrypts password-protected workbooks (#11)
Without a password, file.open returns an error carrying
io::PASSWORD_REQUIRED (never a dialog). A decrypted workbook gets no save
path, so Save never replaces the encrypted original.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:29:28 +02:00
Shirish Veerabattini 3936f3b79c engine: correct which functions the entry check skips
IF, IFERROR, CHOOSE, SWITCH and INDEX are in the registry and are checked; the comment listed IF as skipped.

Claude-Session: https://claude.ai/code/session_01BGBBGBC2gRpQ7GDuwQ6WPt
2026-10-11 16:10:04 -05:00
derechopiano 1a6c864235 home.autofitColumnWidth: reserve filter dropdown space 2026-10-11 22:09:51 +01:00
Shirish Veerabattini 478f01d236 functions: keep DATEDIF's original description, add the units
Restores "Counts whole years, months or days between two dates." and
appends the units, in the multi-line form rustfmt gives a long entry.

Drops the 256-argument test case: the parser already refuses more than
255 arguments, so it never reached the entry check. (993c108's message
says entry "also refuses" them; it already did.)

Claude-Session: https://claude.ai/code/session_01BGBBGBC2gRpQ7GDuwQ6WPt
2026-10-11 15:57:33 -05:00
James cd5f3f0a71 T6: pending keytips resolve at runtime and go live when their command lands
- Action::Pending now consults the engine catalog at fire time: silent
  no-op while the command is missing, runs it once it exists - no table
  edit needed when a future feature lands.
- Stripped stray backticks from 7 pending target ids so catalog lookup
  can ever match them.
- gridcraft-engine: doc(hidden) register_test_command hook so UI tests
  can prove the go-live path without touching production code.
- Tests: pending_sequences_are_silent_no_ops (no dialog/toast/journal),
  pending_sequences_go_live_when_the_command_lands (fake command fires
  via its reserved sequence), every_sequence_terminates_without_panicking
  (all 413 sequences pressed end-to-end).
2026-10-11 23:40:04 +03:00