Commit graph

4 commits

Author SHA1 Message Date
624d6b846f feat(makepad-table): document library for Phase 3, and correct every stale note
Some checks failed
email.yml / feat(makepad-table): document library for Phase 3, and correct every stale note (push) Failing after 0s
repo hygiene / hygiene (push) Has been cancelled
makepad-table / model (push) Has been cancelled
makepad-table / widget (push) Has been cancelled
makepad-table / hygiene (push) Has been cancelled
Two things: the model layer Invoicer UI Phase 3 needs, and a sweep of the
documentation, which was still describing the crate as it was six phases ago.

`DocumentLibrary` in `makepad-doc-model` — open, save, recents and search,
in the model rather than the app so it is testable without a window. The UI
over it is not built; the README says so rather than claiming the phase.

Three things it gets right that are easy to get wrong:

- A document number becomes a filename and is user-controlled text.
  `safe_file_stem` replaces anything outside `[A-Za-z0-9._-]`, so
  `../../etc/passwd` cannot steer a write out of its directory. Leading dots
  go too, and a fully-stripped name falls back to `untitled`.
- An empty query matches everything, so clearing the search box restores the
  list instead of emptying it. All terms must match, so each word narrows.
- Recents de-duplicate and move to the front. Without that, re-opening one
  file fills the list with it and evicts everything else.

doc-model tests 22 -> 31. Verified by reintroducing four defects: dropping
the filename sanitising fails 3, removing the recents de-duplication fails 1,
and switching the search from all-terms to any-term fails 2.

The empty-query guard is honestly untested and marked as such below.

Two test expectations I wrote were wrong and the code was right, which is
worth recording because both look like search bugs and are not. Searching
"globex" returns the invoice *and* the receipt — both are addressed to
Globex, and finding every document for a client is the point. Searching
"inv-2024-001" also returns both, because the receipt's line item reads
"Invoice INV-2024-001 — Brand identity + website": it is the payment for
that invoice, and surfacing it is the useful answer.

Documentation, all of which had drifted:

- `src/table.rs` called itself a "Phase 1 + 2 scaffold" with "Phase 3+
  (SCAFFOLD ONLY — emits actions, no UI yet)". All six phases are
  implemented; the header now summarises what each one does.
- `src/lib.rs` said Phase 3+ was "scaffolded via TableAction emissions but
  not yet implemented", and did not export the Phase 6 types at all.
  `parse_solid_spec`, `wireframe_edges`, `project_isometric`, `SolidSpec`,
  `SolidSpecError` and `Point3` were public but unreachable from the crate
  root.
- `TableAction::RowMenuRequested` / `ColMenuRequested` were documented as
  "Phase 3 will open a PopupMenu". The widget opens the menu itself; these
  are notifications, not requests.
- Both demos logged "Phase 3 will open PopupMenu" and neither handled
  `ColumnMoved`, so a Phase 4 drag produced no output in either.
- The invoicer's header described a toolbar of six buttons that does not
  exist and a context menu as pending.
- The README's caveats section listed three "if the compiler complains"
  predictions from before the crate had ever been built. All three are
  settled — `KeyCode::Tab` is right, `TextInput` needs no `ComponentRef`,
  pdf-writer 0.15 compiles as written — so it now lists the five real
  remaining limitations instead.
- The README's workspace tree omitted `examples/table_demo` entirely and
  described `table.rs` as 1145 lines; it is 3260.

The "drop into makepad" instructions were quietly wrong after Phase 5 and
are now corrected with verified line numbers. They say to register `Table`
next to `chart`, which at the pinned revision is line 611 — but `MathView`
registers at 617, and `Table`'s DSL body names `mod.widgets.MathView`.
Following the old advice literally would register the widget six lines
before the type it depends on.
2026-08-17 05:30:24 +00:00
c4b646c1fa feat(makepad-table): editable header, currency and tax, doc switcher (Invoicer UI Phase 2)
Some checks failed
email.yml / feat(makepad-table): editable header, currency and tax, doc switcher (Invoicer UI Phase 2) (push) Failing after 0s
repo hygiene / hygiene (push) Has been cancelled
makepad-table / model (push) Has been cancelled
makepad-table / widget (push) Has been cancelled
makepad-table / hygiene (push) Has been cancelled
The invoicer displayed the document number, issue date and due date in three
`TextInput`s that were all `is_read_only: true`, because there was nowhere to
write an edit back to. This is the write half, plus the currency and tax
entry and the sidebar switcher the phase called for.

Model (`makepad-doc-model`):
- Setters for number, both dates, currency, default tax, issuer and
  recipient, each trimming its input. A trailing space in a document number
  becomes a trailing space in the exported filename, and a leading one makes
  two identical-looking documents sort apart.
- `secondary_date`, `set_secondary_date` and `secondary_date_label`, because
  the second date is a due date on an invoice and a valid-until on a quote,
  and a receipt has neither.
- `Currency::presets()` and `from_code()`. An unknown code is refused rather
  than turned into an `Other` with a guessed symbol and decimal count, which
  would format amounts confidently and wrongly.
- `TaxRate::parse_percent`.
- `switcher_label()`.

**A defect this uncovered.** `Document::default_tax()` returned `None` for a
receipt, even though `Receipt` carries a `default_tax` field like the other
two and its `tax_total_minor()` bills from it. The accessor was the only
thing claiming a receipt has no default rate. `document_to_table_data`
trusted it, substituted `TaxRate::zero()`, and printed 0% in the Tax column
for every un-overridden line while the totals underneath were computed from
the real rate — the table and the total disagreeing on the same screen.

It never showed because the shipped sample receipt is 0%-rated, so the wrong
answer and the right one coincided. It separates as soon as a rate is set,
which is exactly what the tax field added here now lets a user do. Fixed at
the accessor, so the table builder is corrected without touching it.

**A second one.** `TaxRate::percent` casts `f64 -> u32`, and that cast
saturates: `percent(-5.0, ..)` is 0%, and so is `percent(f64::NAN, ..)`.
Neither refuses, so a user typing nonsense into the new field would have got
a plausible-looking rate they did not ask for. `parse_percent` validates
first — finite, 0 to 100 — and returns `None` otherwise. Rejected input is
reported in the status line and the field is reset to the stored value, so
the box never keeps text the document did not accept.

UI:
- The three header inputs are editable, with a white background and a focus
  border rather than the read-only grey.
- The due-date field used to render "2024-05-01 (valid until)" for a quote —
  the label baked into the value, so it could not be edited without deleting
  the annotation. The label is now on the label.
- Currency and default-tax fields.
- Three sidebar buttons switch document, labelled from the documents
  themselves, with the current one named below.
- Header edits commit on Return or focus loss, not per keystroke: re-reading
  the model on each character fights the caret, and a half-typed date is not
  a date.

Also fixed, all pre-existing:
- `examples/table_demo` did not compile. It used `action.cast::<T>()`, which
  makepad's Action API no longer has. That package was in no workspace and
  had no CI until the previous commits, so it never failed loudly — it was
  simply never built. This is the second defect found purely by putting it
  somewhere a compiler would look.
- Both demos imported `makepad_widgets` alongside `makepad_table`, which
  re-exports it wholesale, making every widget name ambiguous.
- A dead `refresh_totals_display` no-op stub.
- Stale "Phase 3 will open PopupMenu" status strings; the menus exist.

doc-model tests 12 -> 22, and all five crates now pass
`clippy --all-targets -D warnings`. Verified by reintroducing three defects:
restoring `None` for a receipt's default tax fails the tax-reporting test,
letting `parse_percent` fall through to `percent` fails the validation test,
and dropping the trim fails the whitespace test.

Invoicer UI Phase 3 (file browser, recent documents, search) remains open.
2026-08-17 04:41:08 +00:00
ea98d4d95c fix(makepad-table): exclude from the workspace, pin makepad, fix money defects
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
email.yml / fix(makepad-table): exclude from the workspace, pin makepad, fix money defects (push) Failing after 0s
doc-engine / engine (push) Has been cancelled
doc-engine / consumer (push) Has been cancelled
nigig-map / test (push) Has been cancelled
sms / gates (push) Has been cancelled
sms / robius-sms (push) Has been cancelled
sms / android (push) Has been cancelled
sms / nigig-sms (push) Has been cancelled
sms / supply-chain (push) Has been cancelled
`crates/apps/makepad_table` is a nested workspace that has never been
compiled — its README says as much: "written without a local cargo/rust
toolchain, so the first compile on your machine is the verification step."
This is that step. Four crates, all of which build, and three defects in
the money code that only a compiler and a test runner could have found.

Workspace containment, which is what was asked for:

- The root manifest now names `crates/apps/makepad_table` in `exclude`.
  Cargo already declined to absorb it, because the crate carries its own
  `[workspace]` table — but that made the isolation a property of someone
  else's manifest. Deleting that table would have pulled four crates and a
  second makepad checkout into every workspace-wide build. Verified: the
  root workspace resolves 58 members and none of them are these.

- `examples/table_demo` belonged to no workspace at all and had no
  `[workspace]` table of its own, so `cargo metadata` failed outright in
  that directory. It is now a member of the nested workspace. Kept rather
  than deleted: it is the template the README's "drop into makepad"
  section refers to.

- All three manifests pinned to the fork revision the rest of the repo
  uses (`gitdab.com/andodeki/makepad` @ ecf5a57) instead of tracking
  `github.com/makepad/makepad` branch `dev`. A floating branch means the
  same commit of this repo builds against a different makepad from one day
  to the next, and against a different makepad from every other crate
  here. All four crates verified to compile against the pin.

The defects, in the order they surfaced — each was hidden by the one
before it:

1. `format_with_thousands` computed `(i - first_group_len)` before the
   `i >= first_group_len` guard that protects it. `&&` short-circuits left
   to right, so the check never ran in time. Any number whose leading
   group is short of three digits — 2, 3, 5, 6, 8, 9, 11, 12 digits wide —
   underflowed a usize: a panic in debug, silent wrapping and misplaced
   commas in release. Every currency string in the application went
   through it. The two existing tests used 1234 and 1234567, the two
   widths that happen to work.

2. With the panic gone, `Currency::format` was visibly wrong on negatives.
   The symbol was emitted before a signed whole part, giving "$-12.34"
   instead of "-$12.34"; and `whole` truncated toward zero while `frac`
   used `rem_euclid`, so the two disagreed below zero. -1234 formatted as
   "$-12.66" and -1 as "$0.99" — the wrong sign, the wrong place, and the
   wrong amount.

3. `invoice_totals_arithmetic` asserted `1_840_00` where the sample data
   totals 1_840_000 minor units. The prose in the same comment said
   18,400.00, which is right; the literals were a factor of ten low. The
   arithmetic was never wrong, the expectations were. The two loose range
   assertions on tax and grand total are now exact equalities.

Tests 12 -> 16 across the two crates, and all 16 pass; previously 6 of 12
failed. Each fix was verified by reintroducing the defect on its own:
the guard-order bug fails 5 tests, the sign bug fails 4 with the overflow
fix left in place, and dropping the per-line discount from the tax
calculation fails the arithmetic test by 71.32 — an error the old range
assertions were wide enough to have accepted.
2026-08-17 04:10:26 +00:00
258fa3259e Merge origin/main: resolve xref/document conflicts, add makepad_table
Some checks failed
repo hygiene / hygiene (push) Has been cancelled
PDF engine / engine (push) Has been cancelled
PDF engine / makepad-integration (push) Has been cancelled
PDF engine / fuzz (push) Has been cancelled
2026-08-16 22:53:23 +03:00