oficina / sheets Public

Clone
git clone https://amadan.net/oficina/sheets

Plain git — no account needed to clone.

Download

Download this file

The next three features for Oficina Sheets

1. Multiple tabs in one sheet

What it is. A person can add, name and switch between tabs inside one sheet, using the tab strip in the grid or ordinary links in the table view. XLSX import then brings in every worksheet instead of silently stopping after the first one.

Why it is first. This is the largest remaining gap in the ordinary job PRODUCT.md names: putting real spreadsheet work into a shared grid and moving it in and out without losing structure. The data model already promises tabs, the UI already renders a one-item tab strip, and spec §14 gives a precise trigger: importing later worksheets starts when a second tab is reachable. That trigger has not merely become relevant; the shipped import feature now makes its absence visible whenever a workbook has more than one worksheet.

Cost. This touches internal/sheets/handlers_sheets.go and new tab handlers, templates/sheet.html, templates/table.html, the sheet summary/query code, store/, xlsx/import.go, xlsx/export.go, and small chrome modules under static/. The existing tabs table, sealed tab name, tab position and tab-scoped cells mean it should need no migration. It is still large: permissions, URLs, import cleanup, history, comments, sort/filter and live streams must all remain tab-scoped. Paul should rule the destructive edges before they ship—especially deleting a non-empty tab and what happens to the last tab—but creating, naming and switching tabs does not reopen a settled decision.

What breaks if it is wrong. A partial import can look complete while dropping worksheets, or one tab can leak another tab's cells through a route that checks the sheet but not the tab pairing. I would drop this from the list if the dogfood workbooks are consistently single-worksheet files; without observed multi-tab use, the import trigger has not fired in practice.

Build first. Add and switch tabs through server-rendered links in both the grid and table views, with sealed names and the existing sheet-level grant check. Leave rename, reorder, delete and multi-worksheet import out of that first slice; a two-tab sheet that persists and is reachable is coherent, and it fires the import trigger safely.

2. Formatting in the table view

What it is. A person using the table view can select a cell or range and apply bold, italic, alignment, number format, fill, text colour, column width and row height. The controls are ordinary forms and work without JavaScript.

Why it is second. PRODUCT.md principle 2 says the scriptless path is the product, and explicitly calls the table view unfinished when the grid has an affordance it lacks. Spec §14 records this exact debt and says its trigger is the next slice that touches the table view or Paul asking for it. The grid gained all these controls while templates/table.html still exposes only per-cell value editing, so this is a broken product principle rather than a checklist feature.

Cost. The main work is in templates/table.html, handlers_table.go, handlers_format.go, handlers_size.go, view models, and their tests. The existing format and size storage is enough, so there is no migration. The JSON-only POST .../format route is close but not form-ready; the form path should share validation and application code with it rather than duplicate formatting rules. This is medium-sized and needs no new spec ruling unless the table UI introduces a new selection model.

What breaks if it is wrong. The two editing surfaces can apply different formatting, an enormous submitted range can evade maxFormatCells, or a form can echo a user-authored number format into an error or log. I would drop it only if the table view's editing claim is deliberately narrowed in PRODUCT.md; under the current principle, leaving it out is not an option.

Build first. Format one cell from its existing edit state, using a real form and the same allowlisted patch logic as handleFormatPost. Range formatting and row/column sizing can follow once one scriptless write round-trips and renders identically in both views.

3. CSV import and export

What it is. A person can upload a comma-separated values (CSV) file into one tab and download a tab as CSV. It carries cell data, not workbook-only features such as colours, comments or formulas with cross-tab references.

Why it is third. CSV is the remaining false edge around the shipped interoperability story: PRODUCT.md now states plainly that no CSV code exists, while spec §13 still places XLSX/CSV before sharing and collaboration. For a small dogfooding team, moving a plain table to or from another tool is more likely than authoring a chart, and it can reuse the scriptless import form and download pattern already proven by XLSX.

Cost. Add an internal/sheets/csv package, extend handlers_import.go and importupload.go, add a CSV export handler and routes in app.go, and update the import and File menu templates. It can write through the existing sealed cell store and needs no migration. This is medium-sized rather than tiny because encoding, line endings, delimiters, cell limits and safe download headers need fixtures. Paul should rule whether an imported leading = becomes a formula or literal text, and whether export writes raw inputs or displayed values; either choice affects round trips and spreadsheet-injection risk.

What breaks if it is wrong. A CSV can open with shifted columns, silently change formulas into values, or turn literal text into executable spreadsheet input. I would drop it if nobody in the current team exchanges CSV files; PRODUCT.md rejects building for hypothetical users.

Build first. Export the current tab as UTF-8 CSV with a documented choice of raw or displayed values. That is a complete, reversible read path and forces the semantic ruling before upload can mutate a sheet.

Shipped but quietly unfinished

Sort and filter do not govern the grid. viewspec.go persists a tab-wide view and templates/table.html tells the user it changes what everybody sees, but handlers_grid.go calls snapshot without loading or applying that view. templates/sheet.html even notes that the grid does not apply it. Two people can therefore open the same tab and see different row orders depending on which shipped view they use. Fixing that matters more than CSV: either make the grid paint the same non-destructive view, including correct edit coordinates and live updates, or change the feature to an explicitly personal table-only view. The latter changes the current shared-view semantics and needs Paul to rule it.

Do not build: charts

Charts are the trap. Spec §13 names them as a subsystem and the first slip candidate, not the natural next checkbox. Here they would add sealed chart titles and labels, stable range binding, a second renderer, accessible non-colour-only descriptions, scriptless presentation, XLSX round-trip rules and likely print/export pressure before the team has shown a need for any of it. A spreadsheet without charts remains coherent; a spreadsheet that drops worksheets, denies scriptless users formatting, or shows two incompatible sorted views does not.