06203f97b39325646093a96da24b26e225735aa7
typing into a field and pressing enter did nothing in the document editor, the customer/item/payment/expense dialogs and the send-document dialog — inputs sat in a div, so the button was the only way to submit. now each wraps in a <form onSubmit>, with every non-submit button (cancel, close, add/remove line, "same as billing") marked type="button" so it doesn't submit instead of doing its own thing. the record editors share one dialog shell (EditorShell), so a single form there covers customer, item, payment and expense at once — kept the dialog's grid gap intact with display:contents rather than nesting a box. left the list-view filter boxes and the reports date-range picker alone: none of them has a submit action, so there's nothing for enter to do. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Invoices
Your InvoiceShelf books, inside Officer — invoices, estimates, customers and payments, with the credentials held server-side.
What you get
- Invoices — list, filter by status, open one and see its lines
- Estimates — the same, before they become invoices
- Customers and their history
- Payments recorded against invoices
- Multiple companies — add several sets of books and switch between them
Requirements
A running InvoiceShelf instance Officer can reach, and credentials for it.
Setup
Install the plugin, open /invoices, and add an account: a label, the URL, and the credentials. They are encrypted at rest and never sent to the browser. Mark one active.
The plugin does not install or supervise InvoiceShelf. Point it at one you already run.
Permissions
One permission, invoices, grantable per role like any other app permission.
Notes
- The plugin is named
invoices, notinvoiceshelf— named for what it shows rather than the daemon behind it, which is what keeps the URL/invoices. SeePLUGIN.md.
Languages
TypeScript
100%