Phase 4: Entity Data Grid
Objective
Section titled “Objective”Port the entity data grid factory (createEntityDataGrid<T>()), create the composable useDirtyTracking<T>() hook, build the ActionCellRenderer<T> atom, and create the vendored-compatible shim (createEntityDataGridShim<T>()).
Corresponds to Waves 3a and 3b of the Porting Strategy.
Entry Criteria
Section titled “Entry Criteria”Phase 3 must be complete. Verify by checking artifacts — do NOT re-run tests.
Verify before starting:
- DataGrid molecule present:
ls src/components/canary/molecules/data-grid/showsdata-grid.tsx,sort-menu-header.tsx,use-column-persistence.ts,index.ts, test and story files - DataGrid exports compile:
grep 'DataGrid' src/components/canary/molecules/data-grid/index.tsconfirms the barrel exportsDataGrid,DataGridRef, config types - SortMenuHeader present:
ls src/components/canary/molecules/data-grid/sort-menu-header.tsxexists - Phase 3 exit gate passed: check for
npm run lint+npm run testsuccess in the Phase 3 terminal output (do not re-run)
Wave 3a Tasks
Section titled “Wave 3a Tasks”T4.1 — Create useDirtyTracking<T>() Hook
Section titled “T4.1 — Create useDirtyTracking<T>() Hook”- Target:
components/canary/organisms/shared/entity-data-grid/use-dirty-tracking.ts - Extract dirty tracking logic from
components/extras/organisms/shared/entity-data-grid/create-entity-data-grid.tsx:- Clone row data for comparison
- Track per-cell edits (dirty set)
saveAllDrafts()— clears dirty state optimisticallygetHasUnsavedChanges()— returns booleandiscardAllDrafts()— restores original valuesonUnsavedChangesChange?(hasChanges: boolean)— callback
- This is a standalone composable hook — no dependency on
DataGridor AG Grid - Create unit tests: verify dirty state transitions, save/discard behavior, callback invocations
T4.2 — Port createEntityDataGrid<T>()
Section titled “T4.2 — Port createEntityDataGrid<T>()”- Copy
components/extras/organisms/shared/entity-data-grid/create-entity-data-grid.tsxtocomponents/canary/organisms/shared/entity-data-grid/create-entity-data-grid.tsx - Rename exported function from
createArdaEntityDataGridtocreateEntityDataGrid - Update imports:
ArdaDataGrid/ArdaDataGridRef→ canaryDataGrid/DataGridReffrom@/components/canary/molecules/data-gridPaginationData→@/types/canary/paginationag-grid-communitytypes — no change
- Remove inline dirty tracking — replace with optional composition of
useDirtyTracking<T>()from T4.1. The factory should accept an optionaluseDirtyTrackinginstance rather than embedding the logic. - Add Tier 3a features (from vendored
ArdaGridfeatures allocated to 3a in the Q6 feature table):enableMultiSort?: boolean+onSortChanged?(sortModel: any): void— maps to AG Grid’smultiSortKeypropenableFiltering?: boolean+onFilterChanged?(filterModel: any): void— maps tofilter: trueondefaultColDefonCellEditingStarted?,onCellEditingStopped?,onCellFocused?— passthrough AG Grid native eventsgetRowClass?(params): string | string[]— passthrough AG Grid native prop
- Copy and adapt existing tests and stories
- Create barrel:
components/canary/organisms/shared/entity-data-grid/index.ts
T4.3 — Verify Wave 3a
Section titled “T4.3 — Verify Wave 3a”- All unit tests pass
- Storybook stories render in
Components/Canary/Organisms/Shared/Entity Data Grid - Dirty tracking testable in isolation via hook tests
npm run lint+npm run testpass
Wave 3b Tasks
Section titled “Wave 3b Tasks”T4.4 — Create ActionCellRenderer<T>
Section titled “T4.4 — Create ActionCellRenderer<T>”- Target:
components/canary/atoms/grid/action/action-cell-renderer.tsx - Props:
rowData: T,actions: RowAction<T>[]whereRowAction<T> = { label: string; icon?: ReactNode; onClick: (rowData: T) => void } - Behavior: Renders a
⋮button that opens a dropdown menu listing actions. Click an action →onClick(rowData). Click outside or Escape → close. - Uses portal (
createPortal) for dropdown overflow escaping (same pattern asSortMenuHeader) - Dependencies:
cn*,lucide-react(for defaultMoreVerticalicon) - Create tests and story
- Export
RowAction<T>type alongside the component
T4.5 — Create createEntityDataGridShim<T>()
Section titled “T4.5 — Create createEntityDataGridShim<T>()”- Target:
components/canary/organisms/shared/entity-data-grid-shim/create-entity-data-grid-shim.tsx - Wraps
createEntityDataGrid<T>()from Wave 3a - Add Tier 3b features (from vendored
ArdaGridfeatures allocated to 3b in the Q6 feature table):enableRowActions?: boolean+rowActions?: RowAction<T>[]— injectsActionCellRendereras a pinned-right columnonRowDoubleClicked?(entity: T): void— passthrough AG Grid native eventhasActiveSearch?: boolean— vendored compatibility shim: when true + no data, shows “No items found” instead ofemptyStateComponentinitialState?: GridState— passthrough AG Grid v31+ state restoration prop
- Extended ref:
refreshData(): void— delegates togridApi.refreshCells()getSelectedRows(): T[]— delegates togridApi.getSelectedRows()selectAll(): void— delegates togridApi.selectAll()deselectAll(): void— delegates togridApi.deselectAll()
- Create tests and stories demonstrating vendored
ArdaGridfeature parity - Create barrel:
components/canary/organisms/shared/entity-data-grid-shim/index.ts
T4.6 — Verify Wave 3b
Section titled “T4.6 — Verify Wave 3b”- All unit tests pass
- Storybook stories demonstrate: row actions dropdown, double-click handler, hasActiveSearch empty state, extended ref methods
npm run lint+npm run testpass
Acceptance Criteria
Section titled “Acceptance Criteria”components/canary/organisms/shared/entity-data-grid/contains: factory, dirty tracking hook, index barrel, tests, storiescomponents/canary/organisms/shared/entity-data-grid-shim/contains: shim factory, index barrel, tests, storiescomponents/canary/atoms/grid/action/contains:ActionCellRenderer,RowActiontype, tests, storyuseDirtyTracking<T>()works as a standalone composable hookcreateEntityDataGrid<T>()provides Tier 3a features (multi-sort, filtering, cell editing lifecycle, getRowClass)createEntityDataGridShim<T>()provides vendoredArdaGridcompatibility (row actions, double-click, hasActiveSearch, initialState, extended ref)- No imports from
extrasorvendoredin any canary file npm run lint+npm run testpass
Copyright: © Arda Systems 2025-2026, All rights reserved