List View Component Design
Context
Section titled “Context”Guidelines
Section titled “Guidelines”-
The target library for this project is the
Canarymaturity level. This means that the target directories by category are:- Components:
src/components/canary - Types:
src/types/canary - Styles:
src/styles/canary - Visual Elements:
src/visual-elements/canary - Full Sample Stories (ported from
src/dev-witness):src/canary-refactor
- Components:
-
When extracting components from the
extraslibrary:- Port any dependencies they have from other code in
src/components/extras,src/types/extras,src/styles/extrasorsrc/visual-elements/extrasto their correspondingcanarydirectories.
- Port any dependencies they have from other code in
General Workflow
Section titled “General Workflow”- Clone the stories under the directory
ux-prototype/src/dev-witness/reference/itemsto a directory called:ux-prototype/src/canary-refactor/reference/items - lint, build and test
ux-prototypeto ensure that the clone builds and renders. - Update the vrt tests to compare the cloned stories with the original story. They should pass because there are no changes yet.
- Port all target components, including all unit tests.
- Run the lint, build and test commands (no vrt testing needed) to ensure that the port builds and tests successfully.
- Update the cloned stories to use the new canary components. Ensure that the
vendoredcomponents are not used when a canary component exists. - Run the vrt tests again. They should still pass as the port should be visually unchanged.
- If vrt tests don’t pass, report to user for further instructions.
ListView Component Class Diagram
Section titled “ListView Component Class Diagram”This diagram shows the proposed Canary component hierarchy for the List View project. It covers all four in-scope tiers (1, 2, 3a, 3b) and shows Tier 4 (domain grids) for context. Decisions from the Landscape Analysis are reflected in the structure.
- Tier 1 — Two cell variants per type: Display (read-only renderer) and Editor (AG Grid native cell editor). CellInteractive deferred to Entity Viewer project. Priority types: text, number, boolean, date, enum, memo (new), color (new).
- Tier 2 — DataGrid
molecule with the three-part config pattern (Static/Init/Runtime), minimal ref (getGridApi, exportDataAsCsv), internal SortMenuHeader sub-component, and AG Grid native row selection (headerCheckbox, selectionColumnDef) - Tier 3a — createEntityDataGrid
() factory wrapping Tier 2, with entity-level config, model/view props, and the 3a additions (multi-sort, filtering, cell editing lifecycle, getRowClass) - Tier 3b — createEntityDataGridShim
() wrapping 3a, adding vendored compatibility (row actions, double-click, hasActiveSearch, initialState, extended ref with selectAll/deselectAll/etc.) - Composable Hooks — useDirtyTracking
() shown as optional composition with Tier 3a (Q9 decision) - Tier 4 — Domain grids shown greyed out (out of scope)
- Cross-tier — DataGrid renders cell Display/Editor atoms via columnDefs
Name Changes w.r.t. Analysis
Section titled “Name Changes w.r.t. Analysis”ArdaDataGrid->DataGrid(dropArdaprefix)createArdaEntityDataGrid->createEntityDataGrid(dropArdaprefix)createFullEntityDataGrid->createEntityDataGridShim(new name for Tier 3b vendored compatibility layer)
External Dependencies:
Section titled “External Dependencies:”Class Diagram
Section titled “Class Diagram”Component Dependencies
Section titled “Component Dependencies”The table below lists every component, type, utility, hook, and style that must be ported to canary, along with its dependencies. Items already in canary (cn, getBrowserTimezone, getTimezoneAbbreviation) are marked with a dagger (*).
| Component | Source Location | Dependencies |
|---|---|---|
| Shared — Types & Utilities | ||
PaginationData | types/extras/model/general/pagination.ts | None |
formatters | components/extras/atoms/shared/formatters.ts | None (pure functions) |
cn* | types/canary/utils.ts | clsx, tailwind-merge (npm) |
getBrowserTimezone* | types/canary/date-time.ts | None |
getTimezoneAbbreviation* | types/canary/date-time.ts | None |
| Shared — Hooks | ||
useColumnPersistence | components/extras/molecules/data-grid/use-column-persistence.ts | ag-grid-community (types only) |
useDirtyTracking<T> | New | None (pure React state) |
| Shared — Styles | ||
ag-theme-arda.css | styles/ag-theme-arda.css | AG Grid CSS variables |
| Tier 1 — Cell Atoms (per type: text, number, boolean, date, enum) | ||
{Type}CellDisplay | components/extras/atoms/grid/{type}/ | formatters (type-specific formatter); date also uses getBrowserTimezone* |
{Type}CellEditor | components/extras/atoms/grid/{type}/ | cn*; date also uses toDateInputValue (formatter), getBrowserTimezone*, getTimezoneAbbreviation* |
| Tier 1 — New Cell Types (from completeness assessment) | ||
MemoCellDisplay | New | cn*, @radix-ui/react-tooltip (already installed). Truncates text with ellipsis; shows full text in Radix Tooltip overlay after configurable delay. |
MemoCellEditor | New | cn*. Multi-line textarea for AG Grid cell editing. Based on vendored NoteModal textarea pattern (min-height 100px, resizable). |
MemoButtonCell | New (based on vendored NotesCell) | cn*, lucide-react, createPortal. Icon button + modal overlay for viewing/editing long text. Accepts onSave?(value: string) => void callback. Framework-agnostic. |
createMemoButtonCellEditor() | New | MemoButtonCell. Factory wrapping MemoButtonCell as AG Grid cell editor with getValue() ref handle. Follows create{Type}CellEditor pattern. |
ColorCellDisplay | New (based on vendored color renderer) | cn*. Renders color swatch (4x4px rounded square, backgroundColor: hex) + label. Based on vendored columnPresets.tsx pattern. |
ColorCellEditor | New (based on vendored ColorCellEditor) | cn*, shadcn/Radix Select or Popover. React forwardRef replacing vendored raw-DOM class-based editor. Configurable colors: ColorOption[] prop. Default: vendored 10-color map. |
| Tier 1 — Special | ||
ActionCellRenderer<T> | New (Tier 3b) | cn*, RowAction<T> type, lucide-react (icons) |
| Tier 2 — Molecule | ||
SortMenuHeader | Internal to vendored/arda-frontend/components/table/ArdaGrid.tsx (lines 153-257) | ag-grid-community (IHeaderParams), createPortal (React DOM). CSS: .arda-sort-* classes from ag-theme-arda.css. |
DataGrid<T> | components/extras/molecules/data-grid/data-grid.tsx | ag-grid-react, ag-grid-community, ag-theme-arda.css, PaginationData, useColumnPersistence, SortMenuHeader. Native rowSelection config for header checkbox. |
| Tier 3a — Organism Base | ||
createEntityDataGrid<T>() | components/extras/organisms/shared/entity-data-grid/ (export renamed from createArdaEntityDataGrid) | DataGrid<T>, PaginationData, ag-grid-community (types: ColDef) |
| Tier 3b — Organism Full | ||
createEntityDataGridShim<T>() | New (wraps Tier 3a) | createEntityDataGrid<T>(), ActionCellRenderer<T>, RowAction<T>, ag-grid-community (types: GridState) |
Porting Guidelines
Section titled “Porting Guidelines”| Component | Recommended Action | Decision |
|---|---|---|
| Shared — Types & Utilities | ||
PaginationData | Copy from types/extras/model/general/pagination.ts to types/canary/pagination.ts. Pure interface, no changes needed. | |
formatters | Copy from extras/atoms/shared/formatters.ts to canary/atoms/shared/formatters.ts. Pure functions, no changes needed. | Correct |
cn* | Already in canary (types/canary/utils.ts). No action. | Correct |
getBrowserTimezone* | Already in canary (types/canary/date-time.ts). No action. | Correct |
getTimezoneAbbreviation* | Already in canary (types/canary/date-time.ts). No action. | Correct |
| Shared — Hooks | ||
useColumnPersistence | Port from extras/molecules/data-grid/use-column-persistence.ts to canary/molecules/data-grid/use-column-persistence.ts. Update AG Grid type imports (remain ag-grid-community, no change needed). | Correct |
useDirtyTracking<T> | Create new in canary/organisms/shared/entity-data-grid/use-dirty-tracking.ts. Extract dirty tracking logic (clone row data, track per-cell edits, save/discard drafts) from existing create-entity-data-grid.tsx into a standalone composable hook. | Correct |
| Shared — Styles | ||
ag-theme-arda.css | Copy from styles/ag-theme-arda.css to styles/canary/ag-theme-arda.css. Verify AG Grid CSS variable references resolve correctly. | Correct |
| Tier 1 — Cell Atoms (per type: text, number, boolean, date, enum) | ||
{Type}CellDisplay | Copy from extras/atoms/grid/{type}/ to canary/atoms/grid/{type}/. Update imports: @/components/extras/atoms/shared/formatters to @/components/canary/atoms/shared/formatters. Date type also update getBrowserTimezone import (already canary, no change). | Correct |
{Type}CellEditor | Copy from extras/atoms/grid/{type}/ to canary/atoms/grid/{type}/. Update imports: cn (already canary, no change). Date type also update formatter and timezone imports. | Correct |
| Tier 1 — New Cell Types (from completeness assessment) | ||
MemoCellDisplay | Create new in canary/atoms/grid/memo/. Truncates text with ellipsis. On hover, shows full text in Radix Tooltip overlay after configurable delay (per Q12 decision). | |
MemoCellEditor | Create new in canary/atoms/grid/memo/. Multi-line textarea for AG Grid cell editing. Draw from vendored NoteModal textarea pattern: min-height 100px, resizable, placeholder “Add a note…”. Implements getValue() ref handle. | |
MemoButtonCell | Create new in canary/atoms/grid/memo/. Based on vendored NotesCell (~90 lines in columnPresets.tsx): icon button (chat bubble or dash) that opens a modal overlay for viewing/editing. Modal based on vendored NoteModal pattern (500px centered, textarea, Done/Close). Accepts onSave?(value: string) => void callback — framework-agnostic, no AG Grid coupling. | |
createMemoButtonCellEditor() | Create new factory in canary/atoms/grid/memo/. Wraps MemoButtonCell as an AG Grid-compatible cell editor with getValue() ref handle and stopEditing integration. Follows existing create{Type}CellEditor(config) pattern. | |
ColorCellDisplay | Create new in canary/atoms/grid/color/. Based on vendored color renderer in columnPresets.tsx: 4x4px rounded swatch (backgroundColor: hex) + label text. Vendored 10-color hex map as default. Fallback to gray for unmapped values. | |
ColorCellEditor | Create new in canary/atoms/grid/color/. React forwardRef replacing vendored raw-DOM class-based ColorCellEditor. Uses shadcn/Radix Select or Popover for dropdown. Configurable colors: ColorOption[] prop with vendored 10-color map as default. Implements getValue() ref handle. | |
| Tier 1 — Special | ||
ActionCellRenderer<T> | Create new in canary/atoms/grid/action/action-cell-renderer.tsx. Implements pinned-right column with dropdown menu. Depends on RowAction<T> type (defined alongside), cn*, lucide-react. | Correct |
| Tier 2 — Molecule | ||
SortMenuHeader | Port from vendored/arda-frontend/components/table/ArdaGrid.tsx (lines 153-257) to canary/molecules/data-grid/sort-menu-header.tsx. Internal sub-component of DataGrid<T>, not exported independently. | |
DataGrid<T> | Copy from extras/molecules/data-grid/data-grid.tsx to canary/molecules/data-grid/data-grid.tsx. Update imports: PaginationData from types/canary/pagination, useColumnPersistence from canary path, ag-theme-arda.css from styles/canary/. Add SortMenuHeader as internal defaultColDef.headerComponent. Configure AG Grid native rowSelection with headerCheckbox: true and selectionColumnDef (replaces vendored SelectAllHeaderComponent). Keep ag-grid-react and ag-grid-community imports unchanged. | |
| Tier 3a — Organism Base | ||
createEntityDataGrid<T>() | Copy from extras/organisms/shared/entity-data-grid/create-entity-data-grid.tsx. Rename from createArdaEntityDataGrid to createEntityDataGrid (drop Arda prefix per canary naming — the @arda-cards/design-system package scope makes the prefix redundant). Update imports: DataGrid<T> from canary Tier 2, PaginationData from canary types. Extract dirty tracking into useDirtyTracking hook (optional composition). Add Tier 3a features: enableMultiSort/onSortChanged, enableFiltering/onFilterChanged, onCellEditingStarted/onCellEditingStopped/onCellFocused, getRowClass. | |
| Tier 3b — Organism Full | ||
createEntityDataGridShim<T>() | Create new wrapping createEntityDataGrid<T>(). Name: createEntityDataGridShim (vendored ArdaGrid compatibility layer). Add Tier 3b features: enableRowActions/rowActions (via ActionCellRenderer), onRowDoubleClicked, hasActiveSearch, initialState: GridState, extended ref (refreshData, getSelectedRows, selectAll, deselectAll). |
Porting Strategy
Section titled “Porting Strategy”The porting strategy needs to enable incremental testing of the ported components. The waves below correspond to Step 4 of the General Workflow. Steps 1-3 (clone stories, VRT setup) happen before Wave 0. Steps 5-8 (lint/build/test, story swapping, VRT verification) happen after Wave 3b. Based on this the waves for porting should be:
Wave 0 — Shared Foundation
Section titled “Wave 0 — Shared Foundation”Port types, utilities, and styles that have no component dependencies. These are leaf nodes in the dependency graph.
| Item | Source | Target | Notes |
|---|---|---|---|
PaginationData | types/extras/model/general/pagination.ts | types/canary/pagination.ts | Pure interface, no dependencies |
formatters | components/extras/atoms/shared/formatters.ts | components/canary/atoms/shared/formatters.ts | Pure functions, no dependencies |
ag-theme-arda.css | styles/ag-theme-arda.css | styles/canary/ag-theme-arda.css | Copy; verify AG Grid CSS variable references |
Verification:
tsc --noEmitpasses. No visual output yet.- Add unit tests for each component if applicable, run the unit tests and verify that they pass.
Wave 1 — Tier 1 Cell Atoms (5 priority types)
Section titled “Wave 1 — Tier 1 Cell Atoms (5 priority types)”Port 7 cell type directories: 5 ported from extras (text, number, boolean, date, enum) and 2 new (memo, color). Each type has 2 components (Display, Editor) plus an index barrel. CellInteractive is deferred to the Entity Viewer project (see Cell Editing Paths Analysis). For ported types, copy existing tests and stories, adapting imports and Storybook title paths to canary conventions. For new types (memo, color), create tests and stories from scratch.
| Item | Source | Target | Dependencies (from Wave 0) |
|---|---|---|---|
TextCellDisplay | extras/atoms/grid/text/ | canary/atoms/grid/text/ | formatters |
TextCellEditor | same | same | cn* |
NumberCellDisplay | extras/atoms/grid/number/ | canary/atoms/grid/number/ | formatters |
NumberCellEditor | same | same | cn* |
BooleanCellDisplay | extras/atoms/grid/boolean/ | canary/atoms/grid/boolean/ | formatters, lucide-react |
BooleanCellEditor | same | same | cn* |
DateCellDisplay | extras/atoms/grid/date/ | canary/atoms/grid/date/ | formatters, getBrowserTimezone* |
DateCellEditor | same | same | cn*, formatters, getBrowserTimezone*, getTimezoneAbbreviation* |
EnumCellDisplay | extras/atoms/grid/enum/ | canary/atoms/grid/enum/ | None |
EnumCellEditor | same | same | cn* |
MemoCellDisplay | New | canary/atoms/grid/memo/ | cn*, @radix-ui/react-tooltip (already installed) |
MemoCellEditor | New | same | cn* |
MemoButtonCell | New (from vendored NotesCell) | same | cn*, lucide-react, createPortal |
createMemoButtonCellEditor() | New | same | MemoButtonCell |
ColorCellDisplay | New (from vendored renderer) | canary/atoms/grid/color/ | cn* |
ColorCellEditor | New (from vendored editor) | same | cn*, shadcn/Radix primitives |
Verification: Unit tests for each cell type. Storybook stories render in Components/Canary/Atoms/Grid/{Type}.
Wave 2 — Tier 2 Data Grid Molecule
Section titled “Wave 2 — Tier 2 Data Grid Molecule”Port the core AG Grid wrapper and its column persistence hook. Copy existing tests and stories, adapting imports and Storybook title paths. Improve if appropriate.
| Item | Source | Target | Dependencies |
|---|---|---|---|
useColumnPersistence | extras/molecules/data-grid/use-column-persistence.ts | canary/molecules/data-grid/use-column-persistence.ts | ag-grid-community (types only) |
SortMenuHeader | vendored/arda-frontend/components/table/ArdaGrid.tsx | canary/molecules/data-grid/sort-menu-header.tsx | ag-grid-community (IHeaderParams), createPortal. CSS from ag-theme-arda.css (Wave 0). |
DataGrid<T> | extras/molecules/data-grid/data-grid.tsx | canary/molecules/data-grid/data-grid.tsx | ag-grid-react, ag-grid-community, ag-theme-arda.css (Wave 0), PaginationData (Wave 0), useColumnPersistence, SortMenuHeader. Native rowSelection config. |
Persistence strategy: When the consuming application manages column visibility via its own state store (e.g., Redux), omit the persistenceKey prop and drive visibility entirely through EntityGridViewProps.columnVisibility. The useColumnPersistence hook activates only when persistenceKey is provided, so the two mechanisms cannot conflict. See Redux State Management Analysis for details.
Verification: Unit tests. Storybook stories render in Components/Canary/Molecules/DataGrid with loading, empty, error, pagination, selection, and cell editing states. ALL Cell atoms from Wave 1 should be used in column definitions to show rendering and editing in place in the grid. Story tests should be added if necessary.
Wave 3a — Tier 3a Entity Data Grid Base
Section titled “Wave 3a — Tier 3a Entity Data Grid Base”Port the factory and the composable dirty tracking hook. Copy existing tests and stories, adapting imports and Storybook title paths. Improve if appropriate.
| Item | Source | Target | Dependencies |
|---|---|---|---|
useDirtyTracking<T> | New (extracted from extras entity-data-grid) | canary/organisms/shared/entity-data-grid/use-dirty-tracking.ts | None (pure React state) |
createEntityDataGrid<T>() | extras/organisms/shared/entity-data-grid/ | canary/organisms/shared/entity-data-grid/ | DataGrid<T> (Wave 2), PaginationData (Wave 0), ag-grid-community (types). Add 3a features: multi-sort, filtering, cell editing lifecycle, getRowClass. |
Verification: Unit tests. Storybook stories render in Components/Canary/Organisms/Shared/Entity Data Grid. Dirty tracking testable in isolation via hook tests.
Wave 3b — Tier 3b Entity Data Grid Shim
Section titled “Wave 3b — Tier 3b Entity Data Grid Shim”Port the vendored-compatible wrapper and the action cell renderer.
| Item | Source | Target | Dependencies |
|---|---|---|---|
ActionCellRenderer<T> | New | canary/atoms/grid/action/action-cell-renderer.tsx | cn*, RowAction<T> type, lucide-react |
createEntityDataGridShim<T>() | New (wraps Tier 3a) | canary/organisms/shared/entity-data-grid-shim/ | createEntityDataGrid<T>() (Wave 3a), ActionCellRenderer, ag-grid-community (types: GridState). Adds: row actions, double-click, hasActiveSearch, initialState, extended ref. |
Verification: Unit tests. Storybook stories demonstrate vendored ArdaGrid feature parity. Clone dev-witness/reference/items stories to canary-refactor/reference/items and swap the grid component. VRT comparison should pass.
Wave Summary
Section titled “Wave Summary”Follow Up Projects (Out of Scope)
Section titled “Follow Up Projects (Out of Scope)”The following items were identified during the Completeness Assessment as necessary for full migration of vendored components but outside the scope of this project. They are recorded here for future planning.
| # | Item | Description | Source |
|---|---|---|---|
| F1 | Typeahead Cell Editors | 9 domain-specific AG Grid cell editors (SupplierCellEditor, UnitCellEditor, TypeCellEditor, SubTypeCellEditor, UseCaseCellEditor, FacilityCellEditor, DepartmentCellEditor, LocationCellEditor, SublocationCellEditor). Each wraps a typeahead component with debounced API-backed search. Requires a generic TypeaheadCellEditor pattern in the component library, plus domain-specific API bindings. | Completeness #2 |
| F2 | QuickActionsCell | Domain-specific cell renderer with order-queue, print, and preview buttons per row. Requires useItemCards context, kanban API integration, and order queue state. | Completeness #4 |
| F3 | Draft Lifecycle Management | Items-specific editing orchestration: draft creation per row, batched API saves, auto-publish on row leave, row-level saving/error UI states. The generic useDirtyTracking<T>() hook covers dirty state; the domain-specific API integration and row-level UI need separate work. | Completeness #8 |
| F4 | Page Chrome Components | AppSidebar, AppHeader, SidebarProvider, tab navigation, search bar, column visibility dropdown. Application-shell components required for full page rendering but not grid-specific. | Completeness #9 |
| F5 | Remaining Cell Types | 5 additional cell types deferred from the priority subset: url, image, time, datetime, custom. To be added based on consumer demand. | Analysis Q8 |
| F6 | CellInteractive + Entity Viewer | {Type}CellInteractive variants and GridCellProps<V> base type. Deferred until the Entity Viewer project is ported to canary. | Cell Editing Paths Analysis |
References
Section titled “References”Planning Preparation Open Questions
Section titled “Planning Preparation Open Questions”The following questions must be resolved before the implementation plan can be finalized.
| # | Question | Context | Decision |
|---|---|---|---|
| 1 | Existing canary-refactor state — There is already a canary-refactor/reference/items/item-detail.stories.tsx with forked components (ItemDetailPage, ItemDetailsPanel, ItemsPage). Should the implementation plan treat this as existing work to preserve and build on, or start fresh? | The items-grid.stories.tsx from dev-witness has no canary-refactor counterpart yet. | Remove existing canary-refactor/reference/items code and start fresh |
| 2 | Story cloning scope — The General Workflow step 1 says clone dev-witness/reference/items. That directory has two stories: item-detail.stories.tsx and items-grid.stories.tsx. The item-detail story is about a detail panel (not a grid). Should the plan clone both, or only items-grid.stories.tsx since this project is about the List View component? | The item-detail story uses the vendored ArdaGrid indirectly (the items page wraps it), so it would exercise the grid too. | Both. |
| 3 | Barrel exports — Should the ported canary components be added to src/canary.ts (the canary barrel) as they are completed per wave, or all at once at the end? The current canary.ts only has placeholder exports plus the ArdaDetailField atom. | Affects whether waves are independently shippable. | At the end. Placeholder exports and the placeholder components themselves should be removed |
| 4 | ESLint boundary rules — The current ESLint config blocks stable code from importing canary. Are there rules blocking canary from importing extras? If so, the plan needs to ensure zero cross-references between canary and extras components (only canary-to-canary and canary-to-npm). | Determines whether a “copy + update imports” approach works or if we need to verify ESLint passes per wave. | Yes, neither canary nor stable can import from extras. Update the rules if necessary. |
| 5 | Agent team execution — Is this plan intended for a single agent working sequentially through the waves, or for an agent team (via launch-team) with parallel workers per wave? | Affects task granularity and whether the plan should include a worktree strategy section. | Use the project-decomposition skill to decide. Record your rationale in the planning document. |
Open Questions Round 2
Section titled “Open Questions Round 2”The following ambiguities were identified during a consistency review of the design document.
| # | Question | Context | Decision |
|---|---|---|---|
| 6 | Workflow vs Waves relationship — The General Workflow (steps 1-8) describes an end-to-end process: clone stories, VRT setup, port components, swap stories, VRT verify. The Porting Strategy defines Waves 0-3b for the porting step. It is not explicit that Waves 0-3b are substeps of Workflow step 4, or how Workflow steps 1-3 (pre-porting setup) and 5-8 (post-porting integration) map to the wave structure. Should the implementation plan treat the Workflow as the outer structure with waves nested inside step 4, or merge them into a single flat sequence? | An agent executing this needs to know when to do VRT setup (step 3) and story swapping (step 6) relative to the waves. | All waves are part of Step 4 |
| 7 | GridCellProps<V> missing onComplete and onCancel — The class diagram shows GridCellProps<V> with value, onChange, mode, errors, editable. But every extras Interactive cell uses onComplete (commit edit on blur/Enter) and onCancel (revert on Escape) from AtomProps<V>. If GridCellProps<V> omits these, Interactive cells lose their edit commit/cancel mechanism. Should onComplete and onCancel be added to GridCellProps<V>? | These are grid-relevant fields used in every Interactive cell’s inline editor. Without them, the edit lifecycle is broken. | Moot — GridCellProps<V> and CellInteractive are both deferred per Q8 decision. |
| 8 | False dependency: Interactive -> Editor — The class diagram and Component Dependencies table show {Type}CellInteractive depending on {Type}CellEditor. In the actual source code, Interactive does NOT import Editor — it has its own internal inline editor function ({Type}CellInlineEditor). CellEditor is a separate component used by AG Grid’s native double-click-to-edit mechanism. These are two independent editing paths. Should the diagram and dependency table be corrected to remove the Interactive -> Editor dependency? | Affects wave dependency ordering and the agent’s understanding of the component relationship. The current depiction would cause an agent to believe Editor must be ported before Interactive, which is not true. | CellInteractive has no consumer in this project — defer to Entity Viewer project. Remove from scope, diagram, and dependency table. See Cell Editing Paths Analysis. |
| 9 | PaginationData path flattening — Source is types/extras/model/general/pagination.ts (nested under model/general/). Target is types/canary/pagination.ts (flat). The nesting is dropped without explanation. Is the flat target path intentional? | An agent replicating the extras structure would create types/canary/model/general/pagination.ts unless told otherwise. | Flatten the directory structure |
| 10 | Test and story porting — The design says “Port all target components, including all unit tests” (Workflow step 4) and Wave verifications mention “Unit tests” and “Storybook stories”. But neither the Porting Guidelines nor Wave tables mention the existing {type}.test.tsx and {type}.stories.tsx files. Should the plan: (a) copy existing tests and stories, updating imports and Storybook title paths, or (b) write new tests and stories from scratch? | Each extras cell type has a .test.tsx and .stories.tsx file. Copying and adapting is faster. Writing from scratch ensures canary conventions are followed. | Copy, adapt and improve if appropriate |
| 11 | Q7 formal resolution — The analysis Decision Summary shows Q7 (AtomProps<V> dependency for cell atoms) with no decision recorded. But the design uses GridCellProps<V> (the Q7 recommendation) and marks it “Correct” in Porting Guidelines. Should Q7 be formally resolved in the analysis document before the implementation plan is created? | Without formal resolution, the implementation plan references an unresolved decision. | Done. Q7 resolved as “Deferred” in analysis Decision Summary. |
Open Questions Round 3
Section titled “Open Questions Round 3”The following questions arise from the scope additions based on the Completeness Assessment decisions.
| # | Question | Context | Decision |
|---|---|---|---|
| 12 | Memo cell hover overlay implementation — The MemoCellDisplay should show full text in a hover overlay after a configurable delay. Should this use: (a) a Radix UI Tooltip/HoverCard primitive (consistent with shadcn/ui patterns), (b) a custom portal-based overlay (like SortMenuHeader), or (c) AG Grid’s built-in tooltipValueGetter + tooltipComponent? | AG Grid has native tooltip support that avoids rendering custom React components for hover. But its styling is limited. Radix gives full control but adds a dependency. | Option (a) |
| 13 | Color palette configuration — The ColorCellEditor needs a predefined color palette. Should the palette be: (a) hardcoded in the component (the vendored implementation has 10 colors: RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, PINK, GRAY, BLACK, WHITE), (b) configurable via a StaticConfig prop (colors: ColorOption[]), or (c) both (default palette + override)? | The vendored implementation hardcodes 10 colors with hex values and labels. A configurable palette is more reusable but adds API surface. | Configurable. The Hosting Story should provide the colors to display. The default should be a continuos palette. O.K. to source it from ShadCN or Radix if available |
| 14 | Native row selection shift-click validation — Decision #3 replaces SelectAllHeaderComponent with AG Grid native rowSelection config. The vendored component includes custom shift-click range selection logic (~40 lines). Does AG Grid’s native enableClickSelection support shift-click range selection out of the box, or is this a gap that needs a follow-up? | If AG Grid doesn’t support shift-click natively, the canary grid would have a behavioral regression. This should be validated before implementation, not discovered during VRT. | Resolved — no gap. AG Grid Community natively supports shift-click range selection on checkboxes in multiRow mode. No Enterprise license needed. See Appendix A. |
| 15 | Class diagram update — The class diagram still shows the pre-completeness-assessment state (no Memo, Color, SortMenuHeader). Should the diagram be updated now, or deferred to the implementation plan phase? | Updating now keeps the design document self-consistent. Deferring avoids rework if more changes emerge. | Update now. |
Canary-Refactor Sufficiency Assessment
Section titled “Canary-Refactor Sufficiency Assessment”The dev-witness stories (items-grid.stories.tsx and item-detail.stories.tsx) render the full vendored ItemsPage production page. This page is a large component (~1200 lines) that composes:
- Grid layer:
ItemTableAGGridwrappingArdaGridwith items-specific editing, draft management, and 30 column definitions - Page chrome: Sidebar, header, tabs, search bar, column visibility dropdown, action buttons
- Panels:
ItemDetailsPanel(read-only detail view),ItemFormPanel(add/edit form) - Modals: Cards preview, import, delete confirmation
- Context: Auth, order queue, item cards, navigation blocking
The canary-refactor stories (per Workflow step 6) must swap vendored grid components for canary equivalents. The following table lists components/features required by the stories that are not covered by the canary porting scope (Waves 0-3b).
Insufficiencies
Section titled “Insufficiencies”| # | Component / Feature | Used By | Why It’s Needed | Status in Canary Scope |
|---|---|---|---|---|
| 1 | SortMenuHeader — Custom AG Grid header component with sort-direction indicator and portal dropdown menu | ArdaGrid (Tier 2 internal) | Every sortable column uses this header. Without it, columns fall back to AG Grid’s default header (different visual appearance, VRT will fail). | Not listed as a ported component. It’s an internal sub-component of the vendored ArdaGrid. Must be ported as part of the Tier 2 DataGrid<T> molecule or extracted as a separate atom. |
| 2 | 9 Typeahead Cell Editors — SupplierCellEditor, UnitCellEditor, TypeCellEditor, SubTypeCellEditor, UseCaseCellEditor, FacilityCellEditor, DepartmentCellEditor, LocationCellEditor, SublocationCellEditor | ItemTableAGGrid | Required for in-table cell editing. All use the vendored *Typeahead components with API-backed search. | Not in scope. These are domain-specific (Tier 4) editors. The canary Tier 1 cell editors (text, number, boolean, date, enum) don’t cover typeahead-based editors. |
| 3 | SelectAllHeaderComponent — Custom header checkbox with tri-state (all/some/none) and shift-click range selection | itemsColumnDefs (select column) | Required for the row selection checkbox column. Without it, selection UX differs from vendored behavior. | Not listed. It’s a custom cell renderer defined in columnPresets.tsx. Domain-specific (Tier 4). |
| 4 | QuickActionsCell — Cell renderer with order-queue, print, and preview buttons | itemsColumnDefs (actions column) | Requires useItemCards context, kanban API, order queue integration. Renders action buttons per row. | Not in scope. Domain-specific renderer requiring production API context. |
| 5 | CardCountCell — Lazy-loads kanban card count per item | itemsColumnDefs (card count column) | Requires useItemCards context and lazy API fetch. | Not in scope. Domain-specific. |
| 6 | NotesCell / CardNotesCell — Icon button opening a modal for editing notes | itemsColumnDefs (notes columns) | Requires NoteModal component and save-to-API callbacks. | Not in scope. Domain-specific. |
| 7 | itemsColumnDefs and itemsDefaultColDef — 30 column definitions with custom renderers, formatters, editors | ItemTableAGGrid | The column configuration that wires all cell renderers and editors to the grid. Without it, the grid has no columns. | Not in scope (Decision Q3: column presets located with domain stories, not in the library). Must be provided by the canary-refactor story layer. |
| 8 | Draft lifecycle management — createDraftItem, updateItem API calls, dirty set tracking, batched saves, auto-publish on row leave | ItemTableAGGrid | Items-specific editing orchestration built on top of ArdaGrid. The canary useDirtyTracking<T>() hook covers generic dirty tracking, but the draft creation/API integration is domain-specific. | Partially covered. useDirtyTracking<T>() handles generic dirty state. Draft API calls are domain-specific and must remain in the canary-refactor story layer. |
| 9 | Page chrome components — AppSidebar, AppHeader, SidebarProvider, tab navigation, search bar, column visibility dropdown | ItemsPage | The full page layout wrapping the grid. These are vendored UI components not related to the grid library. | Out of scope for the grid library. The canary-refactor stories must either: (a) continue importing these from vendored, or (b) fork them into canary-refactor components. |
| 10 | ItemDetailsPanel / ItemFormPanel — Detail view and add/edit form panels | ItemsPage | Opened by row click and “Add item” button. Not grid components, but the item-detail story exercises them. | Out of scope for the grid library. Must remain vendored in the canary-refactor stories. |
| 11 | Color cell editor with swatches — Inline <select> with 10 color options and color swatch display | ItemTableAGGrid (inline editor) | Domain-specific select editor built into ItemTableAGGrid, not using the canary enum cell editor pattern. | Not covered by canary enum editor. The vendored implementation is a plain <select> element, not an AG Grid cellEditor component. Domain-specific. |
Assessment Summary
Section titled “Assessment Summary”The canary components (Waves 0-3b) provide the grid infrastructure: DataGrid<T> molecule, createEntityDataGrid<T>() factory, createEntityDataGridShim<T>() vendored compatibility layer, 5 basic cell type Display+Editor atoms, pagination, dirty tracking hook.
However, the canary-refactor stories render the full vendored ItemsPage, which has extensive domain-specific components above the grid infrastructure layer. The canary-refactor stories can swap the grid infrastructure (Tiers 2-3b) but must retain vendored imports for:
- All domain-specific cell editors (#2) and custom cell renderers (#3-6)
- Column definitions (#7)
- Page chrome (#9) and panels (#10)
This is consistent with the project scope (Tiers 1-3b in scope, Tier 4 domain grids out of scope). The canary-refactor stories will be hybrid: canary grid infrastructure + vendored domain components + vendored page chrome.
Insufficiency #1 (SortMenuHeader) is the only item that should be in scope but is missing from the design. It is an internal sub-component of ArdaGrid that must be ported as part of Tier 2.
Appendix A: AG Grid Row Selection Capabilities
Section titled “Appendix A: AG Grid Row Selection Capabilities”This appendix documents the AG Grid Community and Enterprise row selection features relevant to this project. It resolves Q14 and informs the decision to replace the vendored SelectAllHeaderComponent with AG Grid native configuration.
AG Grid Community — Row Selection Features
Section titled “AG Grid Community — Row Selection Features”AG Grid Community (ag-grid-community) provides all the row selection features needed by this project. No Enterprise license is required.
| Feature | Configuration | Available In |
|---|---|---|
| Multi-row selection with checkboxes | rowSelection: { mode: 'multiRow' } | Community |
| Shift-click range selection on checkboxes | Built-in behavior in multiRow mode | Community |
| Header checkbox (tri-state: all/some/none) | rowSelection: { headerCheckbox: true } | Community |
| Select-all modes | rowSelection: { selectAll: 'all' | 'filtered' | 'currentPage' } | Community |
| Click-to-select without checkbox | rowSelection: { enableClickSelection: true } | Community |
| Checkbox column customization | selectionColumnDef: { width, pinned, sortable, ... } | Community |
The AG Grid documentation explicitly states:
“Ranges of rows can be selected by holding down Shift while clicking on checkboxes. This behaviour also applies when Click Selection is enabled, and in Group Selection.”
This means the vendored SelectAllHeaderComponent (~160 lines) reimplements functionality that AG Grid Community already provides natively: tri-state header checkbox and shift-click range selection on row checkboxes.
AG Grid Enterprise — Additional Selection Features (Not Required)
Section titled “AG Grid Enterprise — Additional Selection Features (Not Required)”AG Grid Enterprise adds cell-level selection features that are not needed by this project:
| Feature | Description | Available In |
|---|---|---|
| Cell Range Selection | Select rectangular regions of cells (spreadsheet-like drag selection) | Enterprise |
| Range Selection API | Programmatic cell range manipulation, copy/paste ranges | Enterprise |
| Fill Handle | Drag cell corner to auto-fill adjacent cells (Excel-style) | Enterprise |
These features operate at the cell level, not the row level, and are unrelated to the row selection behavior used by the Items grid.
Recommended Configuration for Canary DataGrid<T>
Section titled “Recommended Configuration for Canary DataGrid<T>”The canary Tier 2 DataGrid<T> molecule should configure row selection as follows:
const rowSelection = useMemo(() => ({ mode: 'multiRow' as const, headerCheckbox: true, selectAll: 'all' as const,}), []);
const selectionColumnDef = useMemo(() => ({ pinned: 'left' as const, width: 50, suppressHeaderMenuButton: true,}), []);This replaces the vendored SelectAllHeaderComponent entirely and provides:
- Tri-state header checkbox (all/some/none)
- Shift-click range selection on row checkboxes
- Configurable checkbox column (width, pinning)
References
Section titled “References”- AG Grid React: Multi-Row Selection — shift-click, header checkbox, selectAll modes
- AG Grid: Row Selection API Reference —
rowSelectionconfiguration object - AG Grid React: Community vs. Enterprise — feature comparison
- AG Grid: Licence and Pricing — licensing details
- AG Grid: Cell Selection (Enterprise) — Enterprise-only cell range features
Copyright: © Arda Systems 2025-2026, All rights reserved