Hermes 284313f908
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
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

267 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Scratchpad — Inline Add New Pickers
## Key File Paths
### Picker Components (to modify)
- `packages/ui/src/components/ContactPicker.tsx` — add `onAddNew` prop, render button after scrollable list (~line 361)
- `packages/ui/src/components/ClientPicker.tsx` — add `onAddNew` prop, render button after client list (~line 341)
- `packages/tickets/src/components/CategoryPicker.tsx` — add `onAddNew` prop, pass to TreeSelect
- `packages/ui/src/components/TreeSelect.tsx` — add `onAddNew` prop, render button at bottom of Radix content
### Existing QuickAdd Dialogs (to reuse as-is)
- `packages/clients/src/components/contacts/QuickAddContact.tsx` — Props: `isOpen, onClose, onContactAdded(IContact), clients: IClient[], selectedClientId?: string`
- `packages/clients/src/components/clients/QuickAddClient.tsx` — Props: `open, onOpenChange(boolean), onClientAdded(IClient), trigger?: ReactNode`
### QuickAddCategory (to extract)
- Source: `packages/tickets/src/components/settings/CategoriesSettings.tsx` lines 486-620 (inline dialog JSX)
- Target: `packages/tickets/src/components/QuickAddCategory.tsx` (new file)
- Action: `packages/tickets/src/actions/ticketCategoryActions.ts``createCategory` (line 269)
- Also uses: `getAllBoards` from `packages/tickets/src/actions/board-actions/boardActions.ts`
### Reference Implementation
- `packages/ui/src/components/EditableServiceTypeSelect.tsx` lines 253-303 — the "+ Add new" button pattern
## ContactPicker Consumers (10 files)
| # | File | clientId source | contacts source | clients list |
|---|------|----------------|-----------------|--------------|
| 1 | `packages/tickets/src/components/QuickAddTicket.tsx` | `clientId` state | `contacts` state (via getContactsByClient) | `filteredClients` |
| 2 | `packages/tickets/src/components/ticket/TicketProperties.tsx` | `ticket.company_id` prop | `contacts` prop from parent | Need to pass or fetch |
| 3 | `packages/clients/src/components/interactions/QuickAddInteraction.tsx` | `selectedClientId` state | `contacts` state (via getAllContacts) | `clients` available |
| 4 | `packages/clients/src/components/interactions/OverallInteractionsFeed.tsx` | `selectedClient` state | `contacts` state (via getAllContacts) | `clients` available |
| 5 | `packages/projects/src/components/ProjectQuickAdd.tsx` | `selectedClientId` state | `contacts` state | `clients` available |
| 6 | `packages/projects/src/components/Projects.tsx` | filter state | `allContacts` state | `allClients` available |
| 7 | `packages/clients/src/components/clients/ClientDetails.tsx` | `clientId` prop | `clientActiveContacts` prop | current client context |
| 8 | `packages/clients/src/components/clients/BillingConfigForm.tsx` | billing context | `contacts` prop | may need clients prop |
| 9 | `server/src/components/settings/general/UserManagement.tsx` | `selectedClientId` state | `contacts` state | `clients` available |
| 10 | `ee/server/src/components/settings/integrations/EntraReconciliationQueue.tsx` | per-item clientId | `allContacts` state | `clients` available |
## ClientPicker Consumers (5 key files)
| # | File | Notes |
|---|------|-------|
| 1 | `packages/tickets/src/components/QuickAddTicket.tsx` | Ticket creation — highest impact |
| 2 | `packages/projects/src/components/ProjectQuickAdd.tsx` | Project creation |
| 3 | `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx` | Contract creation |
| 4 | `packages/billing/src/components/billing-dashboard/ManualInvoices.tsx` | Invoice creation |
| 5 | `packages/assets/src/components/QuickAddAsset.tsx` | Asset creation |
## CategoryPicker Consumers (4 key files)
| # | File | boardId source | categories source |
|---|------|---------------|-------------------|
| 1 | `packages/tickets/src/components/QuickAddTicket.tsx` | `boardId` state | `categories` state |
| 2 | `packages/tickets/src/components/ticket/TicketInfo.tsx` | `ticket.board_id` via props | `effectiveCategories` from props |
| 3 | `packages/tickets/src/components/TicketingDashboard.tsx` | board filter | categories loaded |
| 4 | `packages/tickets/src/components/ticket/TicketDetails.tsx` | ticket context | categories from props |
## Consumer Wiring Pattern (copy-paste template)
```tsx
// 1. Add state
const [isQuickAddContactOpen, setIsQuickAddContactOpen] = useState(false);
// 2. Pass to picker
<ContactPicker
onAddNew={() => setIsQuickAddContactOpen(true)}
// ... existing props
/>
// 3. Render dialog
<QuickAddContact
isOpen={isQuickAddContactOpen}
onClose={() => setIsQuickAddContactOpen(false)}
onContactAdded={(newContact) => {
setContacts(prev => [...prev, newContact]);
setSelectedContactId(newContact.contact_name_id);
setIsQuickAddContactOpen(false);
}}
clients={clients}
selectedClientId={selectedClientId}
/>
```
## Decisions
- **Pickers stay generic** — no QuickAdd imports in picker components. Consumer wires the dialog.
- **QuickAddCategory is create-only** — editing stays inline in CategoriesSettings. The extracted component handles only creation.
- **CategoriesSettings still handles edit mode** — it passes `editingCategory` and different save logic for edits. QuickAddCategory only handles the create path.
- **preselectedBoardId simplifies inline UX** — when board is known from context (ticket creation), skip the board dropdown entirely.
- **TreeSelect gets onAddNew** — since CategoryPicker is a thin wrapper around TreeSelect, the button rendering logic goes in TreeSelect.
## Gotchas
- **QuickAddContact needs `clients: IClient[]`** — some consumers may not have this loaded. They'll need to fetch it or pass an empty array (QuickAddContact shows a client dropdown).
- **TreeSelect uses Radix Select** — the add button must be inside the Radix portal content. Verify focus management doesn't break.
- **CategoriesSettings edit dialog has more fields** — the extracted QuickAddCategory handles create-only (name, board, parent, display_order). Editing (which also changes board for parent categories + shows warnings) may stay as inline JSX in CategoriesSettings OR QuickAddCategory can accept an `editingCategory` prop for dual-mode. TBD during implementation — start with create-only.
- **QuickAddTicket gets THREE new dialogs** — ContactPicker, ClientPicker, AND CategoryPicker all wired. This file will have the most changes.
## Implementation Order
1. **Part 1** — ContactPicker core (onAddNew prop + button)
2. **Part 2** — ContactPicker consumers (10 files, mechanical)
3. **Part 3** — ClientPicker core (onAddNew prop + button)
4. **Part 4** — ClientPicker consumers (5 files, mechanical)
5. **Part 5a** — Extract QuickAddCategory from CategoriesSettings
6. **Part 5b** — Refactor CategoriesSettings to use QuickAddCategory
7. **Part 5c** — TreeSelect + CategoryPicker onAddNew
8. **Part 5d** — CategoryPicker consumers (4 files)
9. **Verify** — run existing tests, manual smoke test
## Progress Log
- 2026-03-08 F001: Added optional `onAddNew` support to `packages/ui/src/components/ContactPicker.tsx` and rendered the bottom separator/button using the PRD styling pattern. Included the dropdown height estimate update so the portal positions correctly when the new action is present.
- Validation: `cd packages/ui && npx vitest run --config vitest.config.ts src/components/ContactPicker.test.tsx`
- 2026-03-08 F002/F003: The new `handleAddNew` path now closes the dropdown before invoking the consumer callback, and the add-new UI is fully gated behind the optional prop so existing picker rendering remains unchanged when omitted.
- 2026-03-08 T001: Verified the add button and separator render when `onAddNew` is present.
- 2026-03-08 T002: Verified the add button stays hidden when `onAddNew` is omitted.
- 2026-03-08 T003: Verified the add button keeps the requested utility classes and renders a `Plus` icon.
- 2026-03-08 T004: Verified clicking the add button calls the consumer callback exactly once.
- 2026-03-08 T005: Verified clicking the add button closes the dropdown portal.
- 2026-03-08 F004: Wired `packages/tickets/src/components/QuickAddTicket.tsx` to pass `onAddNew` into `ContactPicker`, open `QuickAddContact`, and prefill it with the current `clientId`. Also exported `QuickAddContact` from `packages/clients/src/components/index.ts` so consumers can use the package surface instead of a non-exported deep path.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- Test blocker: `packages/tickets` Vitest still resolves deep server/auth imports while loading `QuickAddTicket`, so the new `QuickAddTicketPrefill` assertions for T006-T008 are written but not yet checklisted. I added `vite-tsconfig-paths` plus ticket-package aliases/mocks to reduce the surface, but the suite still bottoms out in unrelated auth/db module resolution.
- 2026-03-08 F005: `QuickAddTicket` now merges the created contact into local picker state, selects its `contact_name_id`, and closes the dialog after creation.
- 2026-03-08 F006: Wired `packages/tickets/src/components/ticket/TicketProperties.tsx` to open `QuickAddContact` from the inline contact editor, prefill it with the ticket/client context, and keep a local picker contact list synchronized so newly created contacts can be chosen immediately.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F007: Wired `packages/clients/src/components/interactions/QuickAddInteraction.tsx` to offer inline contact creation when a client is selected, reuse `QuickAddContact`, append the new contact into local state, and auto-select it for the in-progress interaction.
- Validation: `npx tsc -p packages/clients/tsconfig.json --noEmit`
- 2026-03-08 F008: Wired `packages/clients/src/components/interactions/OverallInteractionsFeed.tsx` to offer `QuickAddContact` from the filter dialog, remove the empty-list disable state so add-new stays reachable, merge created contacts into `allContacts`, and auto-select the new contact in the active filter.
- Validation: `npx tsc -p packages/clients/tsconfig.json --noEmit`
- 2026-03-08 F009: Wired `packages/projects/src/components/ProjectQuickAdd.tsx` to open `QuickAddContact` from the project contact picker once a client is selected, merge the created contact into local state, and auto-select it in the form.
- Validation: `npx tsc -p packages/projects/tsconfig.json --noEmit`
- 2026-03-08 F010: Wired `packages/projects/src/components/Projects.tsx` contact filter to open `QuickAddContact`, append the created contact to the cached filter data, and auto-select that contact in the active filter state.
- Validation: `npx tsc -p packages/projects/tsconfig.json --noEmit`
- 2026-03-08 F011: Wired `packages/clients/src/components/clients/ClientDetails.tsx` default-contact picker to open `QuickAddContact` for the current client, merge the created contact into the local default-contact options, and immediately apply it as the default contact selection.
- Validation: `npx tsc -p packages/clients/tsconfig.json --noEmit`
- 2026-03-08 F012: Wired `packages/clients/src/components/clients/BillingConfigForm.tsx` billing-contact picker to open `QuickAddContact` with the current client preselected, merge the new contact into local picker state, and apply it as the billing contact while clearing the fallback billing email.
- Validation: `npx tsc -p packages/clients/tsconfig.json --noEmit`
- 2026-03-08 F013: Wired `server/src/components/settings/general/UserManagement.tsx` existing-contact picker to open `QuickAddContact`, append the created contact to the invitation picker state, auto-select it, and prefill the new user form from the created contact.
- Validation attempt: `npx tsc -p server/tsconfig.json --noEmit` crashed with `Signal(6)` before reporting file-level diagnostics.
- Validation attempt: `npx esbuild server/src/components/settings/general/UserManagement.tsx --bundle --platform=node --format=esm --tsconfig=server/tsconfig.json --outfile=/tmp/user-management-check.js` reached unrelated asset/font resolution errors outside this change.
- 2026-03-08 F014: Wired `ee/server/src/components/settings/integrations/EntraReconciliationQueue.tsx` to load clients, pass `onAddNew` into each queue row's `ContactPicker`, open a shared `QuickAddContact` with the row's mapped client preselected, append the created contact into `allContacts`, and auto-select it for that queue item.
- Validation: `npx tsc -p ee/server/tsconfig.json --noEmit`
- 2026-03-08 F015: Added optional `onAddNew` support to `packages/ui/src/components/ClientPicker.tsx` and rendered the bottom separator/button using the same utility-class pattern as `ContactPicker`/`EditableServiceTypeSelect`.
- Validation: `npx tsc -p packages/ui/tsconfig.json --noEmit`
- 2026-03-08 F016: `ClientPicker` now resets the search term, closes the dropdown, and only then invokes the consumer's `onAddNew` callback so the QuickAdd dialog can take focus immediately.
- Validation: `npx tsc -p packages/ui/tsconfig.json --noEmit`
- 2026-03-08 F017: Confirmed `ClientPicker` remains backward compatible because the new separator/button are fully gated behind the optional `onAddNew` prop; consumers that omit it still render the original dropdown content only.
- Validation: `npx tsc -p packages/ui/tsconfig.json --noEmit`
- 2026-03-08 F018: Wired `packages/tickets/src/components/QuickAddTicket.tsx` to open `QuickAddClient` from `ClientPicker`, merge new clients into local state, auto-select the created client, and let the existing client-data effect refresh contacts/locations for the new selection.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F019: Wired `packages/projects/src/components/ProjectQuickAdd.tsx` to maintain a local `clientOptions` list, open `QuickAddClient` from the client picker, merge newly created clients into that list, and auto-select the new client while clearing any stale contact selection.
- Validation: `npx tsc -p packages/projects/tsconfig.json --noEmit`
- 2026-03-08 F020: Wired `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx` to open `QuickAddClient` from the contract client picker, merge created clients into the billing client cache, and immediately update wizard state (including default currency) to the new client.
- Validation: `npx tsc -p packages/billing/tsconfig.json --noEmit`
- 2026-03-08 F021: Wired `packages/billing/src/components/billing-dashboard/ManualInvoices.tsx` to keep a local `clientOptions` cache, expose `QuickAddClient` from the invoice client picker, merge created clients, and auto-select the new client for manual invoice creation.
- Validation: `npx tsc -p packages/billing/tsconfig.json --noEmit`
- 2026-03-08 F022: Wired `packages/assets/src/components/QuickAddAsset.tsx` client picker to open `QuickAddClient`, merge newly created clients into local state, and auto-select the client so asset creation can continue without leaving the modal.
- Validation: `npx tsc -p packages/assets/tsconfig.json --noEmit`
- 2026-03-08 F023: Extracted the create-only category dialog into `packages/tickets/src/components/QuickAddCategory.tsx` and exported it from the tickets component surface, preserving the existing create-form structure (name, board/parent selection, footer actions) as reusable UI.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F024: `QuickAddCategory` now accepts `preselectedBoardId`, seeds the create form with that board, and hides the board selector whenever the consumer already knows the board context.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F025: `QuickAddCategory` renders the required category-name input, conditionally shows the board selector, and keeps the optional parent-category dropdown filtered to top-level categories with board-aware labels/inheritance.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F026: `QuickAddCategory` now validates the create request, calls `createCategory` with board/parent inheritance, shows a success toast, and hands the created `ITicketCategory` back through `onCategoryCreated` so consumers can update local picker state.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F027: `QuickAddCategory` loads boards internally via `getAllBoards` when the consumer does not pass a board list, while still honoring injected board data from settings or inline ticket forms.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F028: Refactored `packages/tickets/src/components/settings/CategoriesSettings.tsx` so add-category now uses the extracted `QuickAddCategory` component, while the settings page still owns the edit-only dialog markup and refreshes category data after create.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F029: Preserved CategoriesSettings behavior by keeping the existing edit-category path intact, leaving board-change warnings/display-order editing untouched, and refreshing category data after both create and update flows.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F030: Added generic `onAddNew`/`addNewLabel` support to `packages/ui/src/components/TreeSelect.tsx`, rendering the separator/button inside the Radix portal content and explicitly closing the dropdown before invoking the consumer callback.
- Validation: `npx tsc -p packages/ui/tsconfig.json --noEmit && npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F031: `packages/tickets/src/components/CategoryPicker.tsx` now accepts `onAddNew` and passes it into `TreeSelect` with a category-specific `+ Add new category` label.
- Validation: `npx tsc -p packages/ui/tsconfig.json --noEmit && npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F032: Wired `packages/tickets/src/components/QuickAddTicket.tsx` category picker to open `QuickAddCategory` with `boardId` preselected, merge the created category into local state, and auto-select it immediately in the ticket form.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F033: Wired `packages/tickets/src/components/ticket/TicketInfo.tsx` category editor to open `QuickAddCategory` with the effective board context, merge created categories into either saved or pending category state, and set `category_id`/`subcategory_id` correctly for newly created parent or child categories.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F034: Wired `packages/tickets/src/components/TicketingDashboard.tsx` category filter to open `QuickAddCategory`, merge the created category into local filter options, and immediately select the new category while clearing any exclusion state for it.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 F035: The ticket-details screen now inherits inline category creation through `packages/tickets/src/components/ticket/TicketInfo.tsx`, which `TicketDetails` renders with the current ticket board/category context and updated category state.
- Validation: `npx tsc -p packages/tickets/tsconfig.json --noEmit`
- 2026-03-08 T006: Fixed the `packages/tickets` Vitest aliases/mocks that `QuickAddTicket` needs, then validated that clicking `+ Add new contact` in `QuickAddTicketPrefill.test.tsx` opens the mocked `QuickAddContact` dialog.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddTicketPrefill.test.tsx -t "T00[678]"`
- 2026-03-08 T007: The same focused `QuickAddTicketPrefill` coverage now asserts that `QuickAddContact` receives `client-1` as `selectedClientId` when the add-new contact dialog opens.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddTicketPrefill.test.tsx -t "T00[678]"`
- 2026-03-08 T008: `QuickAddTicketPrefill.test.tsx` now verifies the full happy path: creating a contact through the mocked `QuickAddContact` appends it to local picker state and selects `contact-new` automatically.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddTicketPrefill.test.tsx -t "T00[678]"`
- 2026-03-08 T009: Added `packages/tickets/src/components/ticket/__tests__/TicketPropertiesQuickAddContact.test.tsx` to open the inline contact editor, trigger `+ Add new contact`, and assert the mocked `QuickAddContact` dialog opens with `ticket.client_id` taking precedence over the fallback client context.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/ticket/__tests__/TicketPropertiesQuickAddContact.test.tsx`
- 2026-03-08 T010: Added `packages/clients/src/components/interactions/QuickAddInteraction.quick-add-contact.contract.test.ts` to lock the add-new contact wiring in `QuickAddInteraction`, including the guarded `onAddNew` callback and the forwarded `selectedClientId` into `QuickAddContact`.
- Validation: `cd packages/clients && npx vitest run --config vitest.config.ts src/components/interactions/QuickAddInteraction.quick-add-contact.contract.test.ts`
- 2026-03-08 T011: Added `packages/clients/src/components/interactions/OverallInteractionsFeed.quick-add-contact.contract.test.ts` to pin the filter dialog wiring that opens `QuickAddContact`, forwards the current client context, and auto-selects the created contact in filter state.
- Validation: `cd packages/clients && npx vitest run --config vitest.config.ts src/components/interactions/OverallInteractionsFeed.quick-add-contact.contract.test.ts`
- 2026-03-08 T012: Added `packages/projects/src/components/ProjectQuickAdd.quick-add-contact.contract.test.ts` to lock the `ProjectQuickAdd` contact-picker wiring that gates `onAddNew` on a selected client, opens `QuickAddContact`, and auto-selects the created contact.
- Validation: `cd packages/projects && npx vitest run --config vitest.config.ts src/components/ProjectQuickAdd.quick-add-contact.contract.test.ts`
- 2026-03-08 T013: Added `packages/projects/src/components/Projects.quick-add-contact.contract.test.ts` to preserve the projects filter wiring that opens `QuickAddContact`, forwards the current client filter, and auto-selects the created contact in filter state.
- Validation: `cd packages/projects && npx vitest run --config vitest.config.ts src/components/Projects.quick-add-contact.contract.test.ts`
- 2026-03-08 T014: Added `packages/clients/src/components/clients/ClientDetails.quick-add-contact.contract.test.ts` to lock the default-contact picker wiring that opens `QuickAddContact` for the current client and immediately applies the created contact as the new default.
- Validation: `cd packages/clients && npx vitest run --config vitest.config.ts src/components/clients/ClientDetails.quick-add-contact.contract.test.ts`
- 2026-03-08 T015: Added `packages/clients/src/components/clients/BillingConfigForm.quick-add-contact.contract.test.ts` to preserve the billing-contact picker wiring that opens `QuickAddContact`, passes the current `clientId`, and clears fallback billing email when a new contact is created.
- Validation: `cd packages/clients && npx vitest run --config vitest.config.ts src/components/clients/BillingConfigForm.quick-add-contact.contract.test.ts`
- 2026-03-08 T016: Added `server/src/components/settings/general/UserManagement.quick-add-contact.contract.test.ts` to preserve the invite-contact wiring that opens `QuickAddContact`, forwards `newUser.clientId`, and hydrates the new-user form from the created contact.
- Validation: `cd server && npx vitest run --config vitest.config.ts --coverage.enabled false src/components/settings/general/UserManagement.quick-add-contact.contract.test.ts`
- 2026-03-08 T017: Added `server/src/components/settings/integrations/EntraReconciliationQueue.quick-add-contact.contract.test.ts` to preserve the EE reconciliation queue wiring that opens `QuickAddContact`, forwards the mapped client context, and assigns the created contact back to the queued item.
- Validation: `cd server && npx vitest run --config vitest.config.ts --coverage.enabled false src/components/settings/integrations/EntraReconciliationQueue.quick-add-contact.contract.test.ts`
- 2026-03-08 T018: Added `packages/ui/src/components/ClientPicker.test.tsx` and verified that `ClientPicker` renders the bottom separator plus `+ Add new client` action only when `onAddNew` is supplied.
- Validation: `cd packages/ui && npx vitest run --config vitest.config.ts src/components/ClientPicker.test.tsx -t T018`
- 2026-03-08 T019: Extended `packages/ui/src/components/ClientPicker.test.tsx` to verify backward compatibility — the inline `+ Add new client` action stays hidden when `onAddNew` is omitted.
- Validation: `cd packages/ui && npx vitest run --config vitest.config.ts src/components/ClientPicker.test.tsx -t T019`
- 2026-03-08 T020: Extended `packages/ui/src/components/ClientPicker.test.tsx` to verify that clicking `+ Add new client` calls the consumer callback exactly once and closes the dropdown portal.
- Validation: `cd packages/ui && npx vitest run --config vitest.config.ts src/components/ClientPicker.test.tsx -t T020`
- 2026-03-08 T021: Extended `packages/tickets/src/components/__tests__/QuickAddTicketPrefill.test.tsx` so the mocked `ClientPicker` exposes `+ Add new client` and the mocked `QuickAddClient` dialog, then verified that clicking the picker action opens the client quick-add dialog.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddTicketPrefill.test.tsx -t T021`
- 2026-03-08 T022: Extended `QuickAddTicketPrefill.test.tsx` again so the mocked `QuickAddClient` creates a client and closes via `onOpenChange(false)`, then verified `QuickAddTicket` appends the new client and auto-selects `client-new`.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddTicketPrefill.test.tsx -t T022`
- 2026-03-08 T023: Added `packages/projects/src/components/ProjectQuickAdd.quick-add-client.contract.test.ts` to preserve the `ProjectQuickAdd` client-picker wiring that opens `QuickAddClient`, merges the created client into local options, auto-selects it, and clears any stale contact selection.
- Validation: `cd packages/projects && npx vitest run --config vitest.config.ts src/components/ProjectQuickAdd.quick-add-client.contract.test.ts`
- 2026-03-08 T024: Added `packages/billing/tests/contract-basics-step.quick-add-client.contract.test.ts` to preserve the contract-wizard client picker wiring that opens `QuickAddClient`, merges the created client, auto-selects it, and updates contract currency from the new client defaults.
- Validation: `cd packages/billing && npx vitest run --config vitest.config.ts tests/contract-basics-step.quick-add-client.contract.test.ts`
- 2026-03-08 T025: Added `packages/billing/tests/manual-invoices.quick-add-client.contract.test.ts` to preserve the manual-invoice client picker wiring that opens `QuickAddClient`, merges created clients into local options, and auto-selects the new client.
- Validation: `cd packages/billing && npx vitest run --config vitest.config.ts tests/manual-invoices.quick-add-client.contract.test.ts`
- 2026-03-08 T026: Added `packages/assets/src/components/QuickAddAsset.quick-add-client.contract.test.ts` to preserve the asset quick-add client picker wiring that opens `QuickAddClient`, merges the created client, auto-selects it, and clears validation state.
- Validation: `cd packages/assets && npx vitest run --config vitest.config.ts src/components/QuickAddAsset.quick-add-client.contract.test.ts`
- 2026-03-08 T027: Added `packages/tickets/src/components/__tests__/QuickAddCategory.test.tsx` with a jsdom harness for `QuickAddCategory`, starting by verifying the create dialog renders the required category-name input.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddCategory.test.tsx -t T027`
- 2026-03-08 T028: Extended `QuickAddCategory.test.tsx` to verify the board selector is visible in create mode when no `preselectedBoardId` is supplied.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddCategory.test.tsx -t T028`
- 2026-03-08 T029: Extended `QuickAddCategory.test.tsx` to verify `preselectedBoardId` hides the board selector so inline callers can skip redundant board selection.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddCategory.test.tsx -t T029`
- 2026-03-08 T030: Extended `QuickAddCategory.test.tsx` to verify the parent-category select remains available and is filtered to top-level categories on the active board only.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddCategory.test.tsx -t T030`
- 2026-03-08 T031: Extended `QuickAddCategory.test.tsx` to submit the dialog, assert `createCategory` receives the expected payload, and verify `onCategoryCreated` is called with the returned category.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddCategory.test.tsx -t T031`
- 2026-03-08 T032: Extended `QuickAddCategory.test.tsx` to verify the dialog blocks submission and surfaces `Category name is required` when the name field is left blank.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddCategory.test.tsx -t T032`
- 2026-03-08 T033: Extended `QuickAddCategory.test.tsx` to verify top-level category creation is blocked with `Board is required for top-level categories` when no board is selected.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddCategory.test.tsx -t T033`
- 2026-03-08 T034: Extended `QuickAddCategory.test.tsx` to verify that omitting the `boards` prop triggers an internal `getAllBoards()` fetch and populates the board selector from the fetched data.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddCategory.test.tsx -t T034`
- 2026-03-08 T035: Added `packages/tickets/src/components/settings/__tests__/CategoriesSettings.contract.test.ts` to lock the refactor entry point: `CategoriesSettings` now imports and renders `QuickAddCategory` for the add dialog.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/settings/__tests__/CategoriesSettings.contract.test.ts -t T035`
- 2026-03-08 T036: Extended `CategoriesSettings.contract.test.ts` to preserve create-flow parity by asserting the extracted `QuickAddCategory` still receives boards/categories and triggers `fetchCategories()` after creation.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/settings/__tests__/CategoriesSettings.contract.test.ts -t T036`
- 2026-03-08 T037: Extended `CategoriesSettings.contract.test.ts` to preserve edit-flow parity, asserting the inline edit dialog remains, `updateCategory` is still called for edits, and categories refresh after update.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/settings/__tests__/CategoriesSettings.contract.test.ts -t T037`
- 2026-03-08 T038: Added `packages/ui/src/components/TreeSelect.contract.test.ts` to lock the new add-new UI block in `TreeSelect`, including the separator, `Plus` icon, and configurable label.
- Validation: `cd packages/ui && npx vitest run --config vitest.config.ts src/components/TreeSelect.contract.test.ts -t T038`
- 2026-03-08 T039: Extended `TreeSelect.contract.test.ts` to assert the add-new UI stays fully gated behind the optional `onAddNew` prop and its default `addNewLabel`.
- Validation: `cd packages/ui && npx vitest run --config vitest.config.ts src/components/TreeSelect.contract.test.ts -t T039`
- 2026-03-08 T040: Added `packages/tickets/src/components/CategoryPicker.contract.test.ts` to lock the `CategoryPicker` passthrough wiring into `TreeSelect`, including the category-specific add-new label.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/CategoryPicker.contract.test.ts -t T040`
- 2026-03-08 T041: Extended `QuickAddTicketPrefill.test.tsx` with `CategoryPicker`/`QuickAddCategory` mocks so the ticket form now verifies `+ Add new category` opens the category quick-add dialog with `board-1` preselected.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/__tests__/QuickAddTicketPrefill.test.tsx -t T041`
- 2026-03-08 T042: Added `packages/tickets/src/components/QuickAddTicket.category.contract.test.ts` to lock the post-create category wiring in `QuickAddTicket`: created categories merge into local state, become the selected category, clear submission errors, and close the inline dialog.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/QuickAddTicket.category.contract.test.ts -t T042`
- 2026-03-08 T043: Added `packages/tickets/src/components/ticket/__tests__/TicketCategoryConsumer.contract.test.ts` to preserve `TicketInfo` wiring into `QuickAddCategory`, including the effective board preselection and post-create category selection updates.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/ticket/__tests__/TicketCategoryConsumer.contract.test.ts -t T043`
- 2026-03-08 T044: Added `packages/tickets/src/components/TicketingDashboard.category.contract.test.ts` to preserve dashboard filter wiring into `QuickAddCategory`, including board-context preselection and immediate category filter selection after create.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/TicketingDashboard.category.contract.test.ts -t T044`
- 2026-03-08 T045: Extended `TicketCategoryConsumer.contract.test.ts` to confirm `TicketDetails` inherits inline category creation via `TicketInfo`, passing through the live ticket and initial category context that `TicketInfo` uses for board-aware quick-add.
- Validation: `cd packages/tickets && npx vitest run --config vitest.config.ts src/components/ticket/__tests__/TicketCategoryConsumer.contract.test.ts -t T045`
- 2026-03-08 T046: Added a minimal root `jest.config.cjs` to ignore collision-heavy generated folders (`dist/`, `.ai/`, nested eslint-plugin package copies) and set `passWithNoTests`, then renamed the Vitest-only picker spec filenames so the PRDs Jest path-pattern command stops picking them up.
- Validation: `npx jest --testPathPattern='QuickAddTicket|ContactPicker|TicketProperties|ClientPicker|CategoryPicker'`