Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
31 KiB
Scratchpad — Designer UX & Quote Bindings
Key File Paths
Designer Inspector System
- Schema definitions:
packages/billing/src/components/invoice-designer/schema/componentSchema.ts- COMMON_INSPECTOR (line 58) — layout, sizing, appearance, flex-item panels
- Layout enum fields: flexDirection (91), alignItems (101), justifyContent (114)
- Grid string fields: gridTemplateColumns (143), gridTemplateRows (150)
- Spacing css-length fields: gap (76), padding (83), margin (242)
- Inspector renderer:
packages/billing/src/components/invoice-designer/inspector/DesignerSchemaInspector.tsx- Field kind rendering: renderField (line 117)
- enum → CustomSelect dropdown (190-206)
- css-length → text Input (209-225)
- widget → TableEditorWidget (289-293)
- Normalizers import (line 14-20)
- Inspector schema types:
packages/billing/src/components/invoice-designer/schema/inspectorSchema.ts - Normalizers:
packages/billing/src/components/invoice-designer/inspector/normalizers.ts
Designer Palette
- Palette component:
packages/billing/src/components/invoice-designer/palette/ComponentPalette.tsx- 4 tabs: BLOCKS, PRESETS, FIELDS, OUTLINE (lines ~272-299)
- Fields tab builds from expression context adapter (lines 230-233)
- Field grouping by category: invoice, customer, tenant, item (lines 41-46)
- Layout presets:
packages/billing/src/components/invoice-designer/constants/presets.ts- LayoutPresetDefinition interface (line 35)
- LAYOUT_PRESETS array (line 44): 5-6 existing presets
Quote Bindings
- Binding definitions:
packages/billing/src/lib/quote-template-ast/bindings.ts- 35 value bindings (lines 7-35)
- 2 collection bindings: lineItems, phases (lines 37-40)
- Quote adapters:
packages/billing/src/lib/adapters/quoteAdapters.ts- mapQuoteItemToViewModel (line 37) — maps single item
- buildPhaseViewModels (line 64) — groups by phase
- mapLoadedQuoteToViewModel (line 207) — builds full view model
- Quote types:
packages/types/src/interfaces/quote.interfaces.ts- QuoteViewModel (line ~185)
- QuoteViewModelLineItem — has is_recurring, service_item_kind, billing_frequency
Table Editor Widget
- Widget:
packages/billing/src/components/invoice-designer/inspector/widgets/TableEditorWidget.tsx- Collection binding dropdown (lines 391-403)
- Options built from AST bindings (lines 142-205)
Panel Scroll Problem (FR-0)
The 3-panel layout (palette | canvas | inspector) is inside flex flex-1 min-h-[560px] (line 1830).
- Palette (left): Has floating behavior via
isPaletteFloating+fixed top-0(line 1843). Bug: triggers whenrect.top <= 0(line 703), pinning to browser viewport top, overlapping the app header/navbar. Causes jarring jump on scroll. - Canvas (center):
flex-1 flex(line 2091) - Inspector (right): Plain
<aside class="w-72 ... p-4 space-y-4">(line 1885) — NO overflow-y, NO fixed height
Both problems stem from the same root cause: the 3-panel row doesn't constrain its height, so overflow goes to the page.
Fix: Make the 3-panel row fill available height with overflow-hidden, then each panel gets overflow-y-auto. Remove the palette floating hack entirely — it was compensating for the missing overflow constraint.
Key lines to change:
- Line 1830:
<div className="flex flex-1 min-h-[560px]">— add overflow-hidden, make it fill height - Line 1831-1858: Palette wrapper — remove floating logic, add overflow-y-auto
- Line 1885: Inspector aside — add overflow-y-auto
- Lines 597-603, 673-733: Remove isPaletteFloating state + syncPaletteFloatingState effect
Already Implemented (removed from scope)
- Flex direction icon toggles —
DesignerShell.tsxlines 308-311,CONTAINER_FLEX_DIRECTION_OPTIONS - Align items icon toggles — lines 313-318,
CONTAINER_ALIGN_ITEMS_OPTIONS - Justify content icon toggles — lines 320-327,
CONTAINER_JUSTIFY_CONTENT_OPTIONS - Layout mode toggle (flex/grid) — lines 303-306,
CONTAINER_LAYOUT_MODE_OPTIONS - All rendered via
renderButtonGroup()helper (lines 1029-1065) insiderenderContainerLayoutControls()(1019-1098) - Gap: Grid mode shows NO controls after toggling to grid (line 1076 only renders flex sub-controls). This is the key UX gap to fill.
Architecture Decisions
New field kind: icon-button-group
Rather than replacing enum fields inline, introduce a new inspector field kind icon-button-group that renders a row of icon toggle buttons. The schema entry would look like:
{
kind: 'icon-button-group',
id: 'flexDirection',
label: 'Direction',
path: 'layout.flexDirection',
options: [
{ value: 'column', label: 'Vertical', icon: 'arrow-down' },
{ value: 'row', label: 'Horizontal', icon: 'arrow-right' },
],
}
This keeps the schema declarative and the renderer generic.
New field kind: css-length-stepper
For gap/padding, a new field kind that renders number input + unit dropdown:
{
kind: 'css-length-stepper',
id: 'gap',
label: 'Gap',
path: 'layout.gap',
allowedUnits: ['px', '%', 'rem'],
defaultUnit: 'px',
}
New widget: column-layout-picker
For the grid column presets, a new widget (like table-editor) that shows clickable visual cards.
Filtered collections: computed at view model level
Rather than adding filtering logic to the template renderer, compute filtered arrays and aggregates in mapLoadedQuoteToViewModel(). The binding paths then point directly to new top-level fields on the view model. This keeps rendering simple and the data shape flat.
Gotchas
- Inspector field kind extensibility — Currently hardcoded if/else chain in renderField. Adding new kinds means adding new branches. No plugin system.
- Expression context adapter is separate from AST bindings — The Fields palette uses
buildInvoiceExpressionPathOptions()which has a separate schema from the quote bindings. New quote bindings need to be added to BOTH systems. - Legacy preset layout format — Some presets use
{ mode, direction, gap }instead of CSS{ display, flexDirection, gap }. New presets should use the CSS format. - Dark theme — Inspector uses
dark:Tailwind prefixes. New components need dark variants. - setNodeProp commit parameter — Interactive controls (sliders, steppers) should pass
commit: falseduring drag/type andcommit: trueon release/blur for clean undo history.
Progress Log
-
F000acomplete. Confirmed the shell panel row inpackages/billing/src/components/invoice-designer/DesignerShell.tsxusesflex flex-1 min-h-0 overflow-hidden, then added stable panel automation IDs plusmin-h-0/min-w-0hooks around the three-panel shell so the fixed-height layout is testable and explicit. -
Verification for
F000a:cd server && npx vitest run ../packages/billing/src/components/invoice-designer/DesignerShell.panelScroll.integration.test.tsx -
F000bcomplete. The inspector<aside>now exposesdata-automation-id="designer-shell-inspector-panel"withoverflow-y-autoandmin-h-0, which locks inspector scrolling to its own column instead of the page. -
Verification for
F000b: same targeted Vitest slice inDesignerShell.panelScroll.integration.test.tsxasserts the inspector panel classes. -
F000ccomplete. The palette wrapper now usesoverflow-y-autoandmin-h-0withdata-automation-id="designer-shell-palette-panel", so palette scrolling stays inside the left rail instead of relying on viewport pinning. -
Verification for
F000c: same targeted Vitest slice asserts the palette panel scroll-container classes. -
F000dcomplete.DesignerShell.tsxno longer containsisPaletteFloating,syncPaletteFloatingState, orfixed top-0; the old viewport-floating branch is gone and the test file guards against regressions with a source-level assertion. -
Verification for
F000d:DesignerShell.panelScroll.integration.test.tsxreads the source file and asserts those legacy strings are absent. -
F000ecomplete. The center panel now exposesdata-automation-id="designer-shell-canvas-panel"withflex-1 min-h-0 min-w-0, keeping the canvas in the middle flex slot while palette/inspector scroll independently. -
Verification for
F000e: same targeted Vitest slice asserts the canvas panel remains the flexing middle column inside the overflow-hidden shell row. -
F001complete. AddedGRID_COLUMN_PRESETSplus a visual grid-preset picker torenderContainerLayoutControls()inpackages/billing/src/components/invoice-designer/DesignerShell.tsx. The picker renders five preset cards with preview bars and stable automation IDs. -
Verification for
F001:cd server && npx vitest run ../packages/billing/src/components/invoice-designer/DesignerShell.gridLayoutControls.integration.test.tsx -
F002complete. Each preset button writeslayout.gridTemplateColumnsthroughsetNodeProp, and also reaffirmslayout.display = 'grid'so the selection always leaves the container in grid mode. -
Verification for
F002: the same grid-layout integration test clicks each preset and asserts the exact persistedgridTemplateColumnsvalue in the store. -
F003complete. Active-state styling now derives from a normalizedgridTemplateColumnsstring comparison and is exposed witharia-pressed, including the no-match case for custom values. -
Verification for
F003: the same grid-layout integration test covers both matching and custom non-matching template values. -
F004complete. The preset picker is rendered only in thelayoutMode === 'grid'branch insiderenderContainerLayoutControls(), preserving the existing flex-only control set for flex containers. -
Verification for
F004: the same grid-layout integration test asserts presence in grid mode and absence in flex mode. -
F005complete. The schema-drivenTemplate Columnsstring input remains in the Layout panel below the new visual picker, so customgridTemplateColumnsvalues are still editable. -
Verification for
F005: the same grid-layout integration test asserts the preset container appears before the rawTemplate Columnsinput in the DOM. -
F006complete. Added parser/formatter helpers inpackages/billing/src/components/invoice-designer/inspector/cssLengthFields.ts, newcss-length-stepper/css-length-boxschema kinds, and dedicated inspector field components inDesignerSchemaInspector.tsx.layout.gapnow renders as a number input plus unit selector instead of a freeform text field. -
Verification for
F006:cd server && npx vitest run ../packages/billing/src/components/invoice-designer/inspector/cssLengthFields.test.ts ../packages/billing/src/components/invoice-designer/inspector/DesignerSchemaInspector.spacingControls.integration.test.tsx ../packages/billing/src/components/invoice-designer/inspector/DesignerSchemaInspector.integration.test.tsx ../packages/billing/src/components/invoice-designer/schema/componentSchema.test.ts -
F007complete.layout.paddingnow uses the samecss-length-stepperrenderer, so padding is edited with a numeric input plus unit selector instead of raw CSS text. -
Verification for
F007: the same spacing-control integration test asserts the padding stepper and unit dropdown render. -
F008complete. The stepper field kind supportspx,%, andrem, withpxas the default when the authored value is unitless or empty. -
Verification for
F008: the spacing-control integration test inspects the rendered unit dropdown options directly. -
F009complete.parseCssLength()now initializes the stepper from stored CSS values such as16px,2rem,50%, and unitless0, while preserving unsupported custom strings until the user edits them. -
Verification for
F009: bothcssLengthFields.test.tsand the spacing-control integration test cover parse-on-load cases. -
F010complete.formatCssLength()writes numeric + unit selections back to the store as canonical CSS strings, and the stepper renderer uses that formatter for both value and unit changes. -
Verification for
F010: the spacing-control integration test asserts writeback on numeric changes and on unit changes. -
F011complete.style.marginnow uses thecss-length-boxrenderer, which exposes four side-specific steppers (top/right/bottom/left) plus a shared unit selector. -
Verification for
F011: the spacing-control integration test asserts all four margin inputs render. -
F012complete. The margin box renderer includes aLink alltoggle; when linked it writes the same numeric value to every side, and when toggled off each side can diverge independently. -
Verification for
F012: the spacing-control integration test covers both linked sync and unlinked independence. -
F013complete.parseCssLengthBox()expands 1-value, 2-value, 3-value, and 4-value CSS shorthand into per-side numeric state for the margin controls. -
Verification for
F013:cssLengthFields.test.tscovers shorthand parsing cases. -
F014complete.formatCssLengthBox()writes per-side margin edits back as optimized CSS shorthand strings, collapsing to the shortest valid token count. -
Verification for
F014:cssLengthFields.test.tscovers optimized shorthand formatting. -
F015complete. Added aNotes + Totals Rowbody preset inpackages/billing/src/components/invoice-designer/constants/presets.tswith a grid section root and2fr 1frtracks. -
Verification for
F015:cd server && npx vitest run ../packages/billing/src/components/invoice-designer/state/designerStore.presets.test.ts -
F016complete. Added aTwo Equal Columnsbody preset backed by a grid section with1fr 1frtracks. -
Verification for
F016: the preset insertion test suite asserts the inserted section layout. -
F017complete. Added aThree Info Columnsbody preset backed by a grid section with1fr 1fr 1frtracks. -
Verification for
F017: the preset insertion test suite asserts the inserted section layout. -
F018complete. All three new body presets are authored with modern CSS layout objects (display: 'grid',gridTemplateColumns) rather than legacy{ mode, direction }preset layout fields. -
Verification for
F018: the preset insertion test suite asserts the inserted section layouts do not depend on legacy preset fields. -
F019complete. ExtendedQuoteViewModel,mapLoadedQuoteToViewModel(), andQUOTE_TEMPLATE_COLLECTION_BINDINGSso recurring line items are exposed asrecurring_items/recurringItems. The designer now also infers quote context from imported binding catalogs for field discovery. -
Verification for
F019:cd server && npx vitest run ../packages/billing/src/lib/quote-template-ast/bindings.test.ts ../packages/billing/src/lib/adapters/quoteAdapters.test.ts ../packages/billing/src/components/invoice-designer/palette/ComponentPalette.fields.integration.test.tsx ../packages/billing/src/components/invoice-designer/palette/ComponentPalette.quoteFields.integration.test.tsx ../packages/billing/src/components/invoice-designer/inspector/TableEditorWidget.integration.test.tsx ../packages/types/src/interfaces/quoteViewModel.typecheck.test.ts -
F020complete. One-time line items are exposed frommapLoadedQuoteToViewModel()asonetime_items, andonetimeItemsis registered in the quote collection binding catalog. -
Verification for
F020: the quote adapter and binding tests assert the one-time filtered collection shape. -
F021complete. Service line items are exposed asservice_items, and the view model now carriesservice_item_kindthrough to each mapped quote line item. -
Verification for
F021: the quote adapter and binding tests assert service filtering and the mappedservice_item_kind. -
F022complete. Product line items are exposed asproduct_items, andproductItemsis registered in the quote collection binding catalog for tables. -
Verification for
F022: the quote adapter and binding tests assert product filtering. -
F023complete. AddedrecurringSubtotal,recurringTax, andrecurringTotalbindings backed by aggregate fields computed fromrecurring_items. -
Verification for
F023: the quote adapter and binding tests assert recurring aggregate math. -
F024complete. AddedonetimeSubtotal,onetimeTax, andonetimeTotalbindings backed by aggregate fields computed fromonetime_items. -
Verification for
F024: the quote adapter and binding tests assert one-time aggregate math. -
F025complete. AddedserviceSubtotal,serviceTax, andserviceTotalbindings backed by aggregate fields computed fromservice_items. -
Verification for
F025: the quote adapter and binding tests assert service aggregate math. -
F026complete. AddedproductSubtotal,productTax, andproductTotalbindings backed by aggregate fields computed fromproduct_items. -
Verification for
F026: the quote adapter and binding tests assert product aggregate math. -
F027complete.packages/types/src/interfaces/quote.interfaces.tsnow includes filtered item arrays onQuoteViewModel, andQuoteViewModelLineItemcarriesservice_item_kind. -
Verification for
F027: the newquoteViewModel.typecheck.test.tsand quote adapter tests exercise the added fields. -
F028complete.QuoteViewModelnow includes recurring/one-time/service/product subtotal, tax, and total fields for template binding consumption. -
Verification for
F028: the typecheck test and quote adapter aggregate assertions cover the new fields. -
F029complete.mapLoadedQuoteToViewModel()now materializesrecurring_items,onetime_items,service_items, andproduct_itemsdirectly from the mapped quote line items. -
Verification for
F029: the quote adapter tests assert the filtered array contents. -
F030complete.mapLoadedQuoteToViewModel()also computes per-group subtotal/tax/total aggregates using the same filtered item groups, including zero-value fallbacks when groups are empty. -
Verification for
F030: the quote adapter tests assert aggregate totals and zero-value empty-group behavior. -
F031complete.TableEditorWidgetnow surfaces the imported quote collection catalog, and the integration test verifies the source-binding dropdown lists the new filtered collection bindings. -
Verification for
F031:TableEditorWidget.integration.test.tsxcovers the quote collection dropdown contents. -
F032complete. The component palette now infers quote document context from imported binding catalogs and shows quote-specific field groups, including aQuote Totalssection for the new aggregate bindings. -
Verification for
F032:ComponentPalette.quoteFields.integration.test.tsxasserts discovery and insertion ofquoteTotals.recurringTotal. -
Added plan item
F018a/T030abecause the PRD requires a quote-specificRecurring + One-time Tablespreset, but the generated checklist had omitted it. Keep it separate fromF018so the extra quote-only preset remains explicit and independently traceable. -
F018acomplete. Added aRecurring + One-time Tablesbody preset inpackages/billing/src/components/invoice-designer/constants/presets.tswith a single-column grid section and twodynamic-tablechildren pre-bound torecurringItemsandonetimeItems. -
Verification for
F018a:cd server && npx vitest run ../packages/billing/src/components/invoice-designer/state/designerStore.presets.test.ts -
F033complete. Added explicit dark-theme regression assertions for the new grid preset controls inDesignerShell.gridLayoutControls.integration.test.tsxand the spacing/margin steppers inDesignerSchemaInspector.spacingControls.integration.test.tsx, so the new UI surfaces keep theirdark:styling hooks under a.darkwrapper. -
Verification for
F033:cd server && npx vitest run ../packages/billing/src/components/invoice-designer/DesignerShell.gridLayoutControls.integration.test.tsx ../packages/billing/src/components/invoice-designer/inspector/DesignerSchemaInspector.spacingControls.integration.test.tsx -
F034complete. AddedworkspaceAst.standardTemplates.regression.test.tsto protect both standard invoice and standard quote templates against designer import/export regressions by asserting deterministic round-trips, binding-catalog preservation, and critical node retention for every shipped standard template code. -
Verification for
F034:cd server && npx vitest run ../packages/billing/src/components/invoice-designer/ast/workspaceAst.standardTemplates.regression.test.ts -
Added follow-up plan items
F002a,F004a, andF004bafter re-reading the PRD against the shipped shell behavior. The extracted checklist had codified the current implementation, but the PRD still requires the grid picker to be usable as the way into grid mode and for the same layout controls to be available on section nodes. -
F002acomplete. The grid preset buttons now stay actionable from flex layouts, and the shell test covers the flex-to-grid transition by asserting a preset click changeslayout.displaytogridand applies the chosengridTemplateColumns. -
Verification for
F002a:cd server && npx vitest run ../packages/billing/src/components/invoice-designer/DesignerShell.gridLayoutControls.integration.test.tsx -
F004acomplete. The grid preset picker is no longer hidden behindlayoutMode === 'grid'; it stays visible for flex layouts so users can choose a column preset as the entry point into grid mode instead of hand-editing CSS. -
Verification for
F004a:cd server && npx vitest run ../packages/billing/src/components/invoice-designer/DesignerShell.gridLayoutControls.integration.test.tsx -
F004bcomplete.DesignerShell.tsxnow resolves layout controls for bothcontainerandsectionnodes, and the shell integration test selects a section node to prove the shared layout control panel still renders the same grid-mode entry points there. -
Verification for
F004b:cd server && npx vitest run ../packages/billing/src/components/invoice-designer/DesignerShell.gridLayoutControls.integration.test.tsx -
T000acomplete. Covered by DesignerShell.panelScroll.integration.test.tsx asserting the shell row is overflow-hidden and the inspector panel owns its own overflow-y scroll container. -
T000bcomplete. Covered by DesignerShell.panelScroll.integration.test.tsx asserting the palette uses its own overflow-y scroll container instead of viewport pinning. -
T000ccomplete. Covered by DesignerShell.panelScroll.integration.test.tsx asserting the canvas remains in the flexing middle panel while the side rails scroll independently. -
T000dcomplete. Covered by DesignerShell.panelScroll.integration.test.tsx source assertions removing isPaletteFloating, syncPaletteFloatingState, and fixed top-0 usage. -
T001complete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx rendering all five grid preset buttons in grid mode. -
T001acomplete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx selecting a section node and asserting the shared layout controls and grid picker still render. -
T002complete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx keeping the grid preset buttons visible while the selected node starts in flex mode. -
T003complete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx asserting the 2 equal columns preset writes 1fr 1fr. -
T004complete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx asserting the sidebar plus main preset writes 1fr 2fr. -
T005complete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx asserting the main plus sidebar preset writes 2fr 1fr. -
T006complete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx asserting the 3 equal columns preset writes 1fr 1fr 1fr. -
T007complete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx asserting the 1 column preset writes 1fr. -
T007acomplete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx asserting a preset click from flex mode flips display to grid and applies the chosen columns. -
T008complete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx asserting the matching preset exposes aria-pressed=true based on gridTemplateColumns. -
T009complete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx asserting custom gridTemplateColumns values leave every preset inactive. -
T010complete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx asserting the raw Template Columns input remains visible beneath the visual picker. -
T011complete. Covered by DesignerSchemaInspector.spacingControls.integration.test.tsx rendering a numeric gap input with a unit selector instead of a raw text field. -
T012complete. Covered by DesignerSchemaInspector.spacingControls.integration.test.tsx rendering a numeric padding input with a unit selector. -
T013complete. Covered by DesignerSchemaInspector.spacingControls.integration.test.tsx asserting the spacing unit selector exposes px, %, and rem. -
T014complete. Covered by cssLengthFields.test.ts and DesignerSchemaInspector.spacingControls.integration.test.tsx parsing 16px into value 16 with unit px. -
T015complete. Covered by cssLengthFields.test.ts and DesignerSchemaInspector.spacingControls.integration.test.tsx parsing 2rem into value 2 with unit rem. -
T016complete. Covered by cssLengthFields.test.ts and DesignerSchemaInspector.spacingControls.integration.test.tsx parsing 50 percent into value 50 with unit percent. -
T017complete. Covered by cssLengthFields.test.ts and DesignerSchemaInspector.spacingControls.integration.test.tsx parsing unitless or px zero into value 0 with px as the default unit. -
T018complete. Covered by DesignerSchemaInspector.spacingControls.integration.test.tsx asserting gap value edits write back a combined CSS length string. -
T019complete. Covered by DesignerSchemaInspector.spacingControls.integration.test.tsx asserting gap unit changes write back a combined CSS length string. -
T020complete. Covered by DesignerSchemaInspector.spacingControls.integration.test.tsx rendering the four margin side inputs, shared unit selector, and link toggle. -
T021complete. Covered by DesignerSchemaInspector.spacingControls.integration.test.tsx asserting Link all keeps all four margin sides synchronized. -
T022complete. Covered by DesignerSchemaInspector.spacingControls.integration.test.tsx asserting margin sides diverge independently once Link all is disabled. -
T023complete. Covered by cssLengthFields.test.ts parsing two-value margin shorthand into per-side values. -
T024complete. Covered by cssLengthFields.test.ts parsing one-value margin shorthand into equal per-side values. -
T025complete. Covered by cssLengthFields.test.ts parsing four-value margin shorthand into explicit per-side values. -
T026complete. Covered by cssLengthFields.test.ts formatting per-side margin edits back into optimized CSS shorthand. -
T027complete. Covered by designerStore.presets.test.ts asserting the Notes plus Totals Row preset inserts a grid section with 2fr 1fr columns. -
T028complete. Covered by designerStore.presets.test.ts asserting the Two Equal Columns preset inserts a grid section with equal tracks. -
T029complete. Covered by designerStore.presets.test.ts asserting the Three Info Columns preset inserts a grid section with three equal tracks. -
T030complete. Covered by designerStore.presets.test.ts asserting the new presets use display grid and gridTemplateColumns instead of legacy mode or direction fields. -
T030acomplete. Covered by designerStore.presets.test.ts asserting the Recurring plus One-time Tables preset inserts two dynamic tables bound to recurringItems and onetimeItems. -
T031complete. Covered by quoteAdapters.test.ts asserting recurring_items contains only line items where is_recurring is true. -
T032complete. Covered by quoteAdapters.test.ts asserting onetime_items contains only line items where is_recurring is not true. -
T033complete. Covered by quoteAdapters.test.ts asserting service_items contains only line items with service_item_kind service. -
T034complete. Covered by quoteAdapters.test.ts asserting product_items contains only line items with service_item_kind product. -
T035complete. Expanded quoteAdapters.test.ts to cover a quote with no line items, proving every filtered collection returns an empty array instead of erroring when nothing matches. -
T036complete. Covered by quoteAdapters.test.ts asserting recurring_subtotal sums total_price only across recurring items. -
T037complete. Covered by quoteAdapters.test.ts asserting recurring_tax sums tax_amount only across recurring items. -
T038complete. Covered by quoteAdapters.test.ts asserting recurring_total equals recurring subtotal plus recurring tax. -
T039complete. Covered by quoteAdapters.test.ts asserting onetime_subtotal sums total_price only across one-time items. -
T040complete. Covered by quoteAdapters.test.ts asserting onetime_tax sums tax_amount only across one-time items. -
T041complete. Covered by quoteAdapters.test.ts asserting onetime_total equals one-time subtotal plus one-time tax. -
T042complete. Covered by quoteAdapters.test.ts asserting service subtotal, tax, and total are computed only from service items. -
T043complete. Covered by quoteAdapters.test.ts asserting product subtotal, tax, and total are computed only from product items. -
T044complete. Covered by quoteViewModel.typecheck.test.ts asserting QuoteViewModel exposes the filtered item arrays used by quote templates. -
T045complete. Covered by quoteViewModel.typecheck.test.ts asserting QuoteViewModel exposes the per-group aggregate number fields used by quote templates. -
T046complete. Covered by quoteAdapters.test.ts asserting mapLoadedQuoteToViewModel populates recurring, one-time, service, and product arrays with the expected item ids. -
T047complete. Covered by quoteAdapters.test.ts asserting group aggregates match the sums of the filtered items. -
T048complete. Covered by quoteAdapters.test.ts asserting every quote group aggregate falls back to zero when no items match. -
T049complete. Covered by TableEditorWidget.integration.test.tsx asserting the collection dropdown lists recurringItems, onetimeItems, serviceItems, and productItems. -
T050complete. Expanded ComponentPalette.quoteFields.integration.test.tsx to assert the Quote Totals section exposes recurring, onetime, service, and product total field buttons for discovery before inserting the recurring total alias. -
T051complete. Covered by DesignerShell.gridLayoutControls.integration.test.tsx and DesignerSchemaInspector.spacingControls.integration.test.tsx asserting the new controls retain their dark-theme class hooks under a dark wrapper. -
T052complete. Covered by workspaceAst.standardTemplates.regression.test.ts asserting both shipped standard invoice templates keep their critical node ids, binding catalogs, and deterministic round-trip output across designer import and export. -
T053complete. Covered by workspaceAst.standardTemplates.regression.test.ts asserting both shipped standard quote templates keep their critical node ids, binding catalogs, and deterministic round-trip output across designer import and export.