* fix: update routing form identifier hint text with learn more link
Co-Authored-By: carina@cal.com <c.wollendorfer@me.com>
* UI improvements
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
* feat: Add infrastructure for no-show audit integration
- Add Prisma migrations for SYSTEM source and NO_SHOW_UPDATED audit action
- Add NoShowUpdatedAuditActionService with array-based attendeesNoShow schema
- Update BookingAuditActionServiceRegistry to include NO_SHOW_UPDATED
- Update BookingAuditTaskConsumer and BookingAuditViewerService
- Add AttendeeRepository methods for no-show queries
- Update IAuditActionService interface with values array support
- Update locales with no-show audit translation keys
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: Add NO_SHOW_UPDATED to BookingAuditAction and SYSTEM to ActionSource types
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: Remove HOST_NO_SHOW_UPDATED and ATTENDEE_NO_SHOW_UPDATED from BookingAuditAction type to match Prisma schema
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: Update BookingAuditActionSchema to use NO_SHOW_UPDATED instead of HOST_NO_SHOW_UPDATED and ATTENDEE_NO_SHOW_UPDATED
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* refactor: Remove deprecated no-show audit services and unify to NoShowUpdatedAuditActionService
- Delete HostNoShowUpdatedAuditActionService and AttendeeNoShowUpdatedAuditActionService
- Update BookingAuditProducerService.interface.ts to use queueNoShowUpdatedAudit
- Update BookingAuditTaskerProducerService.ts to use queueNoShowUpdatedAudit
- Update BookingEventHandlerService.ts to use onNoShowUpdated
- Add integration tests for NoShowUpdatedAuditActionService
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: Add data migration step for deprecated no-show enum values
Addresses Cubic AI review feedback (confidence 9/10): The migration now
includes an UPDATE statement to convert existing records using the
deprecated 'host_no_show_updated' or 'attendee_no_show_updated' enum
values to the new unified 'no_show_updated' value before the type cast.
This prevents migration failures if any existing data uses the old values.
Co-Authored-By: unknown <>
* fix: Use CASE expression in USING clause for enum migration
Fixes PostgreSQL error 'unsafe use of new value of enum type' by avoiding
the ADD VALUE statement and instead using a CASE expression in the ALTER
TABLE USING clause to convert deprecated enum values (host_no_show_updated,
attendee_no_show_updated) to the new unified value (no_show_updated) during
the type conversion.
Co-Authored-By: unknown <>
* fix: Replace hardcoded color with semantic text-success class
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: Remove color class completely from display fields
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* feat: Add valuesWithParams support for translatable complex field values
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* refactor(booking-audit): use discriminated union for displayFields and update consumers
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: add explicit return type to getBookingHistoryHandler to bust stale tRPC build cache
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* refactor: replace $t() nested interpolation with separate translation keys and add translationsWithParams tests
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add keyboard shortcuts and tooltips to booking slideover buttons
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: remove duplicate useBookingLocation import and fix import ordering
- Removed duplicate import of useBookingLocation from non-existent
@calcom/web/modules/bookings/hooks/useBookingLocation path
- Fixed import ordering to satisfy biome organizeImports rules
- Removed unnecessary code comment
- Original feature by @PeerRich via Devin AI
Co-Authored-By: unknown <>
* use same style arrows for both button and remove bydefault focus from them
* fix join button tooltip hover
* fix: disable keyboard shortcuts when overlays/dialogs are open on BookingDetailsSheet
Co-Authored-By: unknown <>
* fix: use focus-based detection instead of selector-based overlay detection for keyboard shortcuts
Co-Authored-By: unknown <>
* fix: allow keyboard shortcuts when focus is on sheet ancestors
Co-Authored-By: unknown <>
* fix: use capture phase for keyboard handler to prevent Enter from activating focused buttons
Co-Authored-By: unknown <>
* fix: allow shortcuts when focus is on page elements outside any Radix portal
Co-Authored-By: unknown <>
* fix: handle calendar event clicks in onInteractOutside to prevent sheet close/reopen
Co-Authored-By: unknown <>
* fix: stop arrow key propagation to prevent Radix dropdown from opening during booking navigation
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: always stop arrow key propagation when sheet is active, even at first/last booking
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* refactor: extract keyboard handler into testable utility with tests
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: resolve type errors in keyboard handler config and test mocks
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* test: add e2e tests for booking sheet keyboard shortcuts
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: replace text= locators with data-testid selectors in e2e tests
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* made 3 fixes: Fix 1 — Stabilize handleNext/handlePrevious/handleClose with useCallback
In BookingDetailsSheet.tsx, all three handler functions were plain arrow functions recreated on every render, causing the useEffect to tear down and re-attach the document keydown listener unnecessarily. Wrapped all three in useCallback with proper dependency arrays (the Zustand store functions they call).
Fix 2 — data-booking-list-item verified (no change needed)
Confirmed that data-booking-list-item is rendered on BookingListItem.tsx and data-booking-calendar-event is rendered on Event.tsx. The onInteractOutside handler in the final merged state correctly checks both selectors. No code change required.
Fix 3 — Removed dead code from JoinMeetingButton
Reverted JoinMeetingButton back to a plain function component:
Removed forwardRef wrapping (no caller passes a ref)
Removed showTooltip prop (unused — tooltip is handled by the parent BookingDetailsSheet)
Removed ref prop from the inner Button
Removed unused Tod forwardRef imports
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Dhairyashil <dhairyashil10101010@gmail.com>
Co-authored-by: eunjae@cal.com <hey@eunjae.dev>
Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
* init
* wiring up
* fix type
* feat: implement DI pattern for webhook producer in API v2
- Export IWebhookProducerService and getWebhookProducer from platform-libraries
- Add WEBHOOK_PRODUCER token and useFactory provider in RegularBookingModule
- Inject webhookProducer in RegularBookingService and pass to base class
This follows the composition root pattern where only the NestJS module
knows about getWebhookProducer(), and all consumers depend only on the
IWebhookProducerService interface via constructor injection.
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
* test: migrate BOOKING_REQUESTED tests to new webhook architecture
- Remove failing BOOKING_REQUESTED tests from fresh-booking.test.ts (4 tests)
- Remove failing BOOKING_REQUESTED tests from reschedule.test.ts (2 tests)
- Remove failing BOOKING_REQUESTED test from collective-scheduling.test.ts (1 test)
- Replace WebhookTaskConsumer.test.ts with placeholder (constructor changed)
- Create new webhook architecture test suite:
- producer/WebhookTaskerProducerService.test.ts (14 tests)
- consumer/WebhookTaskConsumer.test.ts (8 tests)
- consumer/triggers/booking-requested.test.ts (8 tests)
The new test suite is organized by trigger type for extensibility as more
triggers are migrated to the producer/consumer pattern.
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
* test: remove paid events BOOKING_REQUESTED test (moved to new architecture)
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
* wrap webhook in own try-catch
* wire datafetcher
* fix
* fix v2
* fix circular dependency
* --
* merge-conflict-resolve
* mreg-conflict-resolve
* remove early return
* test: add integration tests for BOOKING_REQUESTED webhook producer invocation
Cover all 8 scenarios verifying the booking flow correctly invokes
the webhook producer for BOOKING_REQUESTED:
1. Basic confirmation → queueBookingRequestedWebhook called
2. Booker-is-organizer + confirmation → still called
3. Confirmation threshold NOT met → not called (BOOKING_CREATED instead)
4. Confirmation threshold IS met → called
5. Paid event + confirmation → called after payment succeeds
6. Reschedule + confirmation (non-organizer) → called (not BOOKING_RESCHEDULED)
7. Reschedule + confirmation (organizer) → not called (BOOKING_RESCHEDULED instead)
8. Collective scheduling + confirmation → called
Adds reusable MockWebhookProducer helper in @calcom/testing for
extendable use as more webhook triggers migrate to the new architecture.
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
* fix bug
* fix conditional check
* remove unnecessary comment
* add missing expect
* remove empty test
* clean up
* tasker config
* --
* fix missing metadata
* remove faulty if else
* test: add payload content verification tests for BOOKING_REQUESTED webhook
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
* remove unnecessary tests
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Hariom Balhara <1780212+hariombalhara@users.noreply.github.com>
* feat: replace admin API settings page with link to API docs
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* chore: remove unused AdminAPIView component
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* feat: rename admin API tab to API Docs
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add duplicate functionality for managed event types
Co-Authored-By: peer@cal.com <peer@cal.com>
* feat: add disclaimer and redirect for managed event type duplication
- Add info alert disclaimer in duplicate modal for managed event types
- Pass schedulingType to duplicate dialog via query params
- Redirect to assignment tab after duplicating managed event types
- Add translation key for managed event type duplicate disclaimer
Co-Authored-By: peer@cal.com <peer@cal.com>
* test: add tests for managed event type duplication
Co-Authored-By: peer@cal.com <peer@cal.com>
* refactor: replace PrismaMock unit test with Prisma integration test for duplicate handler (#27973)
* refactor: replace PrismaMock unit test with Prisma integration test for duplicate handler
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
* fix: re-throw TRPCErrors in duplicate handler catch block and assert specific error codes in tests
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Hariom Balhara <1780212+hariombalhara@users.noreply.github.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
* fix: allow booking rejection via GET for email clients that do not support forms
Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>
* Refactor test cases for GET handler in route.test.ts
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: decouple large calendar from features
* fix: move calendar to features since this is the better approach
* chore: move OOO slots to features
* feat: add DefaultOutOfOfficeSlot fallback for calendar OOO rendering
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* chore: cleanup unused LargeCalendar component
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Replaced dayjs with date-fns for better performance and consistency in date handling. Added Tooltip for displaying formatted timestamps and improved search functionality by translating field labels and values. Cleaned up code for better readability.
* fix: deep link reschedule audit log to booking drawer history tab
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: make booking drawer tab-agnostic for cross-tab deep links
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: use status-agnostic /bookings URL for audit log deep links
- Update audit service URLs from /bookings/upcoming?uid=... to /bookings?uid=...
- Add /bookings/page.tsx redirect that routes to /bookings/upcoming preserving query params
- Update tests to expect new URL format
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fixes
* refactor: use client-side replaceState instead of server redirect for booking deep links
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: use router.replace instead of replaceState to update tab and booking list
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* improvements
* refactor: extract deep link logic from BookingListContainer into usePreSelectedBooking hook
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: use proper BookingOutput status type in test helper
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: decouple getTabForBooking from BookingOutput type for simpler testing
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: accept Date | string for endTime in BookingForTabResolution interface
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* refactor: eliminate initialBookingUid prop drilling and revert formatting-only changes
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: use AuditDeepLink wrapper to preserve target=_blank through ServerTrans cloneElement
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* Improve code organization
* refactor: rename usePreSelectedBooking to useSwitchToCorrectStatusTab
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fix: push preSelectedBooking into store so drawer opens on direct navigation
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* fixes
* fixes
* fixes
* fix
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
* fix: revert assignmentReason breaking change in webhook payloads
Remove the new { category, details } format from EventPayloadType to
maintain backward compatibility for webhook consumers. The new format
is stripped at all webhook payload construction sites by destructuring
assignmentReason out of CalendarEvent before spreading into the payload.
A sanitizeAssignmentReasonForWebhook function provides an additional
safety net in sendPayload itself. Emails and booking single view
continue to use the new format via CalendarEvent.
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
* fix: strip assignmentReason from handlePaymentSuccess webhook payload
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
* fix: strip assignmentReason from triggerWebhooks and handleSeats webhook payloads
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
* refactor: use zod safeParse instead of type assertion in sanitizeAssignmentReasonForWebhook
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: enable onboarding-v3 globally and update e2e tests
- Add migration to set onboarding-v3 feature flag enabled=true
- Rewrite onboarding.e2e.ts for v3 flow (Plan Selection → Personal Settings → Calendar)
- Update URL assertions in signup, team-invitation, org-invitation, ab-tests-redirect, and auth tests to accept both old and new onboarding paths
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: use pathname-only matching in waitForURL to prevent false matches on callbackUrl query param
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* use test IDs
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
* feat: add signup watchlist review feature flag and handler logic
- Add 'signup-watchlist-review' global feature flag
- Add SIGNUP to WatchlistSource enum in Prisma schema
- When flag enabled, lock new signups and add email to watchlist
- Show 'account under review' message on signup page
- Add i18n strings for review UI
- Create seed migration for the feature flag
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* test: add isAccountUnderReview tests to fetchSignup test suite
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* fix: address Cubic AI review feedback (confidence >= 9/10)
- Remove 'import process from node:process' in signup-view.tsx (P0 bug in 'use client' component)
- Move watchlist review check before checkoutSessionId early return in calcomSignupHandler (P1 premium bypass)
- Revert selfHostedHandler to original state (out of scope per user request)
- Add test mocks for FeaturesRepository and GlobalWatchlistRepository
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* fix: remove node:process import from useFlags.ts (client-side file)
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* fix: remove !token condition from watchlist review check
Token is present in normal email-verified signups, so the !token
condition was incorrectly skipping watchlist review for verified users.
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* Apply suggestion from @cubic-dev-ai[bot]
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* refactor: move user lock to UserRepository.lockByEmail
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* refactor: use cached getFeatureRepository() instead of deprecated FeaturesRepository
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* refactor: remove user locking, keep only watchlist addition on signup review
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* feat: lock user on signup review, remove watchlist entry on unlock
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* fix: update data-table hook imports after refactor (#27833)
The data-table hooks (useDataTable, useFilterValue) were moved from
@calcom/features/data-table to ~/data-table/hooks/ in #27833 but this
file was missed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: update DataTableProvider import path in insights-wrong-routing-view
Another import missed in #27833 refactor — DataTableProvider moved from
@calcom/features/data-table/ to ~/data-table/.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* factory and statergie
* chore: use correct method of DI
* feat: add onchagne
* add logic to HWM stat
* add webhook resolver methods to each statergy
* move seat tracking + webhooks over to own statergy
* Move to factory base approach
* move logic to correct class
* rename create -> createByTeamId
* fix: remove debug `true ||` overrides from IS_STRIPE_ENABLED and IS_TEAM_BILLING_ENABLED
Remove accidentally committed debug overrides that short-circuited
IS_STRIPE_ENABLED and IS_TEAM_BILLING_ENABLED to always be true,
bypassing Stripe credential checks. This would break self-hosted
instances without Stripe configured.
Identified by cubic (https://cubic.dev)
Co-Authored-By: unknown <>
* feat: active user billing
* add tests
* UI side for users on active billing
* use correct period of stripe sub
* feat: claude feedback
* fix: skip Stripe sync for canceled/expired subscriptions to prevent repeated API calls
Co-Authored-By: unknown <>
* feat: feedback
* feat: only render when active users mode is set
* fix type error
* fix: constants + feature flags
* fix: default to null in tests
* chore: use seats in test
* fix: use node:crypto protocol for Node.js builtin imports
Co-Authored-By: sean@cal.com <Sean@brydon.io>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
## What does this PR do?
Fixes footer text overlap in the Booking Details drawer where action buttons covered the last content items on smaller screens.
**Root cause:** `sm:-my-6` on `SheetFooter` applied both negative top and bottom margins. The negative top margin pulled the footer up into the body content area, causing the overlap.
**Fix:**
- Removed `-mb-4` and `sm:-my-6` from `SheetFooter`, keeping only horizontal negative margins (`-mx-4` / `sm:-mx-6`) for edge-to-edge stretch
- Added `pb-0` to `SheetContent` to remove bottom padding so the footer sits flush at the bottom on all breakpoints
<img width="1098" height="1362" alt="image" src="https://github.com/user-attachments/assets/0418df56-a432-4edf-8e5b-664a5e8c18ac" />
- Fixes #XXXX (GitHub issue number)
- Fixes CAL-XXXX (Linear issue number - should be visible at the bottom of the GitHub issue description)
## Visual Demo (For contributors especially)
#### Image Demo (if applicable):
See screenshot above showing the overlap bug. The footer actions ("..." button) overlap with the last booking history entry.
## Mandatory Tasks (DO NOT REMOVE)
- [ ] I have self-reviewed the code (A decent size PR without self-review might be rejected).
- [ ] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). If N/A, write N/A here and check the checkbox.
- [ ] I confirm automated tests are in place that prove my fix is effective or that my feature works.
## How should this be tested?
1. Open any booking in the bookings list to open the details drawer
2. Scroll to the bottom of the drawer content
3. Verify the footer actions (buttons, dropdown) do not overlap with the last content item
4. Test on both mobile and desktop viewport sizes — footer should sit flush at the bottom with no extra gap on either
## Human Review Checklist
- [ ] Verify footer appearance on **mobile** (below `sm` breakpoint) — no gap below footer, no overlap with content
- [ ] Verify footer appearance on **desktop** (`sm+` breakpoint) — same checks
- [ ] Confirm the footer still stretches edge-to-edge horizontally on both breakpoints
## Checklist
- I haven't read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md)
- My code doesn't follow the style guidelines of this project
- I haven't commented my code, particularly in hard-to-understand areas
- I haven't checked if my changes generate no new warnings
- My PR is too large (>500 lines or >10 files) and should be split into smaller PRs
---
Link to Devin run: https://app.devin.ai/sessions/b9d130b8a7a54f039b90b53921b19c78
Requested by: @hariombalhara
* Add DB table for wrong assignment reports
* When report is submitted write to the db
* Prevent duplicate reportings
* test: add migration and tests for WrongAssignmentReport table
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: add unique constraint on bookingUid and booking access check for hasWrongAssignmentReport
- Add @unique constraint on bookingUid in WrongAssignmentReport model to prevent duplicate reports at DB level
- Add booking ownership check using BookingAccessService in hasWrongAssignmentReport endpoint
- Refactor hasWrongAssignmentReport into separate handler and schema files
Addresses Cubic AI review feedback on PR #27405
Co-Authored-By: unknown <>
* feat: add routingFormId to WrongAssignmentReport and fix Select clearing
- Add routingFormId field to WrongAssignmentReport model in schema.prisma
- Add relation to App_RoutingForms_Form with SetNull on delete
- Update WrongAssignmentReportRepository.createReport to accept routingFormId
- Update BookingRepository.findByUidIncludeEventTypeAndTeamAndAssignmentReason to include routedFromRoutingFormReponse
- Extract routingFormId from booking in reportWrongAssignment handler
- Fix Select clearing issue: handle null case when user clears team member selection
- Update tests to include routingFormId field
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* chore: add migration for routingFormId in WrongAssignmentReport
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* feat: add wrong assignment reports dashboard under routing tab
- Add reviewedById and reviewedAt fields to WrongAssignmentReport model
- Add repository methods for listing reports by status and updating status
- Create tRPC endpoints for fetching reports and updating status
- Create dashboard UI with pending/reviewed tabs showing routing form name
- Add translation keys for dashboard UI
- Integrate dashboard into routing insights page
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: move hooks before early return and fix indentation
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: address Udit's review comments
- hasWrongAssignmentReport: throw UNAUTHORIZED error instead of returning false
- reportWrongAssignment: add try-catch for Prisma P2002 unique constraint error
- WrongAssignmentReport: add Team relation to teamId field
- WrongAssignmentReportRepository: use findUnique instead of findFirst
- reportWrongAssignment: use i18n for error messages
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: revert hasWrongAssignmentReport to return false when user lacks access
Per PR checklist, hasWrongAssignmentReport should return { hasReport: false }
when user lacks access to booking, not throw an error. This allows the UI
to gracefully treat 'no access' as 'no report exists'.
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* test: update mocks for findUnique and i18n in unit tests
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: throw UNAUTHORIZED in hasWrongAssignmentReport and squash migrations
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* feat: move wrong assignment reports to its own tab under Insights
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Use data table for wrong reports
* Add option to view routing trace
* feat: add view routing form submission action to wrong assignment reports
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* feat: add RoutingFormResponseSheet component for viewing form submissions
- Create slide-out sheet to display routing form responses
- Map option IDs to display labels for select/multiselect fields
- Handle both legacy and modern option formats
- Add i18n strings: form_submission, no_responses_found
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: improve wrong assignment reports UX
- Integrate RoutingFormResponseSheet as slide-out panel instead of new tab
- Fix dropdown padding by using StartIcon prop instead of manual Icon
- Allow direct status changes for reviewed reports (no need to reopen first)
- Remove unused Icon import
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: change User relation onDelete from Cascade to SetNull in WrongAssignmentReport
Address Hariom's review feedback:
- Changed reportedById from Int to Int? (nullable)
- Changed reportedBy relation from onDelete: Cascade to onDelete: SetNull
- Updated migration SQL to reflect these changes
This preserves wrong assignment reports even when the reporting user is deleted,
as the data is still useful for analysis.
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* feat: add missing i18n strings for wrong assignment reports dashboard
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* refactor: move form response display value resolution server-side
Replace client-side option ID to label resolution in
RoutingFormResponseSheet with a new lean tRPC endpoint
(getFormResponseDisplay) that resolves values server-side using
the existing getHumanReadableFieldResponseValue utility. This
enforces DTO boundaries by returning a clean pre-resolved payload
instead of leaking internal option format details to the client.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add report wrong assignment button to routing trace sheet
Wire up the WrongAssignmentDialog from the routing trace sheet header
so users can flag wrong assignments directly while viewing the trace.
The report button is disabled with a tooltip when a report already
exists.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: reuse existing WrongAssignmentDialog from parent
Replace the duplicate WrongAssignmentDialog in RoutingTraceSheet with
a callback to the existing instance in BookingActionsDropdown. This
reduces the prop surface from a 6-field reportContext object to an
onReport callback and hasExistingReport boolean.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: use repository instead of direct Prisma in getFormResponseDisplay
Replace direct Prisma query with PrismaRoutingFormResponseRepository's
findByIdIncludeForm method. Extend the method to also select form name,
description, userId, and teamId needed for display and auth checks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: replace direct Prisma calls with repository methods
Use MembershipRepository.hasMembership() for auth checks and
TeamRepository.findAllByParentId() for child team queries instead
of direct Prisma calls. Replace direct user query with
UserRepository.getTimeZoneAndDefaultScheduleId(). Remove unused
seed script.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: use PBAC services for wrong assignment report auth
Replace manual MembershipRepository.hasMembership() checks with
PBAC-aware permission checking. getWrongAssignmentReports uses
createTeamPbacProcedure middleware since teamId is in input.
updateWrongAssignmentReportStatus uses PermissionCheckService
directly since teamId is discovered from the report entity.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve type errors in RoutingFormResponseSheet and wrong-routing view
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* feat: add seed script for wrong assignment reports test data
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* Revert "feat: add seed script for wrong assignment reports test data"
This reverts commit 0bd60e9661858a59aab1573d14d57d81733b7991.
* Only update reviewed fields when not pending
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* refactor: wrap handleStatusChange in useCallback to fix useMemo recalculation
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Fix routing sheet UI
* fix: use appropriate error message in getFormResponseDisplay handler
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* refactor: extract WrongAssignmentReportService from tRPC handlers
Move business logic (booking lookup, duplicate check, report creation,
webhook dispatch, org-level team resolution) into a dedicated service
in packages/features. Handlers become thin controllers that only handle
auth checks and delegate to the service.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: restrict report status updates to admin/owner roles
Remove MembershipRole.MEMBER from fallbackRoles in
updateWrongAssignmentReportStatus permission check. Updating report
status is an administrative action that should be limited to team
admins and owners.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: localize hard-coded success message in WrongAssignmentReportService
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: rename reviewed tab to handled and add missing translations
Rename the "Reviewed" tab to "Handled" since it groups three distinct
statuses (Reviewed, Resolved, Dismissed). Also add missing translation
keys for "resolved" and "dismissed" status badges.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* merge: resolve conflicts with main branch
Merge main into devin/1769747741-wrong-assignment-dashboard, resolving conflicts in:
- BookingActionsDropdown.tsx: use main's booking prop with PR's fragment structure
- reportWrongAssignment.handler.ts: keep PR's service-based approach
- reportWrongAssignment.handler.test.ts: use main's class-based mocks with PR's additions
- WrongAssignmentReportService.ts: align with main's repo method and field names
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* Add guard when accessing assignmentReasonSortedByCreatedAt
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* fix: address Cubic AI review feedback - select projection and useLocale refactor
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* fix: remove stale TRPCError assertion in test (service throws ErrorWithCode)
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* refactor: remove unused findByTeamIdAndStatus and findByTeamIdAndStatuses methods
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* perf: add composite index on WrongAssignmentReport and narrow findByIdIncludeForm select
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* perf: use lightweight findTeamIdById in update-status handler instead of findById
Co-Authored-By: alex@cal.com <me@alexvanandel.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@cal.com <hariombalhara@gmail.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: alex@cal.com <me@alexvanandel.com>