Problem
Users are routinely handed a spreadsheet template, fill it in offline, and upload it to a form. Today that upload is a dead attachment: the file is stored, but nothing reads it. The same figures then get retyped into the form by hand, which is slow, error-prone, and means nothing downstream can act on the numbers.
Two forms in one-trade-artifacts already assume this capability exists:
- SLTB blend sheet (
sltb/1-application) has a .xlsx upload for the "Particulars of Sale" grid, and the trader retypes every sale row into the form.
- CDA (
cda/1-application) tells the trader to download a template, fill it in, upload it — and also asks them to re-enter the same rows into a dc_grades array.
What's needed
A renderer that reads an uploaded spreadsheet and turns it into form data:
- Parse on upload. When the user picks an
.xlsx, extract its rows in the browser so they see the result before submitting and can fix the sheet and re-upload. The file must still upload exactly as it does today — same UploadProvider contract, same storage key.
- Write rows into a sibling array field, so the extracted table becomes ordinary form data that validates and submits like anything else.
- Compute summary values from the rows (totals, weighted averages, dominant category) into sibling fields.
- Be schema-driven. Column names, formulas, and any domain knowledge belong in the artifact JSON, not in the renderer — the same control has to serve SLTB tea grades and CDA bag counts without code changes.
- Report what happened. Row count, columns it could not find, rows it skipped, and any calculation that failed — silence would let a wrong or empty figure pass as correct.
Constraints worth stating up front
- Real templates are messy. They carry banner/title rows above the grid, blank spacer rows, and a trailing
TOTAL row. Anything that assumes the header is row 1, or that sums a fixed cell range, will silently produce wrong numbers — a range that overshoots the data picks up the TOTAL row and doubles the figure.
- Column order and spelling drift between template revisions, so columns should be located by header text rather than by position.
- Licensing. This is an Apache-2.0 package. HyperFormula, the most complete formula engine, is GPL-3.0-only and therefore unusable here.
- Bundle size. Spreadsheet reading and formula evaluation together run to a few hundred kilobytes. Applications that use the renderer set without any spreadsheet field must not pay for it.
Out of scope
- Parsing
.xml blend sheets (the SLTB field accepts .xml too; those uploads should be stored and left alone).
- Server-side re-parsing. Values extracted in the browser are only as trustworthy as the client; any consumer needing them tamper-evident should re-derive them from the stored file. Worth a separate issue.
Problem
Users are routinely handed a spreadsheet template, fill it in offline, and upload it to a form. Today that upload is a dead attachment: the file is stored, but nothing reads it. The same figures then get retyped into the form by hand, which is slow, error-prone, and means nothing downstream can act on the numbers.
Two forms in
one-trade-artifactsalready assume this capability exists:sltb/1-application) has a.xlsxupload for the "Particulars of Sale" grid, and the trader retypes every sale row into the form.cda/1-application) tells the trader to download a template, fill it in, upload it — and also asks them to re-enter the same rows into adc_gradesarray.What's needed
A renderer that reads an uploaded spreadsheet and turns it into form data:
.xlsx, extract its rows in the browser so they see the result before submitting and can fix the sheet and re-upload. The file must still upload exactly as it does today — sameUploadProvidercontract, same storage key.Constraints worth stating up front
TOTALrow. Anything that assumes the header is row 1, or that sums a fixed cell range, will silently produce wrong numbers — a range that overshoots the data picks up theTOTALrow and doubles the figure.Out of scope
.xmlblend sheets (the SLTB field accepts.xmltoo; those uploads should be stored and left alone).