Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
250 lines
23 KiB
Markdown
250 lines
23 KiB
Markdown
# SCRATCHPAD — Invoice Designer Unified Component AST
|
||
|
||
## Context
|
||
|
||
Goal: collapse designer state into a unified generic node tree so adding new properties (for example `borderRadius`) is mostly schema work, not store plumbing.
|
||
|
||
This plan intentionally continues the simplification arc:
|
||
|
||
1. Templates are data (`templateAst` JSON) not code/WASM.
|
||
2. Layout math is delegated to the DOM/CSS engine (flex/grid + dnd-kit).
|
||
3. Designer state becomes a single generic AST with schema-driven editing.
|
||
|
||
## Current State (Starting Point)
|
||
|
||
- Designer store uses `DesignerNode[]` with typed fields:
|
||
- `position`, `size`, `parentId`, `childIds`, `allowedChildren`, `layout`, `style`, `metadata`, etc.
|
||
- Property editing is largely hardcoded in `packages/billing/src/components/invoice-designer/DesignerShell.tsx`.
|
||
- Nesting rules are defined in `packages/billing/src/components/invoice-designer/state/hierarchy.ts`.
|
||
- Palette metadata defaults live in `packages/billing/src/components/invoice-designer/constants/componentCatalog.ts`.
|
||
|
||
## Decisions (Implementation Choices That Minimize Trouble)
|
||
|
||
- Source of truth for hierarchy is `children` arrays only.
|
||
- Do not persist `parentId` (redundant and easy to desync).
|
||
- Parent lookup is derived when needed (tree sizes are small enough for O(n) searches).
|
||
- Patch API uses dot-notation paths (for example `style.width`, `metadata.bindingKey`) rather than JSON Pointer to keep call sites readable.
|
||
- Internally, patch operations should be applied immutably (structural sharing).
|
||
- This patch API is a hard requirement for the strategy: without it, the refactor cost is paid without getting the “new prop = schema change” velocity gain.
|
||
- Component schema becomes the single source of truth for:
|
||
- palette labels/descriptions/categories
|
||
- defaults (initial props)
|
||
- editable props schema (inspector UI)
|
||
- allowed parents/children (nesting rules)
|
||
- Inspector will support a small set of core field widgets plus opt-in custom widgets for complex objects/arrays (tables).
|
||
|
||
## Notes / Gotchas
|
||
|
||
- Ensure history/undo remains stable:
|
||
- Either snapshot `nodesById + rootId` per commit, or store patches and replay.
|
||
- Snapshotting is simpler and aligns with current approach; patch replay is smaller but more error-prone.
|
||
- Some existing code expects `allowedChildren` to be present on nodes; that must become a derived selector from schema.
|
||
- Export/import to invoice-template AST needs a single authoritative mapping; avoid letting schema defaults leak into exported templates unexpectedly.
|
||
|
||
## File Targets (Likely Touchpoints)
|
||
|
||
- Store:
|
||
- `packages/billing/src/components/invoice-designer/state/designerStore.ts`
|
||
- Hierarchy rules removal:
|
||
- `packages/billing/src/components/invoice-designer/state/hierarchy.ts` (delete)
|
||
- Component schema/catalog:
|
||
- `packages/billing/src/components/invoice-designer/constants/componentCatalog.ts` (likely merged into or replaced by schema module)
|
||
- Inspector refactor:
|
||
- `packages/billing/src/components/invoice-designer/DesignerShell.tsx`
|
||
- Canvas rendering:
|
||
- `packages/billing/src/components/invoice-designer/canvas/DesignCanvas.tsx`
|
||
- Workspace AST mapping:
|
||
- `packages/billing/src/components/invoice-designer/ast/workspaceAst.ts`
|
||
|
||
## Validation Runbook (When Implementing)
|
||
|
||
- Tree invariants:
|
||
- every child id exists in `nodesById`
|
||
- no cycles (walk from root and track visited)
|
||
- all nodes are reachable from root (or explicitly allow unattached nodes, but prefer not to)
|
||
- Quick grep for legacy references:
|
||
- `rg -n "parentId|allowedChildren|updateNodeStyle\\(|updateNodeLayout\\(|updateNodeMetadata\\(" packages/billing/src/components/invoice-designer -S`
|
||
|
||
## Developer Guide (Adding Props / Components)
|
||
|
||
### Component Schema Source Of Truth
|
||
|
||
- File: `packages/billing/src/components/invoice-designer/schema/componentSchema.ts`
|
||
- Each component defines:
|
||
- `label`/`description`/`category` (palette + inspector display metadata)
|
||
- `defaults`: initial `name`, `layout`, `style`, `metadata`, `size`
|
||
- `hierarchy`: `allowedParents` + `allowedChildren`
|
||
- `inspector`: panels/fields (schema-driven Inspector)
|
||
- Helpers now live on the schema module:
|
||
- `getAllowedChildrenForType(type)`
|
||
- `getAllowedParentsForType(type)`
|
||
- `canNestWithinParent(childType, parentType)`
|
||
|
||
### Inspector Schema Format
|
||
|
||
- Files:
|
||
- `packages/billing/src/components/invoice-designer/schema/inspectorSchema.ts` (field/panel types)
|
||
- `packages/billing/src/components/invoice-designer/inspector/DesignerSchemaInspector.tsx` (renderer)
|
||
- Field kinds supported:
|
||
- primitives: `string`, `number`, `boolean`, `enum`
|
||
- CSS-ish: `css-length`, `css-color`
|
||
- complex: `widget` (custom React editor for component-specific metadata)
|
||
- Visibility rules:
|
||
- `visibleWhen` supports `nodeIsContainer`, `pathEquals`, `parentPathEquals`
|
||
- Widgets:
|
||
- Implement widgets in `packages/billing/src/components/invoice-designer/inspector/widgets/`
|
||
- Register by referencing the widget `id` in schema (example: `table-editor` for `metadata.columns`)
|
||
|
||
### Patch API (How To Mutate State)
|
||
|
||
- File: `packages/billing/src/components/invoice-designer/state/designerStore.ts`
|
||
- Only supported mutation surface (for anything persistent/undoable):
|
||
- `setNodeProp(nodeId, path, value, commit?)`
|
||
- `unsetNodeProp(nodeId, path, commit?)`
|
||
- `insertChild(parentId, childId, index)`
|
||
- `removeChild(parentId, childId)`
|
||
- `moveNode(nodeId, nextParentId, nextIndex)`
|
||
- `deleteNode(nodeId)`
|
||
- Dot-path conventions (recommended):
|
||
- `name`
|
||
- `style.*` (sizing/typography/media CSS-like props)
|
||
- `layout.*` (container layout props)
|
||
- `metadata.*` (component-specific config)
|
||
- History/undo semantics:
|
||
- `commit` defaults to `true`
|
||
- For multi-step edits that should be a single undo step: use `commit=false` for intermediate writes and `commit=true` for the final write.
|
||
|
||
### Persistence Rules (What Gets Serialized)
|
||
|
||
- Persisted workspace snapshot is `{ rootId, nodesById, canvas settings }`.
|
||
- `exportWorkspace()` sanitizes node `props` to drop runtime/editor-only keys:
|
||
- `position`, `size`, `baseSize`, `layoutPresetId`
|
||
- If a prop should survive reload and affect output, it should live under:
|
||
- `props.style`, `props.layout`, or `props.metadata` (and be surfaced via schema).
|
||
|
||
### Conventions For Adding A New Property
|
||
|
||
1. Add/extend the schema field in `componentSchema.ts` (usually via `COMMON_INSPECTOR` or component-specific `inspector`).
|
||
2. Provide a default in `defaults.style` / `defaults.layout` / `defaults.metadata` only if it must exist on insertion.
|
||
3. Avoid adding store actions/reducers: use `setNodeProp`/`unsetNodeProp` from inspector and other UI.
|
||
|
||
### Conventions For Adding A New Component
|
||
|
||
1. Add a `DesignerComponentSchema` entry in `DESIGNER_COMPONENT_SCHEMAS`.
|
||
2. Define `hierarchy.allowedParents` and `hierarchy.allowedChildren` (the only authority for nesting rules).
|
||
3. Define `defaults` and `inspector` panels/fields.
|
||
4. Canvas/palette/outline should not need bespoke wiring if schema is complete.
|
||
|
||
## Progress Log
|
||
|
||
- 2026-02-13: Implemented unified AST type definitions in `packages/billing/src/components/invoice-designer/state/designerAst.ts`:
|
||
- `DesignerAstNode` with `{ id, type, props, children }`
|
||
- `DesignerAstWorkspace` with `{ rootId, nodesById }`
|
||
- Stable document root id constant: `DESIGNER_AST_DOCUMENT_ID = 'designer-document-root'`
|
||
- 2026-02-13: Added canonical indexing to the designer store state in `packages/billing/src/components/invoice-designer/state/designerStore.ts`:
|
||
- Store state now includes `rootId` and `nodesById` kept in sync with the existing `nodes` array via a `setWithIndex` wrapper.
|
||
- This is an incremental cutover step so downstream UI/tests can migrate off `nodes` progressively.
|
||
- 2026-02-13: Implemented generic patch operations in `packages/billing/src/components/invoice-designer/state/patchOps.ts` and exposed them on the store:
|
||
- `setNodeProp` / `unsetNodeProp` for dot-path updates (immutable deep updates with empty-object cleanup).
|
||
- `insertChild` / `removeChild` / `moveNode` / `deleteNode` for hierarchy mutations (cycle prevention in `moveNode`).
|
||
- Renamed legacy coordinate nudge API to `moveNodeByDelta` to free `moveNode` for tree moves.
|
||
- 2026-02-13: Refined undo/redo history behavior in `packages/billing/src/components/invoice-designer/state/designerStore.ts`:
|
||
- Store now initializes history with a baseline snapshot so the first committed mutation can be undone.
|
||
- `setNodeProp` / `unsetNodeProp` now commit to history by default to match existing property-edit behavior.
|
||
- 2026-02-13: Introduced component schema definitions in `packages/billing/src/components/invoice-designer/schema/componentSchema.ts`:
|
||
- Defines per-component label/description/category, defaults (size/layout/metadata), and hierarchy allowlists.
|
||
- `packages/billing/src/components/invoice-designer/constants/componentCatalog.ts` now derives palette definitions from schema (schema is the new source of truth for palette metadata/defaults).
|
||
- 2026-02-13: Hierarchy allowlists are now resolved via schema:
|
||
- `packages/billing/src/components/invoice-designer/state/hierarchy.ts` is now a thin wrapper over `getComponentSchema(type).hierarchy`.
|
||
- 2026-02-13: Palette insertion now uses schema defaults and generic tree ops:
|
||
- `packages/billing/src/components/invoice-designer/state/designerStore.ts` `addNodeFromPalette` now pulls size/layout/style/metadata defaults from `getComponentSchema(type).defaults` and attaches nodes using `insertChild` semantics (`patchOps.insertChild`).
|
||
- Default metadata normalization for repeated insertions (table columns, attachment items) moved into the store (`normalizeDefaultMetadataForNewNode`), removing hardcoded defaults from `DesignerShell.tsx`.
|
||
- 2026-02-13: Outline + breadcrumbs now traverse the tree via children arrays:
|
||
- `packages/billing/src/components/invoice-designer/palette/OutlineView.tsx` now renders from `rootId` and `nodesById`, deriving parent lookup only for expand behavior.
|
||
- `packages/billing/src/components/invoice-designer/DesignerShell.tsx` breadcrumbs now derive parent links from `childIds` instead of relying on persisted `parentId`.
|
||
- 2026-02-13: Selection/hover state now validates ids against `nodesById`:
|
||
- `packages/billing/src/components/invoice-designer/state/designerStore.ts` `selectNode`/`setHoverNode` clear invalid ids and `deleteNode` clears selection/hover if the referenced node is removed as part of a subtree delete.
|
||
- 2026-02-13: Canvas rendering now resolves from unified node props:
|
||
- Added `packages/billing/src/components/invoice-designer/utils/nodeProps.ts` as the canonical accessor for `props.name`, `props.layout`, `props.style`, `props.metadata` (with temporary legacy fallbacks during cutover).
|
||
- `packages/billing/src/components/invoice-designer/canvas/DesignCanvas.tsx` and `packages/billing/src/components/invoice-designer/canvas/previewScaffolds.ts` now render using `props.*` accessors.
|
||
- Store mutations keep `props` in sync with legacy fields for now (`packages/billing/src/components/invoice-designer/state/designerStore.ts`).
|
||
- 2026-02-13: Drag-drop reparent/reorder now uses generic tree ops:
|
||
- `packages/billing/src/components/invoice-designer/DesignerShell.tsx` now calls `store.moveNode(...)` (tree move) instead of `moveNodeToParentAtIndex`.
|
||
- `packages/billing/src/components/invoice-designer/state/designerStore.flowDnd.test.ts` updated to exercise `moveNode(...)` directly.
|
||
- 2026-02-13: Resizing now writes through the generic patch API:
|
||
- Removed `updateNodeSize` from `packages/billing/src/components/invoice-designer/state/designerStore.ts`.
|
||
- `packages/billing/src/components/invoice-designer/DesignerShell.tsx` now implements `resizeNode(...)` using `setNodeProp` writes (`size.*`, `baseSize.*`, `style.*`) with a single history commit on mouse-up.
|
||
- `setNodeProp`/`unsetNodeProp` now mirror `name`/`style.*`/`layout.*`/`metadata.*` updates into both legacy fields and `props.*` during cutover.
|
||
- 2026-02-13: Started schema-driven Inspector cutover:
|
||
- Added a minimal inspector schema format in `packages/billing/src/components/invoice-designer/schema/inspectorSchema.ts` and attached schemas to component definitions in `packages/billing/src/components/invoice-designer/schema/componentSchema.ts`.
|
||
- Implemented `packages/billing/src/components/invoice-designer/inspector/DesignerSchemaInspector.tsx` which renders panels/fields from the selected node's component schema and writes edits via `setNodeProp`/`unsetNodeProp` (commit-on-blur for text fields).
|
||
- Updated `packages/billing/src/components/invoice-designer/DesignerShell.tsx` to render the schema-driven inspector for supported metadata panels while leaving complex editors (tables/attachments/media) on the legacy path for now.
|
||
- 2026-02-13: Expanded schema-driven Inspector field types and conditional panels:
|
||
- `packages/billing/src/components/invoice-designer/schema/inspectorSchema.ts` now supports `number`, `css-length`, `css-color` field kinds plus `visibleWhen` rules (`nodeIsContainer`, `pathEquals`, `parentPathEquals`).
|
||
- `packages/billing/src/components/invoice-designer/schema/componentSchema.ts` now defines a `COMMON_INSPECTOR` (Layout, Sizing, Flex Item) and merges it into all component schemas, so layout/style edits are schema-defined rather than hardcoded in the shell.
|
||
- `packages/billing/src/components/invoice-designer/DesignerShell.tsx` removed the hardcoded Layout/Sizing/Flex Item inspector blocks and relies on `DesignerSchemaInspector` for those panels; legacy metadata editors remain only for complex types (table columns, attachment items, media).
|
||
- 2026-02-13: Added first complex schema widget for metadata:
|
||
- Implemented `packages/billing/src/components/invoice-designer/inspector/widgets/TableEditorWidget.tsx` and wired it into the schema via a `widget` inspector field (`table-editor`).
|
||
- `packages/billing/src/components/invoice-designer/schema/componentSchema.ts` now attaches the table editor widget to both `table` and `dynamic-table` schemas.
|
||
- Removed the hardcoded table/dynamic-table inspector block from `packages/billing/src/components/invoice-designer/DesignerShell.tsx` (tables now render their metadata editor via schema widget).
|
||
- 2026-02-13: Updated designer <-> invoice-template AST mapping to prefer unified props + children:
|
||
- `packages/billing/src/components/invoice-designer/ast/workspaceAst.ts` now reads `name/layout/style/metadata` via `packages/billing/src/components/invoice-designer/utils/nodeProps.ts` helpers and traverses `children` (fallback to `childIds` for legacy nodes).
|
||
- Import now materializes `props` and `children` on generated nodes and keeps them in sync with legacy fields during cutover.
|
||
- Updated `packages/billing/src/components/invoice-designer/ast/workspaceAst.test.ts` fixtures to set `props` + `children` so export/import exercises the unified tree.
|
||
- 2026-02-13: Added undo/redo history regression test in `packages/billing/src/components/invoice-designer/state/designerStore.undoRedo.test.ts`:
|
||
- Verifies tree state returns exactly to prior snapshots after a `moveNode` followed by `deleteNode`, via sequential `undo()` and `redo()`.
|
||
- 2026-02-13: Added schema invariants test in `packages/billing/src/components/invoice-designer/schema/componentSchema.test.ts`:
|
||
- Ensures every component type has defaults, an inspector schema, and reciprocal nesting allowlists (parent allowedChildren aligns with child allowedParents).
|
||
- 2026-02-13: Added repo/unit guard ensuring `packages/billing/src/components/invoice-designer/state/hierarchy.ts` stays deleted and is not imported anywhere in the invoice designer code.
|
||
- 2026-02-13: Added palette insertion integration test in `packages/billing/src/components/invoice-designer/state/designerStore.addNodeFromPalette.test.ts`:
|
||
- Verifies `addNodeFromPalette` pulls `layout/metadata/size` defaults from the component schema and attaches the new node id into the parent `children` array.
|
||
- 2026-02-13: Added outline rendering integration test in `packages/billing/src/components/invoice-designer/palette/OutlineView.integration.test.tsx`:
|
||
- Verifies outline order matches `childIds` ordering and selection state drives highlight styling.
|
||
- 2026-02-13: Added breadcrumbs hierarchy integration coverage in `packages/billing/src/components/invoice-designer/DesignerShell.breadcrumbs.test.ts`:
|
||
- Validates breadcrumb path is derived from `childIds` (children-only hierarchy) and does not depend on persisted `parentId`.
|
||
- 2026-02-13: Added unified props rendering integration test in `packages/billing/src/components/invoice-designer/canvas/DesignCanvas.unifiedProps.integration.test.tsx`:
|
||
- Ensures `node.props.layout` and `node.props.style` are sufficient to drive DOM styles (without relying on `node.layout` / `node.style`).
|
||
- 2026-02-13: Added drag-drop reorder integration test in `packages/billing/src/components/invoice-designer/state/designerStore.dragDropReorder.integration.test.ts`:
|
||
- Uses `loadWorkspace({ rootId, nodesById })` to validate `moveNode(...)` reorders `children` for flow (flex) containers in the unified snapshot format.
|
||
- 2026-02-13: Added drag-drop reparent integration test in `packages/billing/src/components/invoice-designer/state/designerStore.dragDropMoveAcross.integration.test.ts`:
|
||
- Validates moving across containers updates only the unified `children` arrays in the exported workspace snapshot and rejects invalid parent targets via schema nesting rules.
|
||
- 2026-02-13: Added resize-to-DOM integration test in `packages/billing/src/components/invoice-designer/canvas/DesignCanvas.resizeProps.integration.test.tsx`:
|
||
- Simulates resize writes via `store.setNodeProp('style.width'/'style.height', ...)` and verifies the rendered canvas node element updates its inline sizing.
|
||
- 2026-02-13: Persisted workspace snapshots now omit runtime geometry/editor-only props:
|
||
- `packages/billing/src/components/invoice-designer/state/designerStore.ts` `exportWorkspace()` sanitizes `node.props` to drop `position`, `size`, `baseSize`, and `layoutPresetId` (new saves are unified-only).
|
||
- Updated `packages/billing/src/actions/invoicePreviewPdfParity.integration.test.ts` workspace fixture to use `{ rootId, nodesById }` (no `nodes` / `constraints`).
|
||
- Updated `packages/billing/src/components/invoice-designer/state/designerStore.constraints.test.ts` assertions to validate unified snapshots.
|
||
- 2026-02-13: Removed legacy hierarchy module:
|
||
- Deleted `packages/billing/src/components/invoice-designer/state/hierarchy.ts`.
|
||
- Moved `getAllowedChildrenForType` / `getAllowedParentsForType` / `canNestWithinParent` helpers into `packages/billing/src/components/invoice-designer/schema/componentSchema.ts` and updated call sites to import from schema.
|
||
- 2026-02-13: Removed per-property store actions in favor of patch ops:
|
||
- Deleted legacy store APIs: `updateNodeName`, `updateNodeMetadata`, `updateNodeLayout`, `updateNodeStyle`, `setNodePosition`, `moveNodeByDelta`, `moveNodeToParentAtIndex`.
|
||
- Kept label text behavior by normalizing label `name` <-> `metadata.text` changes inside `setNodeProp`/`unsetNodeProp` (only when mutating `name` or `metadata.*`).
|
||
- Fixed `rootId` indexing so `exportWorkspace()` snapshots can be round-tripped via `loadWorkspace()` even when legacy fixtures use non-canonical document ids.
|
||
- Updated affected tests and UI call sites to use `setNodeProp`/`unsetNodeProp` exclusively.
|
||
- 2026-02-13: Added deterministic unified-tree traversal helper and tests:
|
||
- `packages/billing/src/components/invoice-designer/state/designerAst.ts` now exports `traverseDesignerAstNodeIds`.
|
||
- Added `packages/billing/src/components/invoice-designer/state/designerAst.test.ts`.
|
||
- 2026-02-13: Added patch ops unit coverage:
|
||
- Added `packages/billing/src/components/invoice-designer/state/patchOps.setNodeProp.test.ts` to validate immutable deep dot-path updates.
|
||
- Added `packages/billing/src/components/invoice-designer/state/patchOps.unsetNodeProp.test.ts` to validate cleanup behavior for empty objects.
|
||
- Added `packages/billing/src/components/invoice-designer/state/patchOps.insertChild.test.ts` to validate deterministic child insertion ordering.
|
||
- Added `packages/billing/src/components/invoice-designer/state/patchOps.moveNode.test.ts` to validate reorder/reparent semantics + cycle prevention.
|
||
- Added `packages/billing/src/components/invoice-designer/state/patchOps.deleteNode.test.ts` to validate subtree deletion behavior.
|
||
- 2026-02-13: Added schema-driven inspector integration coverage:
|
||
- Added `packages/billing/src/components/invoice-designer/inspector/DesignerSchemaInspector.integration.test.tsx` to assert the inspector renders fields from schema and writes unified `props.*` via generic patch operations.
|
||
- Testing gotcha: our shared `<Input>` doesn’t reliably forward `id` to the native `<input>`, so tests query controls by placeholder rather than label association.
|
||
- 2026-02-13: Extracted Inspector input normalizers and added unit coverage:
|
||
- Added `packages/billing/src/components/invoice-designer/inspector/normalizers.ts` (+ `normalizeString`, `normalizeCssLength`, `normalizeCssColor`, `normalizeNumber`) and wired `DesignerSchemaInspector` to use them.
|
||
- Added `packages/billing/src/components/invoice-designer/inspector/normalizers.test.ts` to validate canonicalization behavior (for example unitless CSS lengths become `px`, empty strings unset).
|
||
- 2026-02-13: Added table editor schema widget integration coverage:
|
||
- Added `packages/billing/src/components/invoice-designer/inspector/TableEditorWidget.integration.test.tsx` to assert the `table-editor` widget updates `metadata.columns` and the canvas preview header reacts to the updated columns list.
|
||
- 2026-02-13: Made workspace <-> template AST export/import deterministic:
|
||
- Updated `packages/billing/src/components/invoice-designer/ast/workspaceAst.ts` import to treat a single top-level AST `section` wrapper as the designer `page` node (avoids nested page->section wrapping on roundtrip).
|
||
- Added `export -> import -> export` deterministic roundtrip assertion in `packages/billing/src/components/invoice-designer/ast/workspaceAst.test.ts`.
|
||
- 2026-02-13: Added persisted workspace snapshot format coverage:
|
||
- Added `packages/billing/src/components/invoice-designer/state/designerStore.exportWorkspace.test.ts` to ensure `exportWorkspace()` returns only `{ rootId, nodesById, snapToGrid, gridSize, showGuides, showRulers, canvasScale }` and strips runtime/editor-only `props` keys (`position`, `size`, `baseSize`, `layoutPresetId`).
|
||
- 2026-02-13: Added repo guards for refactor completeness:
|
||
- Added `packages/billing/src/components/invoice-designer/state/noLegacyApis.guard.test.ts` to enforce removed per-property store action names stay gone, and to keep hierarchy traversal using `children` (no `childIds` usage outside `state/`).
|
||
- Updated `packages/billing/src/components/invoice-designer/palette/OutlineView.tsx`, `packages/billing/src/components/invoice-designer/canvas/DesignCanvas.tsx`, and `packages/billing/src/components/invoice-designer/DesignerShell.tsx` to traverse `children` rather than `childIds`.
|