Decision Log: Rich Cell Data Types
Decision Log: Rich Cell Data Types
Section titled “Decision Log: Rich Cell Data Types”Purpose
Section titled “Purpose”Tracks design decisions for Rich Cell Data Types: how reusable rich cells (tokens, composite objects) are packaged for AG Grid so that copy/paste, bulk paste, fill-down, filtering, and export behave consistently. Round 1 records the decisions embedded in the design draft; Round 2 records the questions raised in the PR #99 review.
Decision Table
Section titled “Decision Table”| # | Question | Status | Decision | Round |
|---|---|---|---|---|
| DQ-001 | Mechanism for reusable rich cells | Decided | cellDataType + dataTypeDefinitions registry | R1 |
| DQ-002 | Where the value↔string contract lives | Decided | In the data type (valueFormatter + valueParser) | R1 |
| DQ-003 | How renderer + editor attach to a data type | Decided | Named columnTypes bundle referenced by the data type | R1 |
| DQ-004 | Single-select vs multi-select tokens | Decided | One tokens family; arity via multiple flag | R1 |
| DQ-005 | Composite columns (Address) | Decided | object data type + popup composite editor | R1 |
| DQ-006 | Bulk paste / fill / export wiring | Decided | Data-type defaults; per-grid override only for feedback | R1 |
| DQ-007 | Do image thumbnail + editor use this architecture? | Decided | Yes — same recipe, later slice (see roadmap list) | R2 |
| DQ-008 | Joint editing of units (quantity + unit of measure) | Decided | Composite editor; data type or ColDef factory by storage | R2 |
| DQ-009 | Prioritized list of pre-defined data types | Decided | Added to the design (§ Pre-defined data type roadmap) | R2 |
Round 1: Initial Design Decisions
Section titled “Round 1: Initial Design Decisions”DQ-001: Mechanism for reusable rich cells
Section titled “DQ-001: Mechanism for reusable rich cells”Context: The vendor grid’s Role and Order Method columns are hand-rolled inline
cellRenderer functions. Renderers are cosmetic only — sorting, filtering, clipboard,
fill, and export run against the underlying value — so each hand-rolled column silently
breaks copy/paste, set-filtering, and export. We need one unit of reuse that carries
the functional hooks, not just the visual ones.
| Option | Description | Trade-offs |
|---|---|---|
| A | Per-column cellRenderer/cellEditor (status quo) | No new machinery, but every column must hand-wire valueFormatter/valueParser/keyCreator or silently break; this is the current drift |
| B | Partial-ColDef factory (createTokenColumn(...)) returning a ColDef fragment | Bundles renderer + editor + hooks, but the round-trip wiring is re-applied per factory; nothing forces the next engineer’s createColorColumn onto the same contract |
| C | cellDataType + dataTypeDefinitions registry | Formatter, parser, keyCreator, renderer, and editor registered once and applied by name; every column with cellDataType: 'x' inherits the entire round trip identically |
Recommendation: Option C — the Phase 2 goal is that copy/paste, bulk paste, and
bulk edits behave the same across every rich type; only the data-type registry makes
the value↔string round trip the unit of reuse. A thin factory (createTokenDataType)
is kept as sugar on top.
Decision: Option C, with Option B retained only as sugar that produces data-type definitions rather than loose ColDefs.
Applied to:
- Design § The decision and why, § Architecture
DQ-002: Where the value↔string contract lives
Section titled “DQ-002: Where the value↔string contract lives”Context: Copy, cut, paste, bulk paste, fill-down, and CSV/Excel export are all driven by a string↔value conversion. If that conversion is defined per column (or per grid), rich columns drift apart again.
| Option | Description | Trade-offs |
|---|---|---|
| A | Per-column valueFormatter/valueParser on each ColDef | Maximum flexibility, but N copies of the same contract; inconsistency is the failure mode this project exists to fix |
| B | Grid-level processCellForClipboard/processCellFromClipboard hooks | One place per grid, but export and fill do not run through the clipboard hooks — coverage is partial and grid-specific |
| C | In the data type: valueFormatter (value→string) + valueParser (string→value) | AG Grid consults these for clipboard, fill, and export (useValueFormatterForExport / useValueParserForImport default to true); defined once per type |
Recommendation: Option C — it is the only placement that all consuming features (clipboard, fill, export) resolve automatically.
Decision: Option C.
Applied to:
- Design § Background, § Worked example 1
DQ-003: How renderer + editor attach to a data type
Section titled “DQ-003: How renderer + editor attach to a data type”Context: DataTypeDefinition carries the value hooks but the visual pair
(cellRenderer, cellEditor) and keyCreator attach through column configuration.
The binding must be by name so consumers write only cellDataType: 'roles'.
| Option | Description | Trade-offs |
|---|---|---|
| A | Repeat cellRenderer/cellEditor on every column def | Simple but reintroduces per-column drift for the visual half |
| B | A named columnTypes bundle that the data type references via its columnTypes field | Single registration; the grid resolves renderer, editor, and keyCreator from the type name; matches AG Grid’s own extension mechanism |
Recommendation: Option B — it completes the “one name, whole behavior” contract.
Decision: Option B.
Applied to:
- Design § Worked example 1 (registration)
DQ-004: Single-select vs multi-select tokens
Section titled “DQ-004: Single-select vs multi-select tokens”Context: Role is string[] (multi), Order Method is string (single). They could
be two unrelated types or one family.
| Option | Description | Trade-offs |
|---|---|---|
| A | Two independent data types with separate renderers and parsers | Duplicated pill rendering and parsing; the two drift visually and behaviorally |
| B | One tokens family: multiple: true ⇒ string[] + multi-select editor; multiple: false ⇒ string + typeahead editor; same TokenList renderer | One factory called twice; only editor selection and parser arity differ |
Recommendation: Option B — the consistency payoff is the point of the design.
Decision: Option B.
Applied to:
- Design § Worked examples 1 and 2
DQ-005: Composite columns (Address)
Section titled “DQ-005: Composite columns (Address)”Context: Structured data such as an address must render as one line, edit as several inputs, and still round-trip through copy/paste/fill/export. The same shape recurs for other composites — e.g. joint editing of a quantity with its unit of measure (see DQ-008).
| Option | Description | Trade-offs |
|---|---|---|
| A | Split into sibling scalar columns (street, city, …) | Native behavior per column, but no joint editing, wide grids, and cross-field validation is impossible |
| B | Hand-rolled popup editor per grid | Works once; re-introduces the per-grid drift for every composite |
| C | An object data type: single-line valueFormatter, structured valueParser, popup composite editor (cellEditorPopup: true) | Same architecture as tokens; all round-trip features free. Requires the row to store the composite as one field |
Recommendation: Option C when the row stores one composite field. When the data
lives as several sibling row fields, a DataTypeDefinition cannot express the
gather/scatter (it has no valueGetter/valueSetter) — that variant is a ColDef
factory owning valueGetter/valueSetter, as implemented by combined-column.tsx
in ux-prototype. The value contract (formatter/parser/keyCreator/renderer/editor) is
shared between the two.
Decision: Option C, with the sibling-fields caveat recorded in the design’s “One field, not many” callout.
Applied to:
- Design § Bonus — Address
DQ-006: Bulk paste / fill / export wiring
Section titled “DQ-006: Bulk paste / fill / export wiring”Context: Should grids customize clipboard processing, or should the data type’s round trip be the default with validation feedback layered on top?
| Option | Description | Trade-offs |
|---|---|---|
| A | Per-grid processCell*FromClipboard everywhere | Full control, but every grid re-implements the round trip and they drift |
| B | Rely on the data type’s formatter/parser; add a generic grid-level processCellFromClipboard only where the Phase 2 invalid-input feedback (red flash + alert) is wanted | Default behavior is automatic and consistent; the override is one generic function consulting the column’s data type, not per-column code |
Recommendation: Option B.
Decision: Option B.
Applied to:
- Design § DataGrid integration, § Validation feedback on paste
Round 2: PR #99 Review Questions
Section titled “Round 2: PR #99 Review Questions”DQ-007: Do the image thumbnail and editor use this architecture?
Section titled “DQ-007: Do the image thumbnail and editor use this architecture?”Context: Raised in review — the grid has an existing hand-rolled image column
(grid-image.tsx) with a thumbnail renderer and upload/preview editor, carrying the
same copy/filter/export gap as the hand-rolled token columns.
| Option | Description | Trade-offs |
|---|---|---|
| A | Keep grid-image.tsx as a one-off | No migration cost now; the gap and the drift remain |
| B | Migrate image to an image cell data type (thumbnail renderer + upload editor; value↔string round trip on the image URL/asset id) in a later slice | Same recipe as tokens/address; consistent behavior; deferred so the first slice stays small |
Recommendation: Option B — in scope for the architecture, out of scope for the first slice; sequenced in the pre-defined data type roadmap.
Decision: Option B.
Applied to:
- Design § Overview, § Pre-defined data type roadmap, § Out of Scope
DQ-008: Joint editing of units (quantity + unit of measure)
Section titled “DQ-008: Joint editing of units (quantity + unit of measure)”Context: Raised in review — will this help with joint editing of units, similar to the address structured editor?
| Option | Description | Trade-offs |
|---|---|---|
| A | Composite object data type (like Address) when the row stores { amount, unit } as one field | Full round trip for free; joint popup editor with cross-field validation (unit constrains precision, etc.) |
| B | ColDef factory with valueGetter/valueSetter (the combined-column.tsx mechanism) when quantity and unit live as sibling row fields | Same editor and value contract; the gather/scatter must live in the ColDef because data types have no getter/setter |
Recommendation: Yes on joint editing in both cases; A vs B is dictated by how the row stores the data, not by the editor. The composite editor and the formatter/parser/keyCreator half are shared.
Decision: Both, selected by storage shape, per the design’s “One field, not many” callout — now explicitly naming units as an example.
Applied to:
- Design § Bonus — Address (“One field, not many” callout)
DQ-009: Prioritized list of pre-defined data types
Section titled “DQ-009: Prioritized list of pre-defined data types”Context: Raised in review — the ux-prototype library should publish a prioritized, aspirational list of pre-defined data types that it will ship as they are needed and mature (e.g. Text, Number (Decimal), Boolean, …).
| Option | Description | Trade-offs |
|---|---|---|
| A | Leave the type inventory implicit in each design’s scope section | No single place to see what exists vs. what is planned |
| B | Add a prioritized roadmap section to the design listing built-in types to adopt and custom types to build, in shipping order | One authoritative list; each future slice picks the next entry |
Recommendation: Option B.
Decision: Option B — see the design’s new § Pre-defined data type roadmap.
Applied to:
- Design § Pre-defined data type roadmap
Copyright: (c) Arda Systems 2025-2026, All rights reserved
Copyright: © Arda Systems 2025-2026, All rights reserved