* feat: add no users found fallback action for routing forms
- Add NoUsersFoundFallbackActionType enum with CustomPageMessage and ExternalRedirectUrl options
- Add noUsersFoundFallbackAction field to zodNonRouterRoute schema
- Add NoUsersFoundFallback UI component in RouteBuilder for configuring fallback action
- Update handleResponse to return noUsersFoundFallbackAction when no team members match
- Add i18n translation keys for new UI strings
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* refactor: change fallback to use same action options as main route
- Replace noUsersFoundFallbackAction with fallbackAction that has same structure as main action
- Add action dropdown and input fields to fallback attributes query builder section
- Support Event redirect, External URL, and Custom page options in fallback
- Remove separate NoUsersFoundFallback toggle component
- Update handleResponse to return fallbackAction
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: ensure fallbackAction type is always defined in onChange handlers
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: add guards for route.fallbackAction in onChange handlers
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: only return fallbackAction when no users are found
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* refactor: restructure fallback section to mirror main route structure
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: ensure backwards compatibility for existing routes with fallbackAttributesQueryValue
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: initialize fallbackAction with main event type for backwards compatibility
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: include fallbackAction in getRoutesToSave to persist changes
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: use fallbackAction in getRoutedUrl when no team members found
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: use i18n for fallback label and add tests for fallback action
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: do not trigger fallback action when CRM contact owner is found
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: prioritize fallbackAction over fallbackAttributesQueryValue
When a route has a fallbackAction configured, skip the
fallbackAttributesQueryValue to ensure the fallbackAction is triggered
when no team members are found. This maintains backwards compatibility
by only using fallbackAttributesQueryValue when fallbackAction is not set.
Also treats teamMemberIdsMatchingAttributeLogic being null (routing couldn't
run, e.g., missing orgId) the same as an empty array for the purpose of
triggering the fallbackAction.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: extract RouteActionSelector shared component for action selection UI
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: add i18n string for default custom page message
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* feat: add webhook trigger when routing form fallback route is hit
- Add ROUTING_FORM_FALLBACK_HIT to WebhookTriggerEvents enum in Prisma schema
- Add new trigger to routing-forms webhook triggers in constants
- Add translation string for the new webhook trigger
- Implement triggerFallbackWebhook function in formSubmissionUtils.ts
- Call webhook trigger from handleResponse.ts when fallback action is used
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: remove webhook object from error log to avoid exposing secrets
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* revert: remove webhook trigger changes (to be moved to separate PR)
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* feat: add webhook trigger when routing form fallback route is hit
- Add ROUTING_FORM_FALLBACK_HIT to WebhookTriggerEvents enum in Prisma schema
- Add new trigger to routing-forms webhook triggers in constants
- Add translation string for the new webhook trigger
- Implement triggerFallbackWebhook function in formSubmissionUtils.ts
- Call webhook trigger from handleResponse.ts when fallback action is used
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: remove webhook object from error log to avoid exposing secrets
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: add ROUTING_FORM_FALLBACK_HIT to PayloadBuilderFactory trigger mapping
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* style: apply biome formatting fixes
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: restore removed comments in RouteBuilder
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* chore: add prisma migration for ROUTING_FORM_FALLBACK_HIT enum value
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: add ROUTING_FORM_FALLBACK_HIT to FormTriggerEvents type union
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* test: add test coverage for triggerFallbackWebhook function
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* refactor: consolidate fallback webhook firing with form submission webhooks
Move ROUTING_FORM_FALLBACK_HIT webhooks into the same Promise.all() batch
as FORM_SUBMITTED / FORM_SUBMITTED_NO_EVENT, eliminating redundant
getWebhooks/getWebhookTargetEntity/getOrgIdFromMemberOrTeamId calls.
- Add fallbackAction parameter to _onFormSubmission and onSubmissionOfFormResponse
- Remove triggerFallbackWebhook function and all its usages/imports
- Move getFallbackAction() earlier in handleResponse.ts and pass result through
- Update all tests to verify batched webhook behavior
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Add UI option for trigger
* feat: persist fallbackAction on queued form responses
When a routing form response is queued, the fallbackAction determined
during routing is now stored on the QueuedFormResponse record. When
the queued response is later converted to a real FormResponse, the
stored fallbackAction is passed to onSubmissionOfFormResponse so the
ROUTING_FORM_FALLBACK_HIT webhook fires correctly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add coverage for fallbackAction in queued form response flow
Verify that fallbackAction is persisted when queuing and passed through
to onSubmissionOfFormResponse when the queued response is converted.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add no users found fallback action for routing forms
- Add NoUsersFoundFallbackActionType enum with CustomPageMessage and ExternalRedirectUrl options
- Add noUsersFoundFallbackAction field to zodNonRouterRoute schema
- Add NoUsersFoundFallback UI component in RouteBuilder for configuring fallback action
- Update handleResponse to return noUsersFoundFallbackAction when no team members match
- Add i18n translation keys for new UI strings
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* refactor: change fallback to use same action options as main route
- Replace noUsersFoundFallbackAction with fallbackAction that has same structure as main action
- Add action dropdown and input fields to fallback attributes query builder section
- Support Event redirect, External URL, and Custom page options in fallback
- Remove separate NoUsersFoundFallback toggle component
- Update handleResponse to return fallbackAction
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: ensure fallbackAction type is always defined in onChange handlers
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: add guards for route.fallbackAction in onChange handlers
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: only return fallbackAction when no users are found
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* refactor: restructure fallback section to mirror main route structure
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: ensure backwards compatibility for existing routes with fallbackAttributesQueryValue
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: initialize fallbackAction with main event type for backwards compatibility
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: include fallbackAction in getRoutesToSave to persist changes
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: use fallbackAction in getRoutedUrl when no team members found
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: use i18n for fallback label and add tests for fallback action
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: do not trigger fallback action when CRM contact owner is found
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: prioritize fallbackAction over fallbackAttributesQueryValue
When a route has a fallbackAction configured, skip the
fallbackAttributesQueryValue to ensure the fallbackAction is triggered
when no team members are found. This maintains backwards compatibility
by only using fallbackAttributesQueryValue when fallbackAction is not set.
Also treats teamMemberIdsMatchingAttributeLogic being null (routing couldn't
run, e.g., missing orgId) the same as an empty array for the purpose of
triggering the fallbackAction.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: extract RouteActionSelector shared component for action selection UI
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: add i18n string for default custom page message
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* feat: add webhook trigger when routing form fallback route is hit
- Add ROUTING_FORM_FALLBACK_HIT to WebhookTriggerEvents enum in Prisma schema
- Add new trigger to routing-forms webhook triggers in constants
- Add translation string for the new webhook trigger
- Implement triggerFallbackWebhook function in formSubmissionUtils.ts
- Call webhook trigger from handleResponse.ts when fallback action is used
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: remove webhook object from error log to avoid exposing secrets
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* revert: remove webhook trigger changes (to be moved to separate PR)
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: only show fallback query builder when fallbackAction is explicitly set
The fallback attributes query builder was being shown for new routes
when fallbackAction was not set, causing an extra 'Add rule' button
to appear. This broke e2e tests that relied on the button index.
Now the fallback query builder is only shown when fallbackAction is
explicitly set to EventTypeRedirectUrl, which happens after the route
is saved and reloaded (via auto-initialization in useRoutes).
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: use data-testid for attribute query builder selectors in e2e tests
- Add data-testid='attributes-query-builder' to the main attributes query builder div
- Update addAttributeRoutingRule and addAttributeRoutingRuleWithOperator to use the data-testid selector instead of nth() indices
- This makes the tests more robust and independent of DOM structure changes
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: initialize fallbackAction for new routes in useCreateRoute hook
- New routes created via useCreateRoute now initialize fallbackAction
- This ensures new routes have a valid fallbackAction when saved
- Matches the initialization logic for existing routes in useRoutes
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: initialize fallbackAction at save time when action is EventTypeRedirectUrl
- When saving routes, if fallbackAction is undefined but action is EventTypeRedirectUrl,
initialize fallbackAction from the main action
- This handles the case where user creates a new route and changes action to an event type
- Fixes e2e test failures where form save was failing due to undefined fallbackAction
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: initialize fallbackAction when main action changes to EventTypeRedirectUrl
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: only show fallback section when main action has valid event type selected
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: check for valid fallbackAction event type before preserving existing value
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Give more structure to main and fallback routes
* Update comment
* Rename fallbackAttributesQueryBuilder to matchingMembersFallbackRoute
* Display custom event redirect input
* fix: address Cubic AI review feedback for routing form fallback
- Simplify getFallbackAction logic to use checkedFallback flag instead of
manually parsing attributesQueryValue (confidence 9/10)
- Add i18n translation for 'And connect with specific team members' string
using t('connect_with_specific_team_members') (confidence 9/10)
Co-Authored-By: unknown <>
* fix: update getFallbackAction to use checkedFallback and handle missing orgId case
- Use checkedFallback flag as primary indicator for triggering fallback action
- Also handle edge case where attribute routing was configured but couldn't run
due to missing orgId (teamMemberIdsMatchingAttributeLogic is null)
- Update test to mock checkedFallback: true when expecting fallback action
Co-Authored-By: unknown <>
* Address UI comment
* fix: Use fallbackAttributesQueryValue when fallback action is event redirect
Only use fallbackAttributesQueryValue when:
1. fallbackAction is EventTypeRedirectUrl (attribute routing applies)
2. fallbackAction is not set (backwards compatibility)
Skip it for CustomPageMessage and ExternalRedirectUrl fallback actions
since attribute routing doesn't apply to those action types.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: correct JSX syntax error in matchingMembersFallbackRoute
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* refactor: extract getCustomSlug helper to deduplicate custom event type slug logic
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: only show fallback attribute filtering for teams under orgs
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: show fallback action for all team forms, gate attribute filtering on isOrganization
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
* feat: create BookingHistoryViewerService to combine audit logs with routing form submissions
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* refactor(booking): rename audit log query and enhance type safety
- Updated the booking logs view to use the new getBookingHistory query instead of getAuditLogs.
- Introduced DisplayBookingAuditLog type for improved clarity in BookingAuditViewerService.
- Refactored BookingHistoryViewerService to utilize the new DisplayBookingAuditLog type and added sorting functionality for history logs.
- Adjusted related types and methods to ensure consistency across services.
* refactor(routing-forms): streamline imports and enhance type definitions
- Consolidated type exports and imports from the features library for better organization.
- Removed redundant type definitions and functions in zod.ts, findFieldValueByIdentifier.ts, getFieldIdentifier.ts, and parseRoutingFormResponse.ts.
- Introduced new utility functions for handling field responses and parsing routing form responses.
- Improved type safety and clarity across routing form response handling.
* fix: remove double prefix from uniqueId in form submission entry
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* 1c97f9cc5d50416788c01876fe539bcc9750e9b2 (#26453)
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* perf: add z.ZodType annotations to high-impact schemas
Add explicit type annotations to reduce TypeScript type inference overhead
and .d.ts file bloat in the tRPC package.
Changes:
- packages/prisma/zod-utils.ts: Add EventTypeLocation type and annotate eventTypeLocations schema
- packages/features/eventtypes/lib/schemas.ts: Add TEventTypeDuplicateInput and TCreateEventTypeInput types with annotations
- packages/app-store/routing-forms/zod.ts: Add FieldOption, TNonRouterField, TRouterField, TField, TFields types with annotations for zodField and zodFields
These schemas feed into multiple tRPC routers and were identified as high-impact
targets for reducing type checking time and declaration file sizes.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: replace z.infer with explicit types and define EventTypeLocation locally
Address PR feedback:
- Replace z.infer<typeof calVideoSettingsSchema> with explicit CalVideoSettings type
- Define EventTypeLocation type locally instead of importing from prisma
- Add z.ZodType annotation to calVideoSettingsSchema
Note: Still importing Zod schemas from @calcom/prisma/zod-utils for validation.
Awaiting guidance on whether to move those to @calcom/lib.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* wip
* Add preview mode in router
* only fetch bookings of this month for weighted rr
* test set up
* only get bookings of current month
* reverts test setup
* first changes for weight adjustments
* reset booking count + adjust calibration
* depreciate weightAdjustment
* get only bookings created this month
* fix typo
* make sure createdAt for hosts is correct
* use earliest possibel date as fallback
* add missing createdAt date to tests
* fix typo
* clean up changes in tests
* fix typo
* change end date to current date
* fix: Fall back to empty host array when no hosts are found
* fix: Restructure code a little
* fixed test, incorrectly used now outdated var
* perf: remove Dayjs from getLuckyUser
* Refactor getHostsWithCalibration for optimised performance, intentionally break test as findMany is always an array
* Better mock for host.findMany
* Remove team-event-types.test.ts, move to appropriate package
* TypeScript cannot auto-infer that an array is non-empty when assigning to a var
* fix: Type Fixes and DistributionMethod enum add
* Optimise tests
* Added test to show that bookings made before a newHost was added affect the lucky user result
* Throw error when the usersWithHighestPriority is empty, which should never happen
* WIP
* remove comment
* update migrations
* get attributes weights and virtual queue data
* use attribute weights and use bookings of virtual queue only
* clean up migrations
* Add shortfall column and add tests
* code clean up from feedback
* wrapper function for getLuckyUser
* code clean up
* fetch routingFormResponse in handleNewBooking
* fix type errors
* fix type errors in tests
* fix getAttributesQueryValue import for tests
* fix totalWeight
* add test for attributes weights and virtual queues
* clean up code
* add test for prepareQueuesAndAttributesData
* remove console.log
* use lazy import
* Add more tests and more columns to matching members queue
* fix issue from merge
* always send usersAndTheirBookingShortfalls
---------
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
* only fetch bookings of this month for weighted rr
* test set up
* only get bookings of current month
* reverts test setup
* first changes for weight adjustments
* reset booking count + adjust calibration
* depreciate weightAdjustment
* get only bookings created this month
* fix typo
* make sure createdAt for hosts is correct
* use earliest possibel date as fallback
* add missing createdAt date to tests
* fix typo
* clean up changes in tests
* fix typo
* change end date to current date
* fix: Fall back to empty host array when no hosts are found
* fix: Restructure code a little
* fixed test, incorrectly used now outdated var
* perf: remove Dayjs from getLuckyUser
* Refactor getHostsWithCalibration for optimised performance, intentionally break test as findMany is always an array
* Better mock for host.findMany
* Remove team-event-types.test.ts, move to appropriate package
* TypeScript cannot auto-infer that an array is non-empty when assigning to a var
* fix: Type Fixes and DistributionMethod enum add
* Optimise tests
* Added test to show that bookings made before a newHost was added affect the lucky user result
* Throw error when the usersWithHighestPriority is empty, which should never happen
* WIP
* remove comment
* update migrations
* get attributes weights and virtual queue data
* use attribute weights and use bookings of virtual queue only
* clean up migrations
* code clean up from feedback
* wrapper function for getLuckyUser
* code clean up
* fetch routingFormResponse in handleNewBooking
* fix type errors
* fix type errors in tests
* fix getAttributesQueryValue import for tests
* fix totalWeight
* add test for attributes weights and virtual queues
* clean up code
* add test for prepareQueuesAndAttributesData
* remove console.log
* use lazy import
* use findUnique
* add fallback weight
---------
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
* move types to types file
* Create salesforce routing form components
* Save salesforce data to routing form
* Fixes
* Add event type service
* Change commenting
* Pass data from routing form to CRM
* Init Salesforce routing form booking form handler
* Salesforce find user associated with lookup field
* Add looking up the contact owner
* If salesforce is disabled then don't change the Salesforce option
* Small refactor
* Refactor getting event type app metadata
* Refactor eventType service
* Type fix
* Clean up
* Add translations
Co-authored-by: Alex van Andel <emrysal@users.noreply.github.com>
---------
Co-authored-by: Alex van Andel <emrysal@users.noreply.github.com>
* Add fallback
* Support attribute query fallback
* Refactor
* Add tests and cleanup SingleFofrm
* small text fixes
* With fallback in picture, we dont throw error in preview now instead we capture errors and show them gracefully
* Get attribute logic preview working without saving Fixes CAL-4582
* Abstract useRoutes out
* Update e2e
* Dont define Page component again and again
---------
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
* POC working with no TS error
* cleanup
* Fix query booking
* Simplify things
* Support rerouting to different event
* self-review fixes
* Some improvements
* add more tests
* Remove members relation query
* Udits feedback
* Dont show CTAs when non-eventTypeRedirectUrl action route is chosen
---------
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
* Add handlePaste function and integrate it with options fields
* Prevents function running if user does not paste a list, allows list items to be pasted without deleting following items
* Subs useState for rhf useWatch to fix issues with multiple form fields
* Sets options array as optional property in zod schema
* Assigns default value to options array to fix possibly undefined type errors
* Sets placedholder property as optional
* maps selectText to options on mount
* Removes comma & semicolon delimiting for pasted lists (new line only) & defines regex as a constant
* Sets default value of placeholder to empty string, provides default fallback for component text field if placeholder is omitted.
* Fix type error on placeholder
* Extracts handlePaste to service function & tests thoroughly
* Some improvements and tests arent needed
* More fixes
* Fix reporting as well
* TS fixes
* Do transforms to and fro from label
* Add unit tests
* Unit test reporting
* Test Improvements
* Self review feedback addressed
---------
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>