Release 1.1.0: fix blank window after export, clipped form fields, add units of measure #2

Closed
xavierk wants to merge 0 commits from release/1.1.0 into main
Owner

New

  • Units of measure. A rate line can now be priced per second, minute, hour, day, week, month or session; per
    unit, piece or set; per km or metre; per square foot or square metre; per kg; per litre; or per a custom unit you
    type (up to 12 characters). The unit prints on the invoice beside the quantity ("4.5 hr", "12.75 km") and in the rate
    ("₹1,200.00 per hour"), on all 14 templates.
  • Time typed as hours and minutes. In a time unit, type 4:30 and it counts as 4.5 hours when the amount is
    worked out, with the decimal shown under the box. 4:20 is kept as an exact 4.333... so the amount is not off by a
    paisa. Other units take decimals such as 12.75.
  • Item presets can use any unit as well. The export format (voiced.invoice.v1) documents the new unit values.

Fixed

  • The window went blank after every export, so the app had to be killed. The "Saved to ..." notice held buttons
    inside a notification, which made the interface crash and leave an empty window. It now shows the notice and the
    Open file and Show in folder buttons, and you can go straight to New invoice. If anything in the interface ever
    fails again, a message with a Reload button appears instead of a blank window.
  • A saved client's name was cut off (for example "Timber Media Pv" for "Timber Media Pvt Ltd"). The saved-client
    box and the other invoice fields were too narrow; the form now uses the full width. Dates, GSTIN, PO number and
    place of supply no longer clip their text, and the line type shows "Rate × quantity" in full.
  • Quantities with a long unit (for example "120 wooden crate") no longer squeeze the description column in the
    templates, and the Classic template's quantity column grows to hold "12.75 km" on one line.

Known

  • Windows has not been run on a real machine yet; it is built and tested from Linux only.
  • ERPNext: a custom unit is sent as "Nos", which ERPNext only accepts for whole numbers, and "Month" is not a stock
    ERPNext unit. Map the unit in Settings, Integrations. A time such as 4:20 hours (not exact to three decimals) is
    still refused for sending, with a message saying so.

Merge with a merge commit (not squash or rebase): the v1.1.0 tag already points at the head of this branch and the release assets were built from it.

Local gates on this head: tsc, ESLint (0 errors), cargo fmt --check, jscpd 3.57%, Semgrep clean, Playwright smoke test, vitest 1729 passed, cargo test 253 passed, fonts:verify, real-webview self-test ok.

## New - **Units of measure.** A rate line can now be priced per second, minute, hour, day, week, month or session; per unit, piece or set; per km or metre; per square foot or square metre; per kg; per litre; or per a custom unit you type (up to 12 characters). The unit prints on the invoice beside the quantity ("4.5 hr", "12.75 km") and in the rate ("₹1,200.00 per hour"), on all 14 templates. - **Time typed as hours and minutes.** In a time unit, type `4:30` and it counts as 4.5 hours when the amount is worked out, with the decimal shown under the box. `4:20` is kept as an exact 4.333... so the amount is not off by a paisa. Other units take decimals such as `12.75`. - Item presets can use any unit as well. The export format (`voiced.invoice.v1`) documents the new unit values. ## Fixed - **The window went blank after every export, so the app had to be killed.** The "Saved to ..." notice held buttons inside a notification, which made the interface crash and leave an empty window. It now shows the notice and the Open file and Show in folder buttons, and you can go straight to New invoice. If anything in the interface ever fails again, a message with a Reload button appears instead of a blank window. - **A saved client's name was cut off** (for example "Timber Media Pv" for "Timber Media Pvt Ltd"). The saved-client box and the other invoice fields were too narrow; the form now uses the full width. Dates, GSTIN, PO number and place of supply no longer clip their text, and the line type shows "Rate × quantity" in full. - Quantities with a long unit (for example "120 wooden crate") no longer squeeze the description column in the templates, and the Classic template's quantity column grows to hold "12.75 km" on one line. ## Known - Windows has not been run on a real machine yet; it is built and tested from Linux only. - ERPNext: a custom unit is sent as "Nos", which ERPNext only accepts for whole numbers, and "Month" is not a stock ERPNext unit. Map the unit in Settings, Integrations. A time such as 4:20 hours (not exact to three decimals) is still refused for sending, with a message saying so. Merge with a merge commit (not squash or rebase): the `v1.1.0` tag already points at the head of this branch and the release assets were built from it. Local gates on this head: tsc, ESLint (0 errors), cargo fmt --check, jscpd 3.57%, Semgrep clean, Playwright smoke test, vitest 1729 passed, cargo test 253 passed, fonts:verify, real-webview self-test ok.
xavierk added 6 commits 2026-10-06 04:34:21 +00:00
The saved-client box showed "Timber Media Pv" for "Timber Media Pvt Ltd": the form sat on a Carbon Grid nested in a
Column, whose tracks came out much narrower than the page grid, so the combo box was about 230 px wide at the default
window size and the date, GSTIN and PO fields were just as tight. The fields now sit on a plain 12-column CSS grid
(.voiced-fields), the client fields use the full width, place of supply gets its own row, and the line type select is
wide enough for "Rate x quantity".

Claude-Session: https://claude.ai/code/session_01PZypiWDfMkDTeEPeXjRhW5
Every successful export left the window blank and unresponsive, so the app had to be killed. The "Saved to ..." notice
(and the export-failed notice) held buttons inside a Carbon InlineNotification. Carbon throws "component should have no
interactive child nodes" in an effect, and an uncaught throw makes React unmount the whole tree. Found by driving the
real debug binary through WebKitWebDriver: the page body was empty and the error listener showed that throw.

- The buttons now sit beside the notice, and the failed-export notice uses ActionableNotification's own Retry action.
- ErrorBoundary around the app (reload screen instead of a blank window) and around each export notice.
- A lint test that fails if a Carbon notification wraps an interactive element.
- The real-webview self-test mounts the saved and failed notices and fails on an uncaught React error, and issues and
  exports a second invoice after the first.

Claude-Session: https://claude.ai/code/session_01PZypiWDfMkDTeEPeXjRhW5
Quantities can now be time, count, distance, area, weight or volume, or a custom unit, instead of only
second/minute/hour/session/unit.

- Registry in src/lib/units.ts (mirrored in src-tauri/src/units.rs): grouped built-in units plus a custom unit of 1-12
  characters. A rate line's unit is validated when an invoice or a preset is saved; migration M12 drops the old unit
  allow-list from item_presets and keeps every row.
- Time is typed as h:mm: "4:30" hours counts as 4.5, "4:20" as 4.333... (kept exact, so rate x quantity rounds once, the
  same in TypeScript and Rust). Other units take plain decimals up to 3 places. A bad quantity blocks issuing.
- The PDF quantity column shows the unit ("4.5 hr", "12.75 km"); the rate keeps "per hour" / "/hr". RenderItem carries
  priceText, perText and rateShort, so no template parses the rate text with a regex over five hard-coded units.
- Quantity columns are sized from the widest word once a quantity with its unit is wider than 72 pt, so one long
  custom unit cannot squeeze the description (the serenity and citrus-split tables overflowed in the new fixture).
  Classic's quantity column is now content-sized.
- ERPNext: the default UOM map comes from the registry, with fractional-capable UOMs for time, distance, area, weight
  and volume. A custom unit is sent as Nos. A quantity that is not exact to 3 decimals (4:20 hours) is still refused for
  push, as before.
- Goldens and template thumbnails regenerated; the template harness has a "units" fixture with the longest texts.

Claude-Session: https://claude.ai/code/session_01PZypiWDfMkDTeEPeXjRhW5
Version bump, the README line about units, and two new manual checks in the release checklist (export then New invoice
through the real save dialog, and units).

Claude-Session: https://claude.ai/code/session_01PZypiWDfMkDTeEPeXjRhW5
# Conflicts:
#	package-lock.json
#	src/views/NewInvoice.tsx
Run cargo fmt on the unit code and drop a quantity box's invalid mark when its line is removed
Windows build / build (push) Waiting to run
CI / security (pull_request) Successful in 58s
CI / lint (pull_request) Successful in 2m51s
CI / e2e (pull_request) Successful in 3m34s
CI / ai-review (pull_request) Failing after 10m2s
93a4ece886
The new CI runs cargo fmt --check. QuantityInput also reported its validity only when it changed, so removing a line
whose quantity box held bad text left that box counted as invalid and blocked issuing; it now reports valid when it
unmounts, and no longer writes a ref during render.

Claude-Session: https://claude.ai/code/session_01PZypiWDfMkDTeEPeXjRhW5
First-time contributor

Preparing review...

Preparing review...
Author
Owner

Closing: every commit in this PR (head 93a4ece, release/1.1.0) is already in main through #3 (Release 1.2.0: Reset all data), which was merged as e87fd8f. Nothing left to merge here.

Closing: every commit in this PR (head 93a4ece, release/1.1.0) is already in main through #3 (Release 1.2.0: Reset all data), which was merged as e87fd8f. Nothing left to merge here.
xavierk closed this pull request 2026-10-06 07:25:16 +00:00

Pull request closed

Please reopen this pull request to perform a merge.
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: xavierk/Voiced#2