From f42cb697663c6e58ec0a7dcf9e80203cf43a3d37 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 11:46:01 +0000 Subject: [PATCH] feat(showcase): per-line Receipt attachment on invoice lines (upload-in-grid demo) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a `receipt: Field.file()` to showcase_invoice_line so the showcase exercises objectui#2360 end-to-end: the inline line-item grid auto-derives an upload column and renders a compact picker per row (the "attach the receipt to each expense line" pattern). Verified in-browser against this example: upload → save via /api/v1/batch → value persists with a canonical /api/v1/storage/files/ URL → reopening the form renders the stored chip. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01H5tsBSEhsDZmdcHBvfymYC --- examples/app-showcase/src/data/objects/invoice.object.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/app-showcase/src/data/objects/invoice.object.ts b/examples/app-showcase/src/data/objects/invoice.object.ts index c472c34471..36cb6df918 100644 --- a/examples/app-showcase/src/data/objects/invoice.object.ts +++ b/examples/app-showcase/src/data/objects/invoice.object.ts @@ -210,6 +210,11 @@ export const InvoiceLine = ObjectSchema.create({ min: 0, readonlyWhen: P`parent.status == 'paid'`, }), + // Per-line attachment (objectui#2360): the inline line-item grid renders a + // real upload cell for `file` fields — the "attach the receipt to each + // expense line" pattern. Exercises upload-in-grid end-to-end (auto-derived + // column, compact picker, persistence through the storage service). + receipt: Field.file({ label: 'Receipt' }), // Amount = Qty × Unit Price. Kept as a *stored* currency column (so the // parent Invoice.total summary can roll it up — summary aggregation reads // stored columns, not on-read formula fields), but the `expression` makes