5b88eefed453608617d65f4173c024cd41acd2e8
100
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
51e902f03e |
chore: pause syncing rules to devin (#28041)
* chore: pause syncing rules to devin * Revert "chore: pause syncing rules to devin" This reverts commit dd0e55322fe079b62207c9a4b58c9d24ce1c0dda. * disable temporarily |
||
|
|
21d28c9747 |
refactor: apply biome formatting to packages/trpc (#27928)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
896dfd50fd |
fix: prevent BookingDetailsSheet flicker when switching bookings (#27894)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
e2119879ae |
refactor: apply biome formatting to packages/sms, prisma, emails, lib (#27880)
* refactor: apply biome formatting to small packages + packages/lib Format packages/sms, packages/prisma, packages/platform/libraries, packages/platform/examples, packages/platform/types, packages/emails, and packages/lib. Excludes packages/platform/examples/base/src/pages/[bookingUid].tsx due to pre-existing lint errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * revert: remove packages/platform formatting changes Revert biome formatting for packages/platform as requested. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
1b6b91b0ad |
fix: display phone numbers and localized timezone in BookingDetailsSheet (#27909)
* fix: display phone numbers and localized timezone in BookingDetailsSheet Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: replace selectAll with explicit column selects for Attendee query Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * Update apps/web/modules/bookings/components/BookingDetailsSheet.tsx Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * Add tests: packages/lib/dayjs/formatToLocalizedTimezone.test.ts Generated by Paragon from proposal for PR #27909 * Revert "refactor: replace selectAll with explicit column selects for Attendee query" This reverts commit f810ba801c900c8f065e5e1ce1d02a1700322257. --------- 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> |
||
|
|
1bb4b206c6 |
fix: default icon size to 16px in createIcon wrapper and fix download button alignment (#27924)
* fix: resolve insights page UI regressions for plus button size and download alignment Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: default icon size to 16px in createIcon wrapper Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
f8abce44cb |
fix: update data-table hook imports missed in #27833 refactor (#27900)
* 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> |
||
|
|
1368ffe55d |
refactor: move data-table hooks/contexts/provider from features to web modules (#27833)
* refactor: move data-table hooks/contexts/provider from features to web modules Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: update broken useColumnResizing import path in DataTable.tsx Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: update remaining broken import paths for moved hooks Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: update GUIDE.md import paths and file references for moved modules Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
bf348ee209 |
refactor: migrate Icon to component icons from @coss/ui/icons (#27458)
* feat: add @coss/ui/icons package and migrate static icon usages
Create a new icon system in @coss/ui/icons that wraps lucide-react icons
with controlled props (size and className only). Migrate 44 component
files from <Icon name="xxx" /> to <XxxIcon /> pattern.
This is Phase 1 of the icon migration, covering only static icon names.
Dynamic icon usages (e.g., name={variable}) are skipped for now.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate more static icons to @coss/ui/icons (batch 2)
Migrated 18 files from <Icon name="xxx" /> to <XxxIcon /> pattern:
- Event meta, insights, shell, user table bulk actions
- Webhooks, blocklist, form-builder, form components
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate more static icons to @coss/ui/icons (batch 3)
Migrated 7 files:
- CancelBooking, AddGuestsDialog, ChargeCardDialog
- ReassignDialog, RescheduleDialog
- Categories, Slider
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate more static icons to @coss/ui/icons (batch 4)
Migrated 6 files:
- Organizations: AboutOrganizationForm, PaymentStatusView, profile
- Workflows: CallDetailsSheet, SkeletonLoaderList, TimeTimeUnitInput
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate more static icons to @coss/ui/icons (batch 5)
Migrated 4 files:
- TwoFactorModalHeader
- App setups: alby, make, btcpayserver
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static icons to @coss/ui/icons (batch 6)
- confirmDialog.tsx: clock icon
- ics-feedcalendar/Setup.tsx: trash, plus icons
- hitpay/Setup.tsx: info icon
- paypal/Setup.tsx: circle-alert icons
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static icons to @coss/ui/icons (batch 7)
- webhook-edit-view.tsx: external-link icon
- webhook-new-view.tsx: external-link icon
- UserDropdown.tsx: chevron-down, user, settings, moon, map, circle-help, download, blocks, log-out icons
- TopNav.tsx: settings icon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static icons to @coss/ui/icons (batch 8)
- EmailInviteForm.tsx: x icon
- InviteOptions.tsx: mail, upload, link icons
- SkeletonLoader.tsx: search, clock, user icons
- Embed.tsx: sun, arrow-left icons
- CalendarSwitch.tsx: arrow-left, rotate-cw icons
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static icons to @coss/ui/icons (batch 9)
- apps-view.tsx: search icon
- categories-view.tsx: arrow-left, arrow-right icons
- DatePicker.tsx: calendar icon
- EditLocationDialog.tsx: map-pin icon
- AppPage.tsx: circle-alert, book-open, external-link, mail, file, shield, flag icons
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static icons to @coss/ui/icons (batch 10)
- LicenseSelection.tsx: loader, check icons
- AppConnectionItem.tsx: circle-alert, arrow-right icons
- oauth-client-form/index.tsx: info icons (x2)
- auth/error/page.tsx: x icon
- troubleshoot/layout.tsx: loader icon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static icons to @coss/ui/icons (batch 11)
- UpgradeTipWrapper.tsx: users, refresh-ccw, user-plus icons
- PbacOptInModal.tsx: shield-check, lock, users, shield icons
- AdvancedPermissionGroup.tsx: chevron-right, info icons
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static icons to @coss/ui/icons (batch 12)
- AdminAppsList.tsx: pencil icon
- AvailableTimes.tsx: calendar-x-2 icon
- BookingDetailsSheet.tsx: external-link (x2), repeat icons
- BookingCalendarContainer.tsx: chevron-left, chevron-right icons
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static icons to @coss/ui/icons (batch 13)
- videos-single-view.tsx: chevron-right icon
- TroubleshooterSidebar.tsx: arrow-left icon
- RuleBuilder.tsx: filter icon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static icons to @coss/ui/icons (batch 14)
- FieldMappingBuilder.tsx: arrow-right, link icons
- IntegrationAttributeSyncCard.tsx: key icon
- onboarding-view.tsx: loader icon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static icons to @coss/ui/icons (batch 15)
- team-profile-view.tsx: copy icon
- DateRangeFilter.tsx: check icon
- ColumnVisibilityButton.tsx: check icon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static Icon to @coss/ui/icons (batch 16)
- EventWorkflowsTab.tsx: lock
- event-types-listing-view.tsx: search
- onboarding-migrate-members-browser-view.tsx: arrow-left, arrow-right, rotate-cw, lock, ellipsis-vertical, check, user-plus
- onboarding-migrate-teams-browser-view.tsx: arrow-left, arrow-right, rotate-cw, lock, ellipsis-vertical, check, arrow-right, users
- EventAvailabilityTab.tsx: globe, user
- onboarding-teams-browser-view.tsx: arrow-left, arrow-right, rotate-cw, lock, ellipsis-vertical, check, arrow-right, users
- FormBuilder.tsx: mail, phone, arrow-up, arrow-down
- AIEventController.tsx: info
- EventTeamAssignmentTab.tsx: x
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static Icon to @coss/ui/icons (batch 17)
- EventAdvancedTab.tsx: pencil, info
- HostLocations.tsx: triangle-alert, loader
- EventTypeLayout.tsx: loader
- Locations.tsx: x, corner-down-right, check
- EditWeightsForAllTeamMembers.tsx: upload, search, info, chevron-down
- WorkflowPage.tsx: pencil
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static Icon to @coss/ui/icons (batch 18)
- TestPhoneCallDialog.tsx: phone
- WorkflowListPage.tsx: link
- UsersTable.tsx: building, lock
- TeamList.tsx: building, paintbrush, chart-line, user-plus, users, pencil
- bookings-single-view.tsx: chevron-left, check, calendar, x, external-link
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate static Icon to @coss/ui/icons (batch 19)
- TeamsListing.tsx: users, refresh-ccw, user-plus, mail, video, eye-off, info
- ConnectionInfo.tsx: clipboard
- IntercomContactForm.tsx: message-circle, loader, send
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: migrate static Icon to @coss/ui/icons in teams components
- EventTypesList.tsx: check → CheckIcon
- MemberInvitationModal.tsx: user, users, building → UserIcon, UsersIcon, BuildingIcon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: migrate static Icon to @coss/ui/icons in workflow components
- ImportNumberDialog.tsx: info → InfoIcon
- VoiceSelector.tsx: user → UserIcon
- IncomingCallsTab.tsx: info, phone-incoming → InfoIcon, PhoneIncomingIcon
- PhoneNumberTab.tsx: loader, phone → LoaderIcon, PhoneIcon
- VoiceSelectionDialog.tsx: pause, play, user → PauseIcon, PlayIcon, UserIcon
- WebCallDialog.tsx: loader, phone, phone-off, triangle-alert, trash, message-circle → new icons (kept Icon import for dynamic mic icon)
- WorkflowDetailsPage.tsx: zap, arrow-right → ZapIcon, ArrowRightIcon
- AddActionDialog.tsx: info → InfoIcon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: migrate static Icon to @coss/ui/icons in WorkflowStepContainer
- info → InfoIcon (2 instances)
- phone → PhoneIcon (2 instances)
- circle-help → CircleHelpIcon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: migrate static Icon to @coss/ui/icons in data-table and org components
- attributes-list-view.tsx: tags → TagsIcon
- AddFilterButton.tsx: plus, eye-off → PlusIcon, EyeOffIcon
- BaseSelectFilterOptions.tsx: check → CheckIcon
- DataTable.tsx: arrow-up, arrow-down, check, chevrons-up-down, eye-off → new icons
- booking-dry-run-success-view.tsx: check → CheckIcon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: migrate static Icon to @coss/ui/icons in username and routing components
- UsernameTextfield.tsx: check → CheckIcon
- PremiumTextfield.tsx: check, external-link → CheckIcon, ExternalLinkIcon (kept Icon for star with fill prop)
- Header.tsx (routing-forms): pencil, menu, waypoints → PencilIcon, MenuIcon, WaypointsIcon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate Icon to component icons in routing-forms pages
Batch 25: Migrate static Icon usages to @coss/ui/icons components.
Files changed:
- Forms.tsx: file-text, shuffle, chart-bar, circle-check, mail, download → FileTextIcon, ShuffleIcon, ChartBarIcon, CircleCheckIcon, MailIcon, DownloadIcon
- FormEdit.tsx: chevron-down, menu → ChevronDownIcon, MenuIcon
- IncompleteBooking.tsx: globe → GlobeIcon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate Icon to component icons in UI package
Batch 26: Migrate static Icon usages to @coss/ui/icons components.
Files changed:
- ProgressToast.tsx: file-down, x → FileDownIcon, XIcon
- showToast.tsx: check, info, x → CheckIcon, InfoIcon, XIcon
- InfoBadge.tsx: info → InfoIcon
- MeetingTimeInTimezones.tsx: globe → GlobeIcon
- InputError.tsx: info → InfoIcon
- ConfirmationDialogContent.tsx: circle-alert, check → CircleAlertIcon, CheckIcon
- CalendarSwitch.tsx: arrow-left, rotate-cw → ArrowLeftIcon, RotateCwIcon
- ArrowButton.tsx: arrow-up, arrow-down → ArrowUpIcon, ArrowDownIcon
- FileUploader.tsx: upload → UploadIcon (kept Icon for dynamic)
- Checkbox.tsx: check → CheckIcon
- EditableHeading.tsx: pencil → PencilIcon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate Icon to component icons in UI and app-store packages
Batch 27: Migrate static Icon usages to @coss/ui/icons components.
Files changed:
- MultiEmail.tsx: x → XIcon (converted width to size)
- AppListCard.tsx: circle-alert → CircleAlertIcon
- SplitButton.tsx: chevron-down → ChevronDownIcon (kept Icon for dynamic)
- Calendar.tsx: chevron-left, chevron-right → ChevronLeftIcon, ChevronRightIcon
- AppDependencyComponent.tsx: check, circle-x, arrow-right → CheckIcon, CircleXIcon, ArrowRightIcon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate Icon to component icons in form input components
Batch 28: Migrate static Icon usages to @coss/ui/icons components.
Files changed:
- TextField.tsx: info → InfoIcon (kept Icon for x with onClick)
- Input.tsx: eye, eye-off, search → EyeIcon, EyeOffIcon, SearchIcon
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: use @coss/ui/src/icons in packages with legacy moduleResolution
Packages like packages/ui and packages/app-store use a legacy moduleResolution
setting that doesn't support subpath exports. This changes the import path from
@coss/ui/icons to @coss/ui/src/icons for these packages.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate Icon to component icons in UI form and editor components
Migrates static Icon usages:
- MultiOptionInput: x (2x), arrow-up, arrow-down
- components (select): check
- AddVariablesDropdown: chevron-down (3x)
- ToolbarPlugin: chevron-down
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: migrate Icon to component icons in settings and platform atoms
Migrates static Icon usages:
- SettingsLayoutAppDirClient: chevron-down (2x), chevron-right (2x), arrow-left
- platform/atoms dialog: x
- platform/atoms toast: x
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: resolve @coss/ui/icons module resolution for legacy moduleResolution
Add typesVersions to @coss/ui package.json to help TypeScript resolve
subpath exports even with legacy moduleResolution: "node" setting.
Change imports from @coss/ui/src/icons to @coss/ui/icons to avoid
double-src path issue when Next.js applies import maps.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: localize 'Select field type' fallback label in FormEdit
Address Cubic AI review feedback (confidence 9/10) by using t() for
the hardcoded 'Select field type' string to ensure proper i18n support.
Co-Authored-By: unknown <>
* fix: add typesVersions wildcards for @coss/ui subpath imports
Add lib/*, components/*, and hooks/* to typesVersions to support
legacy moduleResolution with all package subpath patterns.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: resolve missing Icon references in settings and workflows
- Add Icon import for dynamic icon usages in SettingsLayoutAppDirClient
- Replace static Icon usages with component icons (InfoIcon, PhoneIcon)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: resolve icon component type errors
- Add onClick prop support to IconProps
- Fix size prop type (use number instead of string)
- Rename local MailOpenIcon to MailOpenIconWrapper to avoid shadowing
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: add data-testid to icon components for test compatibility
- Add testId parameter to createIcon function
- Auto-generate data-testid for all icons (e.g., "check-icon", "search-icon")
- Remove outdated mock for @calcom/ui/components/icon in tests
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Update package.json
* Update package.json
* fix: migrate Icon to CalendarDaysIcon in videos-single-view.tsx
Co-Authored-By: unknown <>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
||
|
|
14563f664e |
feat: re-render bookings page after feature opt-in without full refresh (#27873)
* feat: re-render bookings page after feature opt-in without full refresh Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: make onOptInSuccess a required prop Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
c7e66a3aa9 |
fix: maintain uid parameter in BookingDetailsSheet URL (#27872)
* fix: maintain uid parameter in BookingDetailsSheet URL Move the isSyncedFromUrlToStoreRef guard from the effect level to inside the Zustand subscription callback. This ensures the Store→URL subscription is always created while still preventing premature URL overwrites during URL→Store sync. Also adds an E2E test verifying the uid parameter appears in the URL after clicking a booking item in the v3 bookings view. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * Update apps/web/playwright/bookings-list.e2e.ts Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * fix: clean up bookings-v3 feature flag after E2E test Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- 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> |
||
|
|
98b6d63164 |
refactor: apply biome formatting to packages/features (#27844)
* refactor: apply biome formatting to packages/features (batch 1 - small subdirs) Format small subdirectories in packages/features: di, flags, holidays, oauth, settings, users, assignment-reason, selectedCalendar, hashedLink, host, form, form-builder, availability, data-table, pbac, schedules, troubleshooter, eventtypes, calendar-subscription, and root-level files. Also includes straggler apps/web BookEventForm.tsx. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 2 - medium subdirs) Format medium subdirectories in packages/features: auth, credentials, calendars, routing-forms, routing-trace, attributes, watchlist, calAIPhone, tasker, and webhooks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 3 - bookings + insights) Format bookings and insights subdirectories in packages/features. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 4 - ee) Format packages/features/ee subdirectory covering billing, workflows, organizations, teams, managed-event-types, round-robin, dsync, integration-attribute-sync, and payments. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 5 - booking-audit part 1) Format booking-audit di, actions, common, dto, repository, and types subdirectories in packages/features/booking-audit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: apply biome formatting to packages/features (batch 6 - booking-audit part 2) Format booking-audit service subdirectory in packages/features/booking-audit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
81e4241f85 |
refactor: apply biome formatting to apps/web (#27692)
* refactor: apply biome formatting to apps/web (batch 1) Formats apps/web non-modules directories: - apps/web/app - apps/web/lib - apps/web/pages - apps/web/styles - apps/web/server - apps/web/test - Root-level .ts and .mjs files Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: apply biome formatting to apps/web/modules (batch 2) Formats smaller apps/web/modules directories: - onboarding, data-table, users, apps, auth - integration-attribute-sync, shell, availability - feature-flags, team, webhooks, getting-started - feature-opt-in, troubleshooter, schedules, notifications - signup-view.tsx Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: apply biome formatting to apps/web/modules (batch 3) Formats medium apps/web/modules directories: - bookings - event-types - insights - embed Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: apply biome formatting to apps/web/modules/ee (batch 4) Formats apps/web/modules/ee directory. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: apply biome formatting to apps/web (batch 5) Formats remaining apps/web directories: - apps/web/modules/settings - apps/web/modules/booking-audit - apps/web/playwright Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: apply biome formatting to apps/web/components (batch 6) Formats remaining apps/web/components files. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: apply biome formatting to new apps/web files from main Formats newly added/modified files from main merge: - WorkflowStepContainer.tsx (resolved merge conflicts) - Newly moved files (blocklist, form-builder, schedules, etc.) - Other files modified in main Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: apply biome formatting to new apps/web files from main Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
c58e1f4ae5 |
feat: add filter segment validation with useActiveFiltersValidator hook and refactor DataTableProvider (#27208)
* feat: add activeFilters validator to DataTableProvider for filter segment validation - Add validateActiveFilters prop to DataTableProvider to filter out inaccessible values - Create useActiveFiltersValidator hook in bookings module to validate filter values - Integrate validator in bookings-view.tsx to validate userId, eventTypeId, teamId filters - Add comprehensive tests for the filter validation logic This provides a scalable solution for handling stale filter segment data by validating filters at the caller level using already-fetched accessible resource IDs. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: add type guard for eventTypeIds to ensure number[] type Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: delay segment filter application until validator is ready - Change useActiveFiltersValidator to return 'loading' state while data is fetching - Add pending segment handling in DataTableProvider to delay filter application - Expose isValidatorPending in context for consumers to disable queries - Update BookingListContainer to disable bookings query while validator is pending This prevents both errors from invalid filters and flash from fetching without filters. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: extract useSegmentManagement hook from DataTableProvider - Extract segment management logic into dedicated useSegmentManagement hook - Reduces DataTableProvider from ~500 lines to ~330 lines - Use NuqsSetter type to match nuqs useQueryState setter signatures - Maintains all existing functionality and type safety Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: export ActiveFiltersValidator types from data-table lib/types Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: import ActiveFiltersValidatorState from lib/types instead of hook Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * Revert "refactor: extract useSegmentManagement hook from DataTableProvider" This reverts commit dd588ac4cfb1d709c71d1f621994a7e8f3118f33. * refactor: split DataTableProvider into fine-grained context providers - Create DataTableStateContext for raw nuqs state management - Create DataTableSegmentContext for segment management - Create DataTableFiltersContext for filter manipulation - DataTableProvider now composes all providers with a bridge component - Maintains backward compatibility via combined DataTableContext Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: apply segment filters when navigating back to page with existing URL state When navigating back to a page with a segment already selected in the URL, the segment was being marked as selected but its filters were not being applied. This caused non-deterministic behavior where the filter segment would sometimes not take effect. The fix ensures that when segmentIdRaw exists in the URL and segments are fetched, we also call applySegmentFilters() (with validator timing support) instead of just setting the selectedSegment state. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: simplify filter validator to only handle multi-select These filters are always multi-select, so remove unnecessary single-select handling code and tests. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: cancel debounced search term on unmount Cancel the debounced search term on unmount/dependency change to avoid queued updates firing after the provider unmounts. Co-Authored-By: Claude Opus 4.5 <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> |
||
|
|
a57fac7a78 |
docs: add code comment guidelines to AGENTS.md and update rule (#27729)
* docs: add code comment guidelines to AGENTS.md Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: extract comment guidelines into agents/rules and reference from AGENTS.md Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
b9c54f6661 |
docs: add Trigger.dev task implementation rule (#27712)
* docs: add Trigger.dev task implementation rule Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: add specific file path references for CalendarsTasker and config examples Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
512002aaef |
refactor: replace FeaturesRepository with DI-based feature repositories (#27200)
* refactor: replace FeaturesRepository with DI-based feature repositories Migrate from the legacy FeaturesRepository pattern to separate DI-based repositories: - Add checkIfFeatureIsEnabledGlobally to IFeatureRepository - Add getTeamsWithFeatureEnabled to ITeamFeatureRepository - Update CalendarSubscriptionService to use featureRepository, teamFeatureRepository, and userFeatureRepository - Update SelectedCalendarRepository.findNextSubscriptionBatch to filter by teamIds instead of featureIds - Update OnboardingPathService to use DI via getFeatureRepository() - Remove prisma parameter from OnboardingPathService callsites Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: update tests to use new DI-based feature repositories Update CalendarSubscriptionService and SelectedCalendarRepository tests to use the new separate repository interfaces: - featureRepository for global feature checks - teamFeatureRepository for team-level feature checks - userFeatureRepository for user-level feature checks Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: update API routes to use DI-based feature repositories Update cron and webhook routes to use the new separate repository interfaces instead of the combined FeaturesRepository. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: remove prisma arg from getGettingStartedPathWithParams call The OnboardingPathService method no longer requires a prisma argument as it now uses DI containers internally. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: update route tests to expect new DI-based feature repositories Update service instantiation tests to expect featureRepository, teamFeatureRepository, and userFeatureRepository instead of the old featuresRepository. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: optimize global feature check and add guard in checkForNewSubscriptions - Use targeted select for only `enabled` field in checkIfFeatureIsEnabledGlobally - Add global feature flag guard in checkForNewSubscriptions to avoid unnecessary DB queries and API calls when the cache feature is globally disabled Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * remove redundant comment --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> |
||
|
|
de24e0a232 | fix: show bookings-v3 opt-in banner (#27653) | ||
|
|
2364cff54d |
feat: custom feedback dialog for feature opt-in (#27578)
* feat: add delayed formbricks tracking for feature opt-in Adds delayed Formbricks survey tracking for feature opt-in. When a user opts into a feature, this allows triggering a Formbricks action after a configurable delay (e.g., 24 hours later) to collect feedback once they've had time to use the feature. Key changes: - Added `formbricks` config option to `OptInFeatureConfig` interface with `actionName` and `delayMs` properties - Created `useFormbricksOptInTracking` hook that handles the delayed tracking logic - Added `isFeatureTracked` / `setFeatureTracked` storage helpers to prevent duplicate tracking - Integrated the tracking hook into `useFeatureOptInBanner` Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * upgrade formbricks * feat: replace formbricks popup with custom feedback dialog Instead of using Formbricks' built-in popup, we now show a custom Cal.com-styled feedback dialog that submits responses directly to Formbricks API via tRPC mutation. - Add FeedbackDialog component with emoji rating selector - Add feedback tRPC router for server-side Formbricks submission - Update useFormbricksOptInTracking to return dialog state - Add survey config fields (surveyId, questions) to config Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: position feedback dialog at bottom-right corner - Use base-ui Dialog primitives for custom positioning - Position dialog at bottom-right to avoid Intercom overlap - Use z-index 10000 (below Intercom's high z-index) - Keep blocking backdrop for modal behavior - Use i18n keys for title/description - Add survey IDs for bookings-v3 feedback Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add i18n keys for feedback dialog title/description Allow each feature to specify custom i18n keys for the feedback dialog title and description via the formbricks config. - Add titleKey/descriptionKey to formbricks config interface - Pass i18n keys through feedbackDialogProps - Add bookings_v3_feedback_title/description translation keys Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: move FeedbackDialog into FeatureOptInBannerWrapper Better encapsulation - consumers of the feature opt-in banner no longer need to handle the feedback dialog separately. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add 5 second delay before showing feedback dialog Ensures the page has time to finish loading before showing the feedback dialog, avoiding showing it while skeletons are still visible. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: simplify feedback dialog UI - Remove redundant question labels - Add "(optional)" to comment placeholder Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: remove emoji button borders and add footer gap - Remove borders from rating emoji buttons - Add proper gap between textarea and footer (pb-4) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: delayMs is opt-in waiting period, not setTimeout delay delayMs represents the minimum time that must pass since opt-in before showing the feedback form (e.g., 3 days). If not enough time has passed, we skip showing the form entirely instead of setting a long setTimeout. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: custom feedback dialog for feature opt-in - Replace Formbricks popup with Cal.com-styled dialog - Add configurable delay (waitAfterDays) before showing feedback - Position dialog at bottom-right, non-blocking - Add localStorage tracking to prevent duplicate feedback - Add device targeting (showOn: desktop/mobile/all) - Create tRPC endpoint for Formbricks API submission - Use proper logger for error handling Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: rename tracking terminology to feedback - Rename useFormbricksOptInTracking → useOptInFeedback - Rename FormbricksOptInTrackingResult → OptInFeedbackState - Rename formbricksTracking property → feedback - Rename FormbricksTrackingState → FeedbackState We no longer "track" events to Formbricks. Instead, we show our custom feedback dialog when conditions are met. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: set waitAfterDays to 3 for production feedback delay Co-Authored-By: unknown <> * fix: update formbricks JS SDK usage for v3.0.0 The @formbricks/js SDK v3.0.0 changed its API: - setup() no longer accepts debug, userId, or attributes - Use setUserId() and setAttributes() after setup instead - track() now expects { hiddenFields: ... } or undefined Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
357c2882ad |
refactor: apply biome formatting to several packages (#27439)
* refactor: apply biome formatting to Phase 1 packages Packages formatted: - packages/app-store-cli - packages/config - packages/dayjs - packages/debugging - packages/embeds/embed-react - packages/embeds/embed-snippet - packages/kysely - packages/platform/constants - packages/platform/utils - packages/testing - packages/tsconfig Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: restore non-null assertions in embed-snippet to fix type error Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: remove ESM import from CommonJS config file Biome incorrectly added 'import process from node:process' to a CommonJS file that uses require(). This breaks Jest which expects CommonJS syntax. The process global is already available in Node.js without explicit import. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: exclude packages/embeds from Phase 1 formatting Per user request, reverting all biome formatting changes in packages/embeds to handle separately. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: restore const enum for BookingLocations Biome changed 'const enum' to 'enum' which is a semantic change. Reverting to keep the PR purely formatting-only. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
3f4109d8a9 |
test: add integration test for FeatureRepository with @Memoize decorator (#27613)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
8dde579d93 |
chore: add deprecated comment to FeaturesRepository (#27611)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
a7f4aebaaa | chore: add react grab (#27598) | ||
|
|
5804cc4fb0 |
feat: add PostHog event tracking for feature opt-in banner and dialog (#27579)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
10dd0e2af2 |
feat: add GitHub workflows to sync agents/ to Devin Knowledge (#26994)
* feat: add GitHub workflows to sync agents/ to Devin Knowledge - Add parse-to-devin-knowledge.ts to convert agents/ markdown to Devin Knowledge JSON - Add validate-format.ts to validate rules have frontmatter and knowledge-base sections start with 'When...' - Add sync-to-devin.ts to sync knowledge entries to Devin API - Add export-devin-knowledge.sh to backup existing Devin knowledge - Add validate-agents-format.yml workflow to validate format on PRs - Add sync-agents-to-devin.yml workflow to sync on merge to main - Add devin-knowledge.json to .gitignore (generated file) Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: use tsx instead of ts-node for better ESM support in CI Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: add missing knowledge entries from Devin backup Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: move agents scripts to scripts/ folder Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: rename scripts to devin-knowledge-* for clarity Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: move scripts to scripts/devin/ with clearer names Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * rename DEVIN_API_TOKEN to DEVIN_API_KEY * docs: fix usage comment script path Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: remove folder creation from sync script (API doesn't support it) Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: add -S flag to shebang for proper env execution Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * use pull_request_target * fix: add -S flag to shebang in sync-knowledge-to-devin.ts for proper env execution Co-Authored-By: unknown <> * restructure workflows * refactor: consolidate agent docs and split knowledge-base into modular rules - Delete knowledge-base.md, migrate content to 17 new rule files - Delete coding-standards.md (content duplicated in AGENTS.md and rules) - Add ci- and reference- prefixes to rules/_sections.md - Update AGENTS.md to reference new rule files - Update agents/README.md as rules index - Clean up parse-local-knowledge.ts (remove deleted file references) New rule files: - testing-playwright, testing-mocking, testing-timezone - ci-check-failures, ci-type-check-first, ci-git-workflow - data-prisma-migrations, data-prisma-feature-flags - quality-error-handling, quality-imports, quality-pr-creation, quality-code-comments - architecture-features-modules - patterns-workflow-triggers, patterns-app-store - reference-file-locations, reference-local-dev Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Revert "refactor: consolidate agent docs and split knowledge-base into modular rules" This reverts commit 8251b6b214c7c01a3bfe2137c6aa9292dd72427e. * refactor: reorganize agent docs - extract coding rules, keep domain knowledge - Slim down knowledge-base.md (356 → 96 lines) to domain knowledge only - Add Business rules section (managed events, orgs/teams, OAuth clients) - Delete coding-standards.md (content moved to rules) - Create 19 new rule files for coding guidelines: - quality-*: PR creation, error handling, imports, comments, code review - testing-*: playwright, mocking, timezone, incremental - ci-*: check failures, type-check-first, git workflow - data-prisma-*: migrations, feature flags - patterns-*: workflow triggers, app store - architecture-features-modules, reference-file-locations, reference-local-dev - Update agents/README.md as rules index (43 total rules) - Update _sections.md with CI/CD and Reference sections - Clean up parse-local-knowledge.ts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: rename knowledge-base sections to start with "When..." Update section headers to pass validation rules: - "Business Rules" → "When working with managed events, organizations, or OAuth clients" - "Product & Codebase Knowledge" → "When you need product or codebase context" Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: split knowledge-base business rules into separate sections Split the combined "When working with managed events, organizations, or OAuth clients" section into three distinct ## sections for better Devin triggering: - When working with managed event types - When working with organizations and teams - When working with OAuth clients Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: simplify trigger description logic in parse-local-knowledge.ts Since validate-local-knowledge.ts enforces that all section titles must start with "When...", we can remove the manual fallback logic and just use the title directly as the trigger description. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: simplify knowledge-base section validation Simplify the validation to only check that section titles start with "When..." since we've standardized on that pattern. Remove the special cases for error, file naming, PR, and repo note sections. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add script to delete all Devin knowledge entries Add delete-all-devin-knowledge.ts script that: - Lists all knowledge entries before deletion - Requires interactive confirmation (Y) to proceed - Blocks execution in non-TTY environments (CI, piped input) - Shows progress while deleting entries Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: add API reference links to delete-all-devin-knowledge script Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: replace NOW() with CURRENT_TIMESTAMP in feature flag migration example Co-Authored-By: unknown <> * add -S * docs: consolidate agent documentation and add AI setup guide - Remove duplicated Project Structure & Tech Stack from agents/README.md - Condense Commands section in AGENTS.md, link to agents/commands.md - Add AI-Assisted Development section to root README.md explaining the agents/ folder structure and symlink configuration Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: remove incorrect CLAUDE.md symlink claim from README Co-Authored-By: unknown <> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> |
||
|
|
12abc316e6 |
refactor: consolidate agent config into agents directory (#27427)
* refactor: consolidate agent config folders into agents directory - Move .claude/skills and .claude/rules content to agents/ - Remove duplicate .cursor/ and .goose/ folders - Create symlinks from .claude/ and .cursor/ to agents/ - Convert review.mdc to quality-review-checklist.md with proper frontmatter Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * feat: add Cal.com APIv2 skills to agents directory Move the Cal.com API v2 skills from PR #27445 into the consolidated agents/skills/ directory structure. This includes: - SKILL.md - Main skill file with API overview - references/authentication.md - Authentication methods - references/bookings.md - Bookings API reference - references/calendars.md - Calendars API reference - references/event-types.md - Event types API reference - references/schedules.md - Schedules API reference - references/slots-availability.md - Slots and availability API reference - references/webhooks.md - Webhooks API reference Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: update calcom-api skill to use Claude Code frontmatter format Remove non-standard frontmatter fields (license, metadata) and keep only the Claude Code supported fields (name, description) as per the Claude Code skills specification. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: restructure calcom-api SKILL.md as index file Convert SKILL.md from a comprehensive API doc (317 lines) to a concise index file (108 lines) that references the detailed documentation in the references/ folder. This follows the Claude Code skills pattern of keeping SKILL.md focused with supporting files for detailed content. The SKILL.md now: - Provides a quick start guide with essential examples - References all 7 detailed reference docs in a table - Lists common workflows and best practices - Points to external resources Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: preserve deleted content in reference files Move content that was removed from SKILL.md to appropriate reference files: - Add Error Handling and Pagination sections to authentication.md - Add Organization endpoints to event-types.md - Add Core Concepts section back to SKILL.md This ensures no useful API documentation is lost during the restructuring. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
4b7ea0c98f |
feat: update current time indicator on page refocus (#27503)
Add updateCurrentTimeOnFocus prop to Calendar component that enables the current time indicator to update when the page is refocused. This helps users see the accurate current time after switching tabs. Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> |
||
|
|
29ec2b9cb6 |
refactor: split flag repositories into Prisma and Cached layers (#27186)
* refactor: split flag repositories into Prisma and Cached layers - Rename FeatureRepository to PrismaFeatureRepository (raw DB access) - Rename TeamFeatureRepository to PrismaTeamFeatureRepository (raw DB access) - Rename UserFeatureRepository to PrismaUserFeatureRepository (raw DB access) - Create CachedFeatureRepository with @Memoize wrapping PrismaFeatureRepository - Create CachedTeamFeatureRepository with @Memoize/@Unmemoize wrapping PrismaTeamFeatureRepository - Create CachedUserFeatureRepository with @Memoize/@Unmemoize wrapping PrismaUserFeatureRepository - Update DI tokens, modules, and containers for all 6 repositories - Update imports in FeatureOptInService and related modules - Update tests to use new repository structure Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: simplify @Memoize key patterns and delegate batch methods to Prisma - Use direct function references for @Memoize key (e.g., KEY.all instead of () => KEY.all()) - Simplify batch methods in Cached repositories to delegate to Prisma repository - Update tests to reflect the new delegation pattern Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: add orderBy to TeamRepository.findAllByParentId for deterministic results Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * test: update TeamRepository test to expect orderBy in findAllByParentId Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: cleanup features repository and add specialized repository methods (#27195) * refactor: cleanup features repository and add findBySlug, update methods - Remove unused methods from FeaturesRepository (keep getTeamsWithFeatureEnabled) - Add findAll(), findBySlug(), update() to IFeatureRepository interface - Add findAll() with caching to CachedFeatureRepository - Add findBySlug() with caching to CachedFeatureRepository - Add update() with Unmemoize to CachedFeatureRepository - Add checkIfFeatureIsEnabledGlobally() to CachedFeatureRepository - Update toggleFeatureFlag.handler.ts to use repository instead of raw Prisma - Add comprehensive unit tests for all new methods Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: update updatedAt timestamp in feature update method Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: move feature check methods to specialized repositories - Replace getUserFeaturesStatus with two checkIfUserHasFeature calls in bookings page - Move checkIfTeamHasFeature to PrismaTeamFeatureRepository with pass-through in CachedTeamFeatureRepository - Move checkIfUserHasFeature and checkIfUserHasFeatureNonHierarchical to PrismaUserFeatureRepository with pass-throughs in CachedUserFeatureRepository - Add getEnabledFeatures to PrismaTeamFeatureRepository with caching in CachedTeamFeatureRepository - Keep FeaturesRepository methods as pass-throughs for backward compatibility - Update test to expect updatedAt in feature update Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: remove getUserFeaturesStatus and unused methods from FeaturesRepository Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * restore comment * fix: invalidate all-features cache on update and enabledFeatures cache on upsert/delete - CachedFeatureRepository: Add KEY.all() to @Unmemoize keys in update() to prevent stale findAll() results - CachedTeamFeatureRepository: Add KEY.enabledFeatures(teamId) to @Unmemoize keys in upsert() and delete() to prevent stale getEnabledFeatures() results Co-Authored-By: unknown <> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test: add CachedUserFeatureRepository tests Add comprehensive tests for CachedUserFeatureRepository covering: - findByUserIdAndFeatureId (cache hit, cache miss, not found) - findByUserIdAndFeatureIds (empty input, multiple features) - upsert (with cache invalidation) - delete (with cache invalidation) - findAutoOptInByUserId (cache hit, cache miss, not found) - setAutoOptIn (with cache invalidation) Co-Authored-By: unknown <> * test: remove tests for methods removed from FeaturesRepository Remove integration tests for methods that were intentionally removed: - getUserFeatureStates - getTeamsFeatureStates - getUserAutoOptIn - getTeamsAutoOptIn - setUserAutoOptIn - setTeamAutoOptIn Co-Authored-By: unknown <> * avoid N+1 query * refactor: add select clauses to PrismaFeatureRepository queries - Add explicit select clauses to findAll, findBySlug, and update methods - Only fetch fields needed for FeatureDto (slug, enabled, description, type, stale, lastUsedAt, createdAt, updatedAt, updatedBy) - Update tests to expect select clauses - Fix UserFeatureRepository test to use findMany mock Co-Authored-By: unknown <> * fix bad conflict resolved * use userId --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
5a7ce63d38 |
fix: show bookings shell headings when v3 disabled (#27433)
* fix: show bookings shell headings when v3 disabled * remove unused hook |
||
|
|
b51a0b0847 |
fix: cache already-enabled feature opt-in status in local storage (#27393)
When the eligibility check returns "already_enabled", store this in local storage to prevent repeated API calls on subsequent page loads. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> |
||
|
|
1e048648ce |
feat: add tooltip for disabled Cancel button on past bookings (#27431)
* feat: Add tooltip for disabled Cancel button on past bookings Show a tooltip explaining "You cannot cancel a past booking" when hovering over the disabled Cancel dropdown item for bookings that have already occurred. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * refactor: Extract tooltip condition into named variable Improves readability by extracting the tooltip open condition into a descriptive variable `showPastBookingCancelTooltip`. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> |
||
|
|
c1f52c219d | fix: align feature opt-in toggle labels with enable/disable wording (#27425) | ||
|
|
e7d38755dd |
refactor: use DI-ed cached FeaturesRepository in flags router (#27394)
## What does this PR do? Replaces direct instantiation of `FeaturesRepository` with the dependency-injected version using `getFeaturesRepository()` from the DI container in the feature flags router. **Key improvement:** The DI-ed version uses Redis caching, replacing the previous in-memory 5-minute cache implementation which was not ideal. This follows the established DI pattern in the codebase for loose coupling, better testability, and more robust caching across instances. ## Type of change - [x] Refactor (non-breaking change that improves code quality) ## Mandatory Tasks (DO NOT REMOVE) - [x] I have self-reviewed the code (A decent size PR without self-review might be rejected). - [x] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). N/A - no documentation changes needed. - [x] I confirm automated tests are in place that prove my fix is effective or that my feature works. ## How should this be tested? 1. Verify feature flags functionality works as expected: - Feature flag list endpoint should return all features - Team feature check should work correctly 2. No environment variables needed beyond standard setup ## Checklist - [x] My code follows the style guidelines of this project - [x] I have checked if my changes generate no new warnings ## Human Review Checklist - [ ] Verify `getFeaturesRepository()` returns a properly configured instance from the DI container - [ ] Confirm the DI container properly injects the Prisma client - [ ] Verify Redis caching is working as expected for feature flag data --- **Link to Devin run:** https://app.devin.ai/sessions/2ff6e4551c8649e4b6178b31a2195327 **Requested by:** @eunjae-lee |
||
|
|
18049bc1d6 |
refactor: update i18n keys to match effectiveReason values (#27381)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
ea15474edf |
fix: show bookings-v3 only in the settings but not in the banner (#27330)
## What does this PR do? Adds a `displayLocations` property to the `OptInFeatureConfig` interface to control where opt-in features are displayed (settings page, banner, or both), and applies this filtering at the callers' side. ## How to test locally ``` update "Feature" set enabled = true where slug='bookings-v3'; ``` Run it to globally enable the flag, and then go to the settings page to see the "Features" menu. --- **Changes:** - Added `OptInFeatureDisplayLocation` type with values `"settings"` | `"banner"` - Added optional `displayLocations` property to `OptInFeatureConfig` interface - Added helper functions: - `getFeatureDisplayLocations()` - returns display locations with default of `['settings']` - `shouldDisplayFeatureAt()` - checks if a feature should display at a specific location - `getOptInFeaturesForLocation()` - filters features by location - Updated `getOptInFeaturesForScope()` to accept an optional `displayLocation` parameter for filtering - Simplified `HAS_*_OPT_IN_FEATURES` constants to use `getOptInFeaturesForScope(scope, "settings").length > 0` - Updated `FeatureOptInService.listFeaturesForUser()` to filter by 'settings' location - Updated `FeatureOptInService.listFeaturesForTeam()` to filter by 'settings' location - Updated `useFeatureOptInBanner` hook to check for 'banner' location before showing **Default behavior:** If `displayLocations` is omitted, features default to `['settings']` only. ## Mandatory Tasks (DO NOT REMOVE) - [x] I have self-reviewed the code (A decent size PR without self-review might be rejected). - [x] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). N/A - internal config change only. - [x] I confirm automated tests are in place that prove my fix is effective or that my feature works. ## How should this be tested? 1. Verify the helper functions work as expected: - `getFeatureDisplayLocations({ slug: "test", ... })` should return `["settings"]` (default) - `getFeatureDisplayLocations({ slug: "test", displayLocations: ["banner"] })` should return `["banner"]` - `shouldDisplayFeatureAt(feature, "settings")` should return `true` for features without `displayLocations` - `getOptInFeaturesForScope("user", "banner")` should only return user-scoped features with `"banner"` in their `displayLocations` 2. Verify caller-side filtering: - `listFeaturesForUser()` and `listFeaturesForTeam()` should only return features with 'settings' in displayLocations - Banner hook should only show features with 'banner' in displayLocations - `HAS_*_OPT_IN_FEATURES` constants should only be true if there are features with 'settings' location ## Checklist - [x] My code follows the style guidelines of this project - [x] I have commented my code, particularly in hard-to-understand areas - [x] My changes generate no new warnings --- ### Human Review Checklist - [ ] Verify the default behavior (defaulting to `['settings']`) matches requirements - [ ] Confirm the filtering logic is applied correctly in all callers (service methods, banner hook, constants) - [ ] Verify the banner hook correctly prevents showing features without 'banner' in displayLocations - [ ] Note: The test mock returns all features regardless of `displayLocation` parameter - the filtering logic in `getOptInFeaturesForScope` isn't directly tested. Consider if this is acceptable or if tests should be added. **Link to Devin run:** https://app.devin.ai/sessions/a064ee43a56d458caf2892b55959f1ea **Requested by:** @eunjae-lee |
||
|
|
91a62a14ee | fix: disable prefetch in /bookings (#27351) | ||
|
|
ddceabe5d4 |
fix: use FeatureOptInService for bookings-v3 check (#27183)
* fix: use FeatureOptInService for bookings-v3 check * refactor: simplify FeatureOptInService API and fix bookings page - Add resolveFeatureStates method that takes only userId and featureIds - Update listFeaturesForUser to take only userId parameter - Remove getUserOrgAndTeamIds from _router.ts (now internal to service) - Fix bookings page to use new resolveFeatureStates method - Parallelize getUserFeaturesStatus and resolveFeatureStates calls Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * check session?.user?.id first * remove comment --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
fd476bf7f7 |
fix: cancel download fetch when progress toast is closed (#27152)
* fix: cancel download fetch when progress toast is closed - Create new progress-toast utility using @coss/ui toastManager - Add ToastProvider to app providers - Update download components to use AbortController for cancellation - When cancel button is clicked, abort signal stops the fetch loop Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: track active toasts with Set instead of accessing toastManager.toasts Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: add AnchoredToastProvider to app providers Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: extract common CSV download logic into useCsvDownload hook Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: improve progress toast with i18n support and Progress component Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: replace useCsvDownload hook with DownloadButton component Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: rename DownloadButton to CsvDownloadButton Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * clean up i18n * fix: properly throw AbortError when download is cancelled Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * Revert "fix: properly throw AbortError when download is cancelled" This reverts commit 3c64b848140271e4dcd2e45dba5302eef9ca562c. * fix abort controller * fix layout shift * better handle error * fix: address Cubic AI review feedback - Fix typo 'copmlete' -> 'complete' in download_progress i18n string - Treat null batch as failure during CSV download to prevent partial exports Co-Authored-By: unknown <> * remove redundant try - catch --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
1e31ac089a |
fix: use createPortal for FeatureOptInBanner to avoid Intercom widget conflict (#27121)
* fix: use createPortal for FeatureOptInBanner to avoid Intercom widget conflict Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: guard portal rendering against non-browser environments Add typeof document check before accessing document.body in createPortal to prevent SSR/test crashes when document is undefined. Co-Authored-By: unknown <> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
25fa46fd34 |
fix(coss-ui): convert /settings/my-account/general to coss-ui (#26053)
* fix(coss-ui): convert /settings/my-account/general to coss-ui * update guide * fix: add menuPosition fixed to TimezoneSelect in TravelScheduleModal Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: use menuPortalTarget to render TimezoneSelect dropdown above dialog footer Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: use Object.assign for type-safe styles in TimezoneSelect Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * revert comment * fix: guard document access for SSR in TravelScheduleModal Addresses Cubic AI review feedback: menuPortalTarget={document.body} will throw during server rendering where document is undefined. Added typeof check to guard against SSR. Co-Authored-By: unknown <> * change dialog backdrop from blur to dim * fix: add menuPlacement auto to open dropdown upward on mobile Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: use menuPlacement top on mobile for TimezoneSelect dropdown Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: make timezone button stack vertically on mobile to prevent overflow Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: make timezone select and button 50/50 width on larger viewports Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix date range picker issue on mobile * prevent travel schedule dialog dismissal with date picker --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
052e99f7ba |
feat: allow normal users to see userId filter with only themselves as option (#26835)
* feat: allow normal users to see userId filter with only themselves as option Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: return empty map when canReadOthersBookings is false and currentUser doesn't exist Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: use generic type parameter for Table to fix type compatibility Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * perf: disable listSimpleMembers query when canReadOthersBookings is false Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
aa8804e498 |
feat(flags): add @Memoize and @Unmemoize decorators for declarative caching (#27063)
* feat(flags): add @Memoize and @Unmemoize decorators for declarative caching - Add @Memoize decorator for caching method results with Zod validation - Add @Unmemoize decorator for cache invalidation on mutations - Create UserFeatureRepository using decorators as example implementation - Add comprehensive tests with 80%+ coverage (19 tests) - Add DI module and tokens for UserFeatureRepository - Enable experimentalDecorators in packages/features/tsconfig.json Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor(cache): use lazy Redis lookup in decorators - Decorators now access Redis via getRedisService() instead of this.redis - UserFeatureRepository no longer has redis property or direct redis calls - findByUserIdAndFeatureIds now uses decorated findByUserIdAndFeatureId - DI module simplified to only pass prisma dependency - Tests updated to call setRedisService() in beforeEach This ensures the repository only knows about Prisma, with all caching handled transparently by the decorators. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat(flags): add FeatureRepository and TeamFeatureRepository with decorator-based caching - Add FeatureRepository with @Memoize decorators for findAll, findBySlug, getFeatureFlagMap - Add TeamFeatureRepository with @Memoize/@Unmemoize decorators for all CRUD operations - Add comprehensive Zod schemas for Feature, TeamFeatures, and AppFlags validation - Add DI modules and tokens for both repositories - Add comprehensive test coverage (33 tests) for both repositories - Maintain backward compatibility with existing FEATURES_REPOSITORY tokens Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor(cache): use DI container pattern for Redis service - Create packages/features/di/containers/Redis.ts with getRedisService() - Update Memoize and Unmemoize decorators to import from DI container - Remove setRedisService() and IRedisService from types.ts exports - Update all tests to mock the container's getRedisService - Fix import ordering issues from biome Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor(cache): remove barrel import and add root-level cache export - Remove packages/features/cache/decorators/index.ts barrel file - Add packages/features/cache/index.ts as root-level export for cache feature - Update repository imports to use direct imports from source files - Follows the pattern: avoid barrel imports at nested levels, keep at feature root Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor(flags): minimize repository methods and address PR feedback - Remove unnecessary methods from FeatureRepository, TeamFeatureRepository, and UserFeatureRepository - Keep only methods needed by FeatureOptInService - Update imports to use @calcom/features/cache public API instead of relative paths - Handle redis.del() errors gracefully in Unmemoize decorator - Update tests to match simplified repositories Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor(cache): use Promise.allSettled for cache invalidation Cleaner approach than Promise.all with individual .catch() handlers Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat(flags): add setAutoOptIn methods and replace featuresRepository usage in _router.ts - Add setAutoOptIn method to TeamFeatureRepository with @Unmemoize decorator - Add setAutoOptIn method to UserFeatureRepository with @Unmemoize decorator - Replace featuresRepository usage in featureOptIn/_router.ts with new repositories - TeamFeatureRepository.setAutoOptIn unmemoizes KEY.autoOptInByTeamId(teamId) - UserFeatureRepository.setAutoOptIn unmemoizes KEY.autoOptInByUserId(userId) Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor(flags): use DI containers for TeamFeatureRepository and UserFeatureRepository - Create TeamFeatureRepository.ts container with getTeamFeatureRepository() - Create UserFeatureRepository.ts container with getUserFeatureRepository() - Update _router.ts to use DI containers instead of direct instantiation Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor(feature-opt-in): use DI containers for FeatureOptInService dependencies - Update FeatureOptInService to use IFeatureOptInServiceDeps with 3 repositories - Add helper functions teamFeatureToState() and userFeatureToState() - Update DI module to use depsMap pattern with featureRepo, teamFeatureRepo, userFeatureRepo - Create FeatureRepository container file - Replace all FeaturesRepository method calls with new repository methods Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * test(feature-opt-in): update FeatureOptInService tests for new IFeatureOptInServiceDeps interface - Update mock structure to use featureRepo, teamFeatureRepo, userFeatureRepo - Add helper functions createMockTeamFeature and createMockUserFeature - Update all test cases to use new repository method names - Add explicit types to satisfy biome lint rules Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor(flags): use DTOs at repository boundaries to prevent Prisma type leakage - Create FeatureDto, TeamFeaturesDto, UserFeaturesDto in packages/lib/dto/ - Update repository interfaces to return DTOs instead of Prisma types - Add toDto() transformation methods in repository implementations - Update FeatureOptInService to use DTOs instead of Prisma types - Follow data-dto-boundaries.md guidelines for architectural boundaries Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix(flags): update TeamFeatureRepository tests to match DTO structure Remove assignedAt from test mock data since TeamFeaturesDto only includes: teamId, featureId, enabled, assignedBy, and updatedAt Co-Authored-By: unknown <> * fix(cache): make Redis failures non-blocking in @Memoize decorator Wrap Redis get and set operations in try-catch blocks to ensure Redis failures don't break the application flow. If cache read fails, proceed to fetch from source. If cache write fails, silently ignore and return the result. Co-Authored-By: unknown <> * fix(cache): add logging for Redis failures and remove barrel import - Add warning logs for Redis failures in @Memoize and @Unmemoize decorators - Remove packages/lib/dto/index.ts barrel import file - Update all imports to use direct file paths instead of barrel imports Co-Authored-By: unknown <> * fix(cache): sanitize log messages to avoid exposing sensitive data - Remove cacheKey from log messages (may contain PII like user/team IDs) - Log only error.message instead of raw error objects - Addresses Cubic AI feedback (confidence 9/10) Co-Authored-By: unknown <> * sanitize log --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Volnei Munhoz <volnei@cal.com> |
||
|
|
087fa03513 |
test: add e2e test for Feature Opt-In banner (#27100)
## What does this PR do? Adds an end-to-end test for the Feature Opt-In banner flow. This test verifies the complete user journey from seeing the banner to enabling a feature. Currently `OPT_IN_FEATURES` in `packages/features/feature-opt-in/config.ts` is empty, so this e2e test skips. Once we uncomment the `bookings-v3` item from the config, this e2e test will run and pass. This is a preparation for when we enable the feature. **Changes:** - Creates a new e2e test file (`feature-opt-in-banner.e2e.ts`) that tests the complete opt-in flow - Adds `data-testid` attributes to banner and dialog components for reliable test selectors ## Mandatory Tasks (DO NOT REMOVE) - [x] I have self-reviewed the code (A decent size PR without self-review might be rejected). - [x] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). N/A - test only. - [x] I confirm automated tests are in place that prove my fix is effective or that my feature works. ## How should this be tested? 1. Add the `ready-for-e2e` label to run e2e tests in CI 2. The test should pass when run with `PLAYWRIGHT_HEADLESS=1 yarn e2e feature-opt-in-banner.e2e.ts` **Test requirements:** - The `bookings-v3` feature flag must exist in the Features table (the test uses `prisma.feature.upsert` to ensure this) - The test will skip if `bookings-v3` is not in `OPT_IN_FEATURES` ## Checklist - [x] I have read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md) - [x] My code follows the style guidelines of this project - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have checked if my changes generate no new warnings ## Updates since last revision - Replaced text-based locators (`getByText`, `getByRole`) with `data-testid` selectors for more reliable element targeting - Added `data-testid` attributes to `FeatureOptInBanner`, `FeatureOptInConfirmDialog`, and `FeatureOptInSuccessDialog` components ## Human Review Checklist - [ ] Verify the `data-testid` attributes don't conflict with existing test IDs in the codebase - [ ] Confirm the test correctly skips when `bookings-v3` is not in `OPT_IN_FEATURES` - [ ] Check that the added `data-testid` attributes follow the project's naming conventions --- Link to Devin run: https://app.devin.ai/sessions/97158ab1b7414e3988ba803b30d95b3e Requested by: @eunjae-lee |
||
|
|
5449b8d913 |
refactor: store timestamp instead of boolean for feature opt-in (#27080)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
adc198b37b |
feat: add feature opt-in banner system (#26625)
* docs: add feature opt-in banner system plan Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: iterate on feature opt-in banner plan based on feedback - Use config.ts for feature metadata instead of TRPC response - Consolidate localStorage dismissal into single key to avoid bloat - Replace separate success dialog with in-dialog success state for smoother UX Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: implement feature opt-in banner system - Add checkFeatureOptInEligibility TRPC procedure to check if user can opt-in - Create useFeatureOptInBanner hook with localStorage dismissal state - Create FeatureOptInBanner floating component for bottom-right display - Create FeatureOptInConfirmDialog with role-based options and success state - Integrate banner into bookings-view.tsx as example usage Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: add i18n translation keys for feature opt-in banner * refactor: create FeatureOptInBannerWrapper for simpler consumer integration Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: use @calcom/lib/webstorage and add Zod schema for localStorage Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: address PR review comments - use PBAC, move logic to service, improve typing Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> # Conflicts: # packages/features/feature-opt-in/services/FeatureOptInService.ts * test: add comprehensive tests for checkFeatureOptInEligibility method Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: correct import and Checkbox type errors Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * update message * invalidate after dialog dismiss * feat: simulate user opt-in to determine banner eligibility When a feature has a strict policy and org/team hasn't explicitly enabled it, user opt-in alone won't enable the feature. This change simulates what would happen if the user opts in and only shows the banner if opting in would actually enable the feature. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: add early return for missing featureConfig and clarify simulation comment Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix repository usage * refactor: simplify FeatureOptInConfirmDialog UI and remove unused translation Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: replace radio buttons with multi-select dropdown in FeatureOptInConfirmDialog Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * resize banner * refactor: use AnimatedPopover pattern for team selection and rename titleI18nKey to nameI18nKey Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: change 'Just for me' to 'For me', fix width clipping, remove divider Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * update style * feat: make 'Just for me' mutually exclusive with teams/org and store opt-ins in localStorage Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: remove barrel imports and update to direct imports Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: add modal prop to AnimatedPopover to fix scroll lock conflict in dialogs Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: wrap Popover.Content with Portal to prevent layout interference in dialogs Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: use flexbox gap instead of space-y to prevent popover wrapper from affecting layout Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * Revert "fix: use flexbox gap instead of space-y to prevent popover wrapper from affecting layout" This reverts commit 8385adafa890c2f2674aa3ae3b10ca6e0c55ba5c. * Revert "fix: wrap Popover.Content with Portal to prevent layout interference in dialogs" This reverts commit e84301a35a99b3559d47c2d37316af290834ca2d. * Revert "fix: add modal prop to AnimatedPopover to fix scroll lock conflict in dialogs" This reverts commit b015af2f1cf31ef7087c02cb8535d96cc4a34125. * feat: replace Radix Dialog and AnimatedPopover with coss-ui components This migration uses @coss/ui Dialog and Popover components which are built on Base UI instead of Radix. Base UI handles scroll locking and positioning differently, which should fix the gap issue when opening the popover inside the dialog. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: replace remaining @calcom/ui components with coss-ui - Replace Divider with Separator from @coss/ui - Replace Label with Label from @coss/ui - Replace CheckboxField with Checkbox + Label from @coss/ui - Replace Icon with direct lucide-react icons (UserIcon, BuildingIcon, UsersIcon, CheckIcon) - Replace showToast with toastManager.add() from @coss/ui Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: replace Popover with Menu component from coss-ui - Replace Popover + FilterCheckboxField with Menu + MenuCheckboxItem - MenuCheckboxItem provides built-in checkbox indicator and styling - MenuSeparator provides proper menu separators - Cleaner API with onCheckedChange callback - Better keyboard navigation support Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: align icon and text on same line in MenuCheckboxItem, widen dialog - Wrap icon and text in flex container with items-center gap-2 - Change dialog width from sm:max-w-md to sm:max-w-lg to prevent text wrapping Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * use dimmed bg for coss dialog title * refactor: change nameI18nKey/descriptionI18nKey to nested i18n object - Change OptInFeatureConfig interface to use i18n: { name, description } - Update all component usages to use featureConfig.i18n.name and featureConfig.i18n.description - Update test mocks to use new structure Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: add i18n.title to OptInFeatureConfig type definition Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * update texts * use title instead of name * update banner style * refactor: split FeatureOptInConfirmDialog into separate success and confirmation dialogs Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: don't record dismissed info in local storage after successful opt-in Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: add checkFeatureOptInEligibility to IFeatureOptInService interface Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * update common.json * refactor: move tRPC usage from features package to apps/web/modules Addresses Cubic AI review feedback (confidence 9/10): - Remove @calcom/trpc import from FeatureOptInConfirmDialog.tsx - Add FeatureOptInMutations type for passing mutation functions via props - Move tRPC hooks to useFeatureOptInBanner hook in apps/web/modules - Pass mutations through FeatureOptInBannerWrapper to dialog component This maintains the architectural constraint that packages/features should not import from @calcom/trpc to prevent circular dependencies. Co-Authored-By: unknown <> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
950f9555ee |
fix(ui): update coss ui components (#26989)
* fix(ui): update coss ui components * fix(sidebar): remove redundant overflow-auto from SidebarContent ScrollArea already provides the scroll container, so keeping overflow-auto on the child creates a nested scroll area and prevents scrollFade from reflecting actual overflow. Addresses Cubic AI review feedback with confidence 9/10. Co-Authored-By: unknown <> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
f691258a5c |
refactor(agents): move prescriptive content from knowledge-base to rules (#26925)
* refactor(agents): move prescriptive content from knowledge-base to rules - Create architecture-page-level-auth.md for Next.js auth checks - Create data-prefer-select-over-include.md for Prisma query optimization - Create performance-dayjs-usage.md for Day.js performance guidelines - Create quality-avoid-barrel-imports.md for import best practices - Update knowledge-base.md to reference rules directory - Remove duplicated prescriptive content from knowledge-base.md Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * chore(agents): remove redundant rules reference from knowledge-base Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: add agents/rules reference to AGENTS.md extended documentation Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
b13e0f46ad |
feat: clear all filters when deselecting a segment (#26920)
## What does this PR do? When a filter segment is selected and the user clicks it again to deselect, this PR now clears all active filters in addition to deselecting the segment. Previously, deselecting a segment only called `setSegmentId(null)`, which removed the segment selection but left the filters in place. Now it calls `clearAll()` which clears both the segment selection and all active filters. ## Mandatory Tasks (DO NOT REMOVE) - [x] I have self-reviewed the code (A decent size PR without self-review might be rejected). - [x] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). N/A - no documentation changes needed. - [x] I confirm automated tests are in place that prove my fix is effective or that my feature works. ## How should this be tested? 1. Go to a page with DataTable and filter segments (e.g., Bookings page or Organization Members page) 2. Select a filter segment (e.g., "My Bookings" system segment or a user-created segment) 3. Verify filters are applied (URL contains `activeFilters`) 4. Click the same segment again to deselect it 5. Verify the segment is deselected AND all filters are cleared (URL should no longer contain `activeFilters`) An e2e test has been added to `filter-segment.e2e.ts`: - `Deselecting a segment clears all active filters` ## Checklist - [x] My code follows the style guidelines of this project - [x] I have checked if my changes generate no new warnings ## Human Review Checklist - [ ] Verify that calling `clearAll()` instead of `setSegmentId(null)` is the intended behavior (clears both segment selection and all active filters) - [ ] Consider if there are use cases where users might want to keep filters when deselecting a segment --- > **Link to Devin run**: https://app.devin.ai/sessions/44f22b80d9c442bdb334d04dac2b476d > **Requested by**: @eunjae-lee |
||
|
|
079749518b |
fix: add integration-test.ts pattern to biome test file overrides (#26836)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
97bfb8158d |
fix: load .env file in vitest config and update integration test docs (#26828)
* docs: update integration test commands for Vitest 4.0 Vitest 4.0 no longer supports custom CLI flags like --integrationTestsOnly. Updated documentation to use the new VITEST_MODE=integration environment variable syntax instead. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: load .env file in vitest config for integration tests Vitest 4.0 doesn't automatically load .env files into process.env. This caused integration tests to fail with ECONNREFUSED errors because DATABASE_URL was not available. Added loadEnv from Vite to load .env file at the start of vitest config. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * chore: remove unnecessary comment Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: only load .env vars if not already set Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
4b99072bcc |
feat: add scope configuration for feature opt-in (#26801)
* feat: add scope configuration for feature opt-in Add scope field to OptInFeatureConfig that allows features to be scoped to specific levels (org, team, user). This enables features to be shown only at certain settings pages rather than all three. Changes: - Add OptInFeatureScope type with values 'org', 'team', 'user' - Add optional scope field to OptInFeatureConfig interface - Add getOptInFeaturesForScope helper function to filter features by scope - Update FeatureOptInService to filter features based on scope - Update tRPC router to pass scope parameter for org/team endpoints Features without a scope field default to all scopes for backward compatibility. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: add scope validation to setUserFeatureState and setTeamFeatureState - Add isFeatureAllowedForScope helper function to check if a feature is allowed for a scope - Update setUserFeatureState to reject if feature is not scoped to 'user' - Update setTeamFeatureState to accept scope parameter and reject if feature is not allowed - Update tRPC router to pass scope parameter for team and org endpoints - Fix unit test mock to include new config exports Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: use ErrorWithCode for scope validation and add tests - Replace raw Error with ErrorWithCode using ErrorCode.BadRequest - Add comprehensive tests for setUserFeatureState scope validation - Add comprehensive tests for setTeamFeatureState scope validation - Test both enabled/disabled and inherit state scenarios - Test error messages include feature ID and scope name Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: improve Features menu visibility to use scope configuration Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: remove unused hasOptInFeaturesForScope function Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: allow features not in config at all scopes (permissive default) Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: revert permissive default and mock scope validation in integration tests Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
5c686d90f9 |
feat: add tri-state UI settings pages and auto opt-in preference (#25892)
* feat: add tri-state UI settings pages and auto opt-in preference TASK 5: Tri-state UI with ToggleGroup - Create shared TeamOrgFeaturesSettings component - Create user features settings page (features-view.tsx) - Create team features settings page - Create org features settings page TASK 6: Add auto opt-in preference - Add autoOptInExperimentalFeatures field to User and Team models - Add migration for new fields - Add TRPC endpoints for auto opt-in preference (using repository pattern) - Add auto opt-in checkboxes to settings pages Also adds i18n keys for feature opt-in UI. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> refactor: rename autoOptInExperimentalFeatures to autoOptInFeatures Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> refactor: apply PBAC procedure pattern to featureOptIn router - Create createTeamPbacProcedure for team-scoped endpoints - Create createOrgPbacProcedure for organization-scoped endpoints - Refactor all team/org endpoints to use the new PBAC procedures - Significantly reduces boilerplate code for permission checks Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> add features pages implement hooks update style update style rename slug to featureId show Features page on the side bar only if OPT_IN_FEATURES.length > 0 revert unncessary renaming revert some changes remove some changes * fix repository usage * test: add unit tests for PBAC utility procedures Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: add 'disabled by organization' badge for Team Level Features page Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * a little clean up * feat: add effectiveReason to computeEffectiveStateAcrossTeams for better UI feedback - Update computeEffectiveStateAcrossTeams to return both enabled state and reason - Add EffectiveStateReason type with 6 possible values - Update FeatureOptInService to include effectiveReason in resolved state - Simplify useUserFeatureOptIn.getBlockedWarning to use effectiveReason directly - Add feature_no_explicit_enablement_warning translation - Invalidate feature list when auto-opt-in setting changes in all hooks * test: add tests for FeatureOptInService.listFeaturesForTeam and refactor router to use TeamRepository Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * make it clearer about auto opt in * move hooks to apps/web/module * fix * fix: move types to packages/features/feature-opt-in, fix imports and test mocks - Move types.ts from apps/web/modules/feature-opt-in/hooks to packages/features/feature-opt-in - Update FeaturesSettings.tsx to import types from new location - Update hooks to import types from @calcom/features/feature-opt-in/types - Fix organization features-view import path (~/settings/organizations -> ~/ee/organizations) - Fix PermissionCheckService mock in util.test.ts to use class syntax Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: add validation for team ID and remove isPublic from featureOptIn handler Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: resolve biome lint errors in feature-opt-in files - Add explicit return types to functions and methods - Replace ternary operators with if-else statements - Replace forEach with for...of loops to avoid useIterableCallbackReturn - Extract helper functions to reduce function complexity - Add explicit type annotations to variables - Move exports to end of file to satisfy useExportsLast rule Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: resolve type errors in featureOptIn router - Replace ctx.organizationId with ctx.user.organization.id - Add null checks for organizationId in org procedures - Remove incorrect type annotation from featureOptInRouter Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: address PR feedback on feature opt-in implementation - Refactor createMutationCallbacks to useMutationCallbacks hook with useLocale internally - Restore comment on featureOptIn prop in FeaturesSettings.tsx - Revert getAllTeamIds helper, use ternary operator instead - Use ctx.user.organizationId with proper guard clauses Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix type error * feat: disable toggle when feature is blocked by higher level - Add isBlockedByHigherLevel function to UseFeatureOptInResult interface - Implement blocking detection for user level (org/team disabled) - Implement blocking detection for team level (org disabled) - Organization level never blocked (top level) - Update FeaturesSettings to disable ToggleGroup when blocked Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * change order of toggle buttons * feat: add policy field (permissive/strict) to feature opt-in config - Add OptInFeaturePolicy type with 'permissive' and 'strict' modes - Update computeEffectiveStateAcrossTeams to handle both policies: - Permissive: user opt-in can activate; disables only win if ALL teams disable - Strict: user opt-in alone not enough; ANY explicit disable blocks - Add new EffectiveStateReason values for strict policy - Update FeatureOptInService to read policy from config - Add unit tests for all 9 policy scenarios from spec Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: rewrite test file with scenario tables and make policy required Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix type * fix types * make policy required * disable toggle group if blocked by higher level * refactor: move PBAC procedures to packages/trpc/server/procedures - Move util.ts to pbacProcedures.ts in procedures folder for better reusability - Move util.test.ts to pbacProcedures.test.ts alongside the main file - Update imports in _router.ts to use new location Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: remove redundant null checks in featureOptIn router The createOrgPbacProcedure middleware already validates organizationId and throws if null. Use non-null assertion (!) instead of redundant runtime checks since the middleware guarantees the value exists. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: improve middleware typing to avoid non-null assertions Remove explicit return type from createOrgPbacProcedure to let TypeScript infer the extended context type. This allows handlers to use ctx.organizationId directly (typed as number) instead of ctx.user.organizationId! assertions. The middleware validates organizationId and adds it to the context, so downstream handlers can safely access ctx.organizationId as a number. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat(pbac): use featureOptIn permissions instead of generic team/org permissions Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat(pbac): add PBAC to team features page and pass canEdit to views Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: add effectiveReason to IFeatureOptInService and update listFeaturesForTeam interface Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: add feature_any_team_disabled to isUserBlockedByHigherLevel check Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: add strict-policy reasons to warning helper function Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> |
||
|
|
829d6c4714 |
feat(pbac): add FeatureOptIn resource to permission registry (#26761)
* feat(pbac): add Feature resource to permission registry Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat(pbac): add migration for Feature resource permissions Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat(pbac): add English translations for Feature resource Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat(pbac): update Feature resource for opt-in/opt-out control (read and update only) Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat(pbac): rename Feature to FeatureOptIn resource Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat(pbac): simplify update description text Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
fd6e2a9ca5 |
fix: enable DI for FeatureOptInService (#26061)
* fix integration test * fix: enable DI for FeatureOptInService * create containers/FeaturesRepository.ts * refactor: convert FeatureOptInService and FeaturesRepository to moduleLoader pattern - Create feature-specific tokens in feature-opt-in/di/tokens.ts and flags/di/tokens.ts - Update modules to use bindModuleToClassOnToken for type-safe dependency injection - Simplify containers to use moduleLoader.loadModule() for automatic dependency loading - Import feature-specific tokens in central tokens.ts using spread operator Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: rename FeatureOptInServiceInterface to IFeatureOptInService Follow the codebase convention of using 'I' prefix for interface files and names. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: export featuresRepositoryModule for backward compatibility The FeaturesRepository module was refactored to use moduleLoader pattern but AvailableSlots.ts still imports featuresRepositoryModule. This adds the export to maintain backward compatibility. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
0413783ffb |
docs: extract DI pattern guide to separate file with moduleLoader pattern (#26756)
* docs: add moduleLoader pattern documentation to knowledge-base Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: rewrite DI section to use moduleLoader pattern as primary approach - Replace manual module loading examples with moduleLoader pattern - Add Mistake 4 about manual module loading being not type-safe - Update Core Concepts to explain moduleLoader components - Show both depsMap (multiple deps) and dep (single dep) usage - Emphasize build-time type safety throughout Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: extract DI pattern to separate file - Move DI documentation from knowledge-base.md to di-pattern.md - Add brief reference in knowledge-base.md pointing to the new file - Keeps knowledge-base.md focused on quick notes while DI gets its own detailed guide Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
70d5a78d69 |
docs: add DI pattern guide to knowledge-base.md (#26751)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
2b7c087ac8 |
feat: limit badges to 2 with hover/click popover in UserListTable (#26556)
* feat: limit badges to 2 with hover tooltip in UserListTable Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: reuse LimitedBadges component with clickable popover for mobile Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: move LimitedBadges to components/ui with hover+click support Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: fix Biome lint issues in LimitedBadges and UserListTable - Refactor LimitedBadges to concrete component with BadgeItem type - Move exports to end of files to comply with useExportsLast rule - Add explicit types to callback parameters for useExplicitType rule - Convert nested ternary to if-else for filterType calculation - Remove unused imports (Row, Table types) - Update ResponseValueCell and UserListTable to use new LimitedBadges API Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: add proper types for filterType and getFacetedUniqueValues - Add FilterType import from @calcom/types/data-table - Add FacetedValue import from @calcom/features/data-table - Type filterType as FilterType to allow reassignment to different ColumnFilterType values - Type getFacetedUniqueValues return as Map<FacetedValue, number> Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * add vertical gap * fix: address code review feedback for LimitedBadges - Add index to id for unique keys in ResponseValueCell.tsx - Restore orange variant for group options in UserListTable.tsx - Fix useMemo dependency array (add t, remove dispatch) - Fix import ordering with biome - Convert ternary operators to if-else statements for biome compliance Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: remove id from BadgeItem type, use label as key - Remove id field from BadgeItem type in LimitedBadges - Use label as React key instead of id - Remove unused rowId parameter from ResponseValueCell - Update all consumers to not pass id field Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: use index for key instead of label in LimitedBadges Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * Revert "refactor: use index for key instead of label in LimitedBadges" This reverts commit 1daaac47e596fd6b5f5583847faa10b131783349. --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
03bb9481a2 |
fix: update E2E test to match German translation without '+' prefix (#26589)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
ae6e0689f4 |
docs: update google calendar guide (#26549)
* docs: update google calendar doc * update page name and include .env in seed-app-store.ts * add onre more step * update |
||
|
|
f9635df629 | chore: load .env for seed-insights.ts (#26545) | ||
|
|
6fa525812c |
docs: add DTO location and naming conventions to knowledge base (#26478)
* docs: add DTO location and naming conventions to knowledge base Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: clarify DTO location rules for new features vs refactored code Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: simplify DTO location - all DTOs go in packages/lib/dto/ Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
f4248bf20d |
feat: implement FeatureOptInService (#25805)
* feat: implement FeatureOptInService WIP * clean up * feat: consolidate feature repositories and add updateFeatureForUser - Implement updateFeatureForUser in FeaturesRepository (similar to updateFeatureForTeam) - Move getUserFeatureState and getTeamFeatureState from PrismaFeatureOptInRepository to FeaturesRepository - Update FeatureOptInService to use only FeaturesRepository - Add setUserFeatureState and setTeamFeatureState methods to FeatureOptInService - Update _router.ts to remove PrismaFeatureOptInRepository usage - Remove PrismaFeatureOptInRepository.ts and FeatureOptInRepositoryInterface.ts - Update features.repository.interface.ts and features.repository.mock.ts - Add integration tests for updateFeatureForUser, getUserFeatureState, getTeamFeatureState - Update service.integration-test.ts to use FeaturesRepository Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: rename updateFeatureForUser to setUserFeatureState Rename to match the convention used for setTeamFeatureState Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: return FeatureState type from getUserFeatureState and getTeamFeatureState * fix integration tests * clean up logics * update services and router * refactor: change getUserFeatureState and getTeamFeatureState to accept featureIds array - Renamed getUserFeatureState to getUserFeatureStates - Renamed getTeamFeatureState to getTeamFeatureStates - Changed parameter from featureId: string to featureIds: string[] - Changed return type from FeatureState to Record<string, FeatureState> - Updated FeatureOptInService to use the new batch methods - Added tests for querying multiple features in a single call - Optimized listFeaturesForTeam to fetch all feature states in one query Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: add getFeatureStateForTeams for batch querying multiple teams - Added getFeatureStateForTeams method to query a single feature across multiple teams in one call - Updated FeatureOptInService.resolveFeatureStateAcrossTeams to use the new batch method - Replaces N+1 queries with a single database query for team states - Added comprehensive integration tests for the new method Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: combine org and team state queries into single call - Include orgId in the teamIds array passed to getFeatureStateForTeams - Extract org state and team states from the combined result - Reduces database queries from 3 to 2 in resolveFeatureStateAcrossTeams Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: use team.isOrganization and clarify computeEffectiveState comment Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: use MembershipRepository.findAllByUserId with isOrganization Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: add featureId validation using isOptInFeature type guard Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * less queries * add fallback value * fix type error * move files * add autoOptInFeatures column * use autoOptInFeatures flag within FeatureOptInService * add setUserAutoOptIn and setTeamAutoOptIn * fix computeEffectiveState logic * rewrite computeEffectiveState * clean up integration tests * clean up in afterEach * fix type error * refactor: use FeaturesRepository methods instead of direct Prisma calls Replace all manual userFeatures and teamFeatures Prisma operations with the new setUserFeatureState and setTeamFeatureState repository methods. Changes include: - Admin handlers (assignFeatureToTeam, unassignFeatureFromTeam) - Test fixtures and integration tests - Playwright fixtures - Development scripts This ensures consistent feature flag management through the repository pattern and supports the new tri-state semantics (enabled/disabled/inherit). Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * clean up * fix the logic * extract some logic into applyAutoOptIn() * remove wrong code * refactor: convert setUserFeatureState and setTeamFeatureState to object params with discriminated union - Convert multiple positional parameters to single object parameter - Use discriminated union types: assignedBy required for enabled/disabled, omitted for inherit - Update all callers across repository, service, handlers, fixtures, and tests * fix type error * use Promise.all * fix --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
e0fd01e377 |
feat: add lightweight E2E session warmup page (#26451)
* feat: add lightweight E2E session warmup endpoint - Add /api/__e2e__/session-warmup endpoint that triggers NextAuth session loading - Update apiLogin fixture to use the new endpoint instead of navigating to /settings/my-account/profile - The endpoint is gated by NEXT_PUBLIC_IS_E2E=1 (already set in playwright.config.ts) - This reduces overhead in E2E tests by avoiding loading a full UI page just to warm up the session Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: move session warmup endpoint to App Router - Move /api/__e2e__/session-warmup from pages/api to app/api - Use App Router patterns (NextResponse, buildLegacyRequest) - Maintains same functionality for E2E session warming Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * rename path * refactor: switch from API route to minimal SSR page (Option 2) - Replace /api/e2e/session-warmup API route with /e2e/session-warmup page - Use App Router page pattern with getServerSession for session warmup - Update apiLogin fixture to navigate to the page instead of API request Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * revert users fixture but with a new url * render nothing on success * clean up * trying something * Revert "trying something" This reverts commit 2ae2f7dcb42612e54eb072a9f09857272020889a. --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Keith Williams <keithwillcode@gmail.com> |
||
|
|
fe4017f302 |
docs: clarify tRPC architecture - packages/features vs apps/web/modules (#26155)
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> |
||
|
|
945ded951f | fix: integration test of booking audit service (#26027) | ||
|
|
cef8610925 |
feat: add enabled column to UserFeatures and TeamFeatures for tri-state semantics (#25765)
* feat: add enabled column to UserFeatures and TeamFeatures for tri-state semantics - Add enabled Boolean column to UserFeatures model with default true - Add enabled Boolean column to TeamFeatures model with default true - Update FeaturesRepository to use tri-state semantics: - enabled=true: feature is explicitly enabled - enabled=false: feature is explicitly disabled (blocks inheritance) - No row: inherit from team/org level - Update SQL queries to check enabled=true for feature access - Add enableFeatureForTeam method to interface and implementation Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * update comments * add integration tests * add more test * select enabled only * no @default(true) * fix types and tests * add missing enabled * add missing enabled * rename enableFeatureForTeam to updateFeatureForTeam and support FeatureState * refactor: rename updateFeatureForTeam to setTeamFeatureState Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix integration test * fix tests * add more tests * add missing enabled --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
aaaff0705b |
fix(bookings): enable past date selection for cancelled bookings (#25644)
* refactor(data-table): clean up DateRangeFilter range options - Replace 'past' | 'custom' with 'past' | 'future' | 'any' | 'customOnly' - Add direction field to PresetOption for preset compatibility filtering - Derive presets visibility automatically based on compatible presets - Update bookings list to use new range values: - past -> 'past' - upcoming -> 'future' - unconfirmed/recurring/cancelled -> 'any' Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat(playground): add DateRangeFilter playground page with E2E tests - Add playground page at /settings/admin/playground/date-range-filter - Demonstrate all 4 range options: past, future, any, customOnly - Add link to playground index page - Add E2E tests for presets visibility and date restrictions Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix(playground): use correct meta.filter pattern for column filter config Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * clean up the playground esign * add unit tests instead of e2e * fix the implementation --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
e0a28af46e |
feat(bookings): conditionally show heading/subtitle based on view (#25889)
* feat(bookings): conditionally show heading/subtitle based on view - Add heading and subtitle props back to ShellMainAppDir in page.tsx - Use headerClassName marker to identify the heading element - Add useLayoutEffect in BookingCalendarContainer to hide heading when calendar view is mounted - Restore heading visibility when switching back to list view Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor(bookings): extract shell heading visibility into reusable hook - Create useBookingsShellHeadingVisibility hook with explicit visible parameter - Move visibility logic from BookingCalendarContainer to BookingsContent - Use data attribute to track if we hid the header (idempotent/Strict-Mode-safe) - Explicit show/hide based on view state instead of relying on unmount Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor(bookings): simplify shell heading visibility hook Remove HIDDEN_DATA_ATTR tracking since the header wrapper won't have a hidden class from any other source Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
c361b9bbc5 |
chore: enable booking redesign for e2e (#25642)
* enable bookings-v3 feature flag for e2e tests WIP * fix e2e * update comments |
||
|
|
52d5261b51 |
feat(booking): implement cross-page/week navigation in booking details sheet with view persistence (#25545)
* display UTM parameters * persist view (list | calendar) in localStorage * move to next page on clicking "next" of last item in the page improve navigation ^ Conflicts: ^ apps/web/modules/bookings/components/BookingCalendarContainer.tsx * fix navigation on calendar view * Delete apps/web/modules/bookings/NAVIGATION_IMPLEMENTATION.md * avoid page size being 0 * check feature flag on user level * use map to improve useBookingListData * address feedback * feat(bookings): add smart navigation for calendar view - Add sort option to tRPC bookings.get schema and handler - Create NAVIGATION_PROBE_WINDOW_MONTHS constant (3 months) - Create useNearestFutureBooking hook to find nearest future booking - Create useNearestPastBooking hook to find nearest past booking - Update useCalendarNavigationCapabilities to use probe results - Update BookingCalendarContainer to wire up probe hooks This enables the booking details sheet to: - Disable next/prev buttons when no bookings exist in that direction - Jump directly to the week containing the nearest booking Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix type error * feat: add booking selection state when using slideover (#25637) * implement booking selection when using slideover * remove pixel shift * fix * auto scroll to selected event on calendar * make DateValues header sticky when scrolling --------- Co-authored-by: Eunjae Lee <hey@eunjae.dev> * prefetch previous / next weeks on calendar view * clean up classes * handle "fetched & but no data" situation more correctly in useCalendarAutoSelector --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> |
||
|
|
728e1173cb | chore: update AGENTS.md on running unit tests for specific test name (#25820) | ||
|
|
3986d61f40 |
feat(bookings): improve bookings redesign (#25251)
* use booking.uid instead of booking.id for url param * show timezone on calendar * fix type * restore horizontal tab and remove header and subtitle * clean up sidebar items * fix event propagation from attendees * fetch all statuses except for cancelled on calendar view * clean up styles of the badges on BookingListItem * fix useMediaQuery * add close button to the header * add assignment reason to the details sheet * use separator row * use ToggleGroup for the top bookings tab * move ViewToggleButton * resize the action button * remove wrong prop * fix type error * fix type error * hide view toggle button on mobile (and fix the breakpoint) * remove unused e2e tests * fix e2e tests * hide toggle button when feature flag is off * update skeleton * improve attendees on booking list item and slide over * improve attendee dropdown * fix type error * move query to containers * select attendee email * infinite fetching for calendar view * update styles * fix compatibility * fix: add backward compatibility for status field in getAllUserBookings * increase calendar height * fix type error * support Member filter only for admin / owners * add debug log (TEMP) * add event border color * show Reject / Accept buttons on BookingDetailsSheet * move description section to the top * update When section * update style of Who section * add CancelBookingDialog WIP * fix CancelBookingDialog * increase clickable area * add schedule info section WIP * fix flaky reject button * fixing reschedule info WIP * add fromReschedule index to Booking * improve rescheduled information * improve reassignment * fix type error * fix unit test * respect user's weekStart value on the booking calendar view * update debug log * improve payment section * clean up * fix log message * reposition filters on list view * fix bookings controller api2 e2e test * clean up file by extracting logic into custom hooks * rename files * merge BookingCalendar into its container * extract logic into separate hook files * remove redundant logic * rearrange items on calendar view * add WeekPicker * extract filter button * responsive header on list view * horizontal scroll for ToggleGroup WIP * fix type error * fix cancelling recurring event * address feedback * fix e2e tests * fix unit test * fix e2e tests * make hover style more visible for ToggleGroup * fix margin on CancelBookingDialog * update styles on the slide over (mostly font weight) * update style of CancelBookingDialog * update styles * update margin top for the header * refactor getBookingDetails handler * fix gap in who section * auto-filter the current user on the calendar view * calculate calendar height considering top banners * improve booking details sheet interaction without overlay * update calendar event styles * update reject dialog style * put uid first in the query params * fix class name * memoize functions in useMediaQuery * query attendee with id instead of email * update margins * replace TRPCError with ErrorWithCode * move calculation outside loop * remove dead code |
||
|
|
41b71d845c |
docs: add ErrorWithCode vs TRPCError guidelines and packages/features import restrictions (#25751)
* docs: add ErrorWithCode vs TRPCError guidelines and packages/features import restrictions Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: correct ErrorWithCode syntax with proper imports and Factory pattern Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: update AGENTS.md with ErrorWithCode guidance for non-tRPC files Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: reduce duplication by linking to knowledge-base.md for error handling details Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
68cdfd42b1 |
docs: add Repository + DTO pattern guidance for Prisma type isolation (#25730)
* docs: add Repository + DTO pattern guidance for Prisma type isolation Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: add 'Why this pattern?' section explaining benefits of Repository + DTO Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: condense Repository + DTO pattern guidance for readability Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
acc82f808d |
docs: instruct to use ast-grep > ripgrep > grep for searching (#25725)
* docs: instruct to use ripgrep with grep fallback Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: update search tool preference to ast-grep > ripgrep > grep Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
4e68bcb021 |
docs: improve AGENTS.md and rename .agents to agents/ (#25665)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
1c3ced5b70 |
fix: simplify date range picker to Airbnb-style selection (#25386)
* feat: simplify date range picker to Airbnb-style selection Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: apply Airbnb-style selection to allowPastDates branch Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: extract date range selection logic and add unit tests - Extract date range selection logic into pure function (dateRangeLogic.ts) - Remove unused allowPastDates parameter from selection logic - Add comprehensive unit tests (11 test cases covering all scenarios) - Simplify DateRangePicker component (30+ lines -> 5 lines) - Improve separation of concerns: allowPastDates only controls calendar date restrictions * style update * feat: add hover highlighting for date range selection When a start date is selected and user hovers over other dates, the potential range between start and hovered date now shows bg-emphasis background for better visual feedback. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * memoize hovering range and update styles --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
6479adf14e |
fix: integer to text comparison in routing insights query (#25019)
* fix: integer to text comparison in routing insights query Add explicit integer array cast to prevent PostgreSQL type mismatch error when comparing bookingUserId (integer) with user_id array values in getRoutedToPerPeriodData query * add e2e tests * refactor: remove LoadingInsight component and handle loading in ChartCard - Enhanced ChartCard to render default loading UI when isPending is true - Replaced all LoadingInsight usages with ChartCard that accepts isPending/isError props - Removed LoadingInsight component and updated exports - Updated 16 chart components to use the new pattern - ChartCard now shows spinner and skeleton title during loading state Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: make children prop optional in ChartCard when isPending is true Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: remove unused loadingState prop from ChartCard - Remove loadingState prop and ChartLoadingState type export - Simplify computedLoadingState to derive state only from isPending/isError - No functional changes - loadingState was not being used by any components - data-loading-state attribute behavior remains unchanged for E2E tests Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: remove duplicate isPending early returns from chart components - Update all 16 chart components to use single ChartCard return pattern - Gate children rendering with !isPending && isSuccess && data checks - Prevents data processing code from executing during loading state - Improves code consistency and maintainability across all charts Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: remove redundant !isPending check from chart conditionals - Simplify conditional rendering to use just 'isSuccess && data' or 'isSuccess' - In TanStack Query, isSuccess and isPending are mutually exclusive - The !isPending check was redundant since isSuccess already implies !isPending - Applied to all 16 chart components for consistency - Components with safe defaults (data ?? []) use just 'isSuccess' - Components requiring data check use 'isSuccess && data' Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * revert the mistake * apply feedback * apply feedback * fix e2e --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
41ad0f718d |
refactor: use Button component instead of plain button in CopyButton (#25489)
* refactor: use Button component instead of plain button in CopyButton Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * add shrink-0 to StartIcon and EndIcon of Button * remove unused class names --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
86b9aa5f23 |
fix: exclude AWAITING_HOST from seed-insights random status selection (#25414)
## What does this PR do? Fixes a bug in the seed-insights script where `AWAITING_HOST` status was randomly assigned to bookings along with a `userId`, which violates the correct behavior of instant meetings. **Problem:** - The seed script randomly picked from all 5 booking statuses (including `AWAITING_HOST`) - When `AWAITING_HOST` was selected, the script still assigned a `userId` - Real instant meetings with `AWAITING_HOST` status should have `userId = NULL` until a host joins - This created incorrect test data that doesn't match production behavior **Solution:** - Filter out `AWAITING_HOST` from `BookingStatus` values using `Object.values(BookingStatus).filter()` - This approach is more maintainable than listing valid statuses explicitly - if new statuses are added in the future, they will automatically be included - Moved `validStatusesForSeed` to module level so it's calculated once at load time instead of on every shuffle call - Added comments explaining why this status requires special handling ## Mandatory Tasks (DO NOT REMOVE) - [x] I have self-reviewed the code (A decent size PR without self-review might be rejected). - [x] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). N/A - seed script only. - [x] I confirm automated tests are in place that prove my fix is effective or that my feature works. N/A - this is a seed script for test data generation. ## How should this be tested? 1. Run the seed script: `yarn seed-insights` 2. Verify no `AWAITING_HOST` bookings are created with a `userId`: ```sql SELECT COUNT(*) FROM "Booking" WHERE status = 'awaiting_host' AND "userId" IS NOT NULL AND "createdAt" > NOW() - INTERVAL '1 day'; -- Should return 0 for newly seeded data ``` 3. Verify other statuses are still generated: ```sql SELECT status, COUNT(*) FROM "Booking" WHERE "createdAt" > NOW() - INTERVAL '1 day' GROUP BY status; -- Should show ACCEPTED, PENDING, CANCELLED, REJECTED (but not AWAITING_HOST) ``` ## Checklist - [x] I have read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md) - [x] My code follows the style guidelines of this project - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have checked if my changes generate no new warnings --- > **Link to Devin run:** https://app.devin.ai/sessions/08f634e7210d415982d71c8f687b4468 > **Requested by:** eunjae@cal.com (@eunjae-lee) |
||
|
|
251d29f65b |
fix: improve overlapping events with dynamic offsets and widths (#25310)
## What does this PR do? Improves the visual presentation of overlapping calendar events in the weekly view with two key enhancements: - **Dynamic startHour per scenario**: Each playground scenario now displays the calendar starting at an appropriate hour based on its earliest event time, rather than always starting at 6am - **Full width for non-overlapping events**: Single events and non-overlapping events now display at 100% width (previously 80%) for maximum visibility ## Key Changes ### Overlapping Event Layout Algorithm Replaces the previous uniform-width, fixed-offset layout with an intelligent spread algorithm: **Previous behavior:** - All overlapping events: 80% width with 8% offset steps - Events clustered on the left side **New behavior:** - **2 overlapping events**: 80% and 50% widths - **3 overlapping events**: 55%, ~42%, and 33% widths - **4+ overlapping events**: Progressive narrowing from 40% down to minimum 25% - **Spread algorithm**: Events distribute across the full width with the last event aligned to the right edge - **Right edge distribution**: `ri = Rmin + (Rmax - Rmin) × i/(n-1)` for even spacing ### Visual Improvements - Single/non-overlapping events: **100% width** (was 80%) - Overlapping events: **Variable widths** based on cascade position (leftmost events wider, rightmost narrower) - Last overlapping event: **Aligned to right border** for maximum scatter - Minimum width: **25%** maintained for readability **Devin session:** https://app.devin.ai/sessions/168d2227f5304c49ae4d34d17da5b025 **Requested by:** eunjae@cal.com (@eunjae-lee) ## Visual Demo https://github.com/user-attachments/assets/693546fa-448d-470a-b041-c08f4697c177 ## Mandatory Tasks (DO NOT REMOVE) - [x] I have self-reviewed the code - [x] I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. **N/A** - playground-only changes - [x] I confirm automated tests are in place that prove my fix is effective or that my feature works. ## How should this be tested? 1. Navigate to `/settings/admin/playground/weekly-calendar` 2. Verify each scenario: - **Non-Overlapping Events**: Both events should be 100% width, no offset - **Touching Events**: Both events should be 100% width, no offset - **Two Overlapping Events**: First event 80% width, second 50% width aligned to right - **Three Overlapping Events**: Progressive narrowing with spread across full width - **Four Overlapping Events**: Four events spread across full width 3. Verify startHour values: - Most scenarios should start at 9am (events start at 10am) - Dense day scenario should start at 8am (events start at 9am) - Mixed statuses scenario should start at 1pm (events start at 2pm) 4. Test with real calendar data to ensure overlapping events look visually distinct **Environment variables:** Standard Cal.com development setup **Test data:** Use playground scenarios or create overlapping events in your calendar ## Human Review Checklist **⚠️ CRITICAL ITEMS:** 1. **Visual verification in playground** (MOST IMPORTANT): - Open `/settings/admin/playground/weekly-calendar` - Verify non-overlapping events are 100% width (not 80%) - Verify overlapping events spread properly across full width - Verify last overlapping event aligns to right edge - Verify each scenario starts at appropriate hour 2. **Algorithm correctness**: - Single events: 100% width (was 80%) - Two overlapping: 80%, 50% widths with last aligned to right - Three overlapping: 55%, ~42%, 33% widths spread across full width - Right-edge distribution: `ri = Rmin + (Rmax - Rmin) * i/(n-1)` 3. **Edge cases**: - Test with 10+ overlapping events to ensure no overflow - Verify minimum width (25%) is respected - Verify backward compatibility: custom `baseWidthPercent`/`offsetStepPercent` should use legacy behavior 4. **Type safety**: - `startHour` parameter now properly typed as `Hours` (union of 0-23) - All scenarios use valid `Hours` values **Known limitations:** - Local visual testing was not completed due to environment issues - Easing curve parameters (curveExponent: 1.3) were chosen based on examples but may need visual tuning - No E2E tests for visual appearance (only unit tests for layout calculations) ## Checklist - [x] I have read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md) - [x] My code follows the style guidelines of this project - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have checked if my changes generate no new warnings |
||
|
|
afbfa11ab5 |
chore: update seed.ts (#25316)
* chore: update seed.ts * Revert "chore: update seed.ts" This reverts commit 2bd0c5a6dc57142632f8fbd267aa6b5eba6d1cea. * use env vars instead |
||
|
|
701490a493 | docs: update the app store doc regarding seed (#25317) | ||
|
|
dd7f108f08 |
fix: put booking details and calendar behind feature flag (#25175)
* Revert "fix: revert bookings redesign (#25172)"
This reverts commit
|
||
|
|
1f102bf3b4 |
fix: revert bookings redesign (#25172)
* Revert "refactor: extract logic as bookingDetailsSheetStore (#25129)" This reverts commit |
||
|
|
7a0b8a9eba |
refactor: extract logic as bookingDetailsSheetStore (#25129)
* refactor: extract logic as bookingDetailsSheetStore * clean up * revert something * provide store from context |
||
|
|
919fc3cdd5 | chore: fix seed-insights.ts (#25018) | ||
|
|
d7e6334ccb |
refactor: remove useInsightsParameters() (#25020)
* refactor: remove useInsightsParameters (no longer needed) * remove log |
||
|
|
ea80e8c8d4 |
fix: enable webhook form submit button when all required fields are filled (#25109)
* fix: enable webhook form submit button when all required fields are filled The submit button was disabled even when all fields were filled because the form relied on isDirty state. Since eventTriggers are pre-populated with default values, the form never became dirty until the user manually changed the triggers. This fix adds validation logic that: - For new webhooks: checks if required fields (URL, triggers) are filled - For editing webhooks: preserves the existing isDirty behavior - Handles the conditional time/timeUnit requirement for no-show triggers Fixes the issue where users had to manually change event triggers to enable the submit button even though all required information was filled. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: extract webhook form validation logic to computed variables Replaced IIFE in disabled prop with clean computed variables: - Extracted all watch() calls to the top of the component - Computed validation logic as clear, named variables - Reused needsTime for showTimeSection to avoid duplicate watch calls - Simplified button disabled prop to just !canSubmit This improves code readability and maintainability while preserving the same validation behavior. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: resolve type error by moving canSubmit computation after changeSecret declaration Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: auto-initialize time/timeUnit for webhooks with no-show triggers When creating a webhook with default event triggers that include no-show triggers (AFTER_HOSTS_CAL_VIDEO_NO_SHOW or AFTER_GUESTS_CAL_VIDEO_NO_SHOW), the time and timeUnit fields are now automatically initialized to default values (5 minutes). This ensures the submit button is enabled when all required fields are filled, fixing E2E test failures in webhook.e2e.ts. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
86353191d2 |
feat: add booking actions into BookingDetailsSheet (#24912)
* move booking actions into a subfolder * fix logic to render booking actions dropdown * skip dropdown portal when rendered from detail sheet * fix type error |
||
|
|
b01cb27c56 |
feat: improve overlapping events display in weekly calendar view (#24880)
* feat: improve overlapping events display in weekly calendar view - Add cascading layout algorithm for overlapping events - First event at 80% width, subsequent events offset by 8% - Implement hover behavior to bring events to front (z-index 100) - Extract overlap logic into reusable utility functions - Add comprehensive unit tests for overlap detection and layout calculation - Sort events by start time, then by duration for consistent rendering Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: add weekly calendar playground page for testing overlapping events - Create comprehensive playground page with 8 test scenarios - Include two overlapping, three cascading, non-overlapping, same start time, chain overlaps, dense day, touching events, and mixed statuses - Add focused view with scenario selector and grid view for side-by-side comparison - Update playground index to include weekly calendar link - Each scenario includes description, expected behavior, and collapsible event data Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * update base props * remove unneccessary things * fix: isolate Calendar store instances to prevent shared state - Refactor useCalendarStore to use Zustand's createStore with React Context - Each Calendar component now creates its own isolated store instance - Maintains backward compatibility with global store fallback - Fixes issue where multiple Calendar instances on same page shared state This allows the playground page to render multiple Calendar instances without state conflicts between them. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: prevent event overflow in dense overlap scenarios - Dynamically compress offset step based on overlap group size - Ensure leftOffset + width never exceeds 100% to prevent bleeding into next day - Add width clamping as safety guard against rounding errors - Add 3 new tests for overflow prevention with dense event scenarios Fixes issue where 10+ overlapping events would cascade beyond day boundary and bleed into the next day's column. The algorithm now calculates the maximum safe step size per overlap group while maintaining visual cascade. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * remove global store * fix: comprehensive overflow prevention with safety margin and CSS fix - Add safetyMarginPercent (0.5%) to prevent rounding and CSS box model overflow - Implement floor3 rounding for width to guarantee left + width <= 100 - safetyMargin - Calculate width from rounded left offset to avoid rounding mismatch - Remove inset-x-1 class conflict that was setting both left and right positioning - Change from marginLeft to left positioning for proper control - Add test for 20+ overlapping events to verify no overflow - Update existing tests to verify safety margin is respected This fixes the slight overflow issue reported by the user where events were still bleeding into adjacent day columns despite the initial dynamic step compression fix. The root cause was a combination of: 1. CSS conflict: inset-x-1 class setting both left and right positioning 2. Rounding mismatch: width calculated from unrounded left offset 3. No safety margin for CSS box model effects (borders, padding) All 21 tests now pass including new safety margin verification. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * feat: update Dense Day scenario to 20+ events - Increase from 11 to 21 overlapping events in Dense Day scenario - Update title from '10+ Events' to '20+ Events' - Add 10 more diverse events with staggered start times - Better stress test for overflow prevention with safety margin This provides a more comprehensive test case for the overflow prevention fix and matches the user's request for 20+ events instead of 10+. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * WIP * feat: enhance event tooltip to show full event details - Replace simple title-only tooltip with rich content tooltip - Display event title, time range, description, and status - Add color indicator matching the event's visual style - Set min-width (200px) and max-width (300px) for better readability - Use inverted theme colors for better contrast in tooltip Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * faster animation * feat: position tooltip based on day of week - Show tooltip on right side for Monday-Thursday (days 1-4) - Show tooltip on left side for Friday-Sunday (days 5-0) - Calculate day of week using dayjs from event start date Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * add margin for tooltip * feat: add event duration layout test scenario - Add new scenario with events of varying durations (3, 7, 15, 20, 30, 53 minutes) - Test layout logic where eventDuration > 30 changes flex direction - Events ≤30min show horizontal layout (title and time inline) - Events >30min show vertical layout (title and time stacked) Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * update styles * feat: add minimum height of 15px for events - Ensure very short events (e.g., 3 minutes) are still visible - Use CSS max() to apply minimum height while respecting duration-based height - Prevents events from becoming too small to interact with Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * update playground * do not mutate * pre-compute some values --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Sean Brydon <sean@cal.com> |
||
|
|
3a1e04bb42 |
refactor: extract booking actions dropdown to separate component (#24872)
* refactor: extract booking actions dropdown to separate component - Created BookingActionsDropdown component with all dropdown actions and dialogs - Component receives booking as prop and handles all action logic internally - Removed duplicate dialog states and mutations from BookingListItem - Fixed img tag to use Next.js Image component - Maintains same functionality and UI while improving code reusability Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: restore cardCharged variable in BookingListItem The cardCharged variable was accidentally removed during the refactoring but is still needed for the actionContext in BookingListItem.tsx Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: move BookingItemProps type to separate types.ts file - Created types.ts to hold shared booking types - Updated BookingListItem.tsx to import from types.ts - Updated BookingActionsDropdown.tsx to import from types.ts - Updated bookingActions.ts to import from types.ts - Removed unused RouterInputs and RouterOutputs imports from BookingListItem.tsx - Removes unwanted dependency chain where BookingActionsDropdown imported from BookingListItem Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * remove unnecessary description * extract states as a zustand store * fix dialog issue * fix type errors --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
763c568797 | fix: existence check of searchParams in NavigationItem (#24877) | ||
|
|
2484b6fad2 |
fix: filter deleted fields from routing form insights headers (#24830)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
f00c14d0c1 |
feat: implement booking calendar view with weekly layout (#24563)
* feat: implement booking calendar view with weekly layout - Create reusable WeekCalendarView component that displays bookings in a weekly calendar format - Replace EmptyScreen in BookingsCalendar with the new calendar view - Calendar view includes: - Week navigation with Today, Previous, and Next buttons - 7-day week view with time slots from 12 AM to 11 PM - Bookings displayed as colored blocks positioned by time - Support for event type colors and status-based colors - Responsive design that fills the viewport - Hover tooltips showing booking details - Filters remain functional at the top of the view Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: use existing Calendar component from weeklyview - Replace custom calendar implementation with the existing Calendar component - Use parseEventTypeColor to properly handle event type colors - Simplify implementation by leveraging existing calendar infrastructure - Maintain week navigation and filtering functionality Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix imports * fix: replace isSameOrAfter with isAfter || isSame - isSameOrAfter method does not exist in dayjs - Use combination of isAfter and isSame instead Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * remove useBookerTime dependency from weekly calendar view * modify date range filters * initial callback * sort events * clean up FilterBar * add showBackgroundPattern * update styles * update style * update styles * fix type error * fix error * update styles * update styles * update event colors * rename component * persist weekStart on the url * use FilterBar * apply feedback * extract BorderColor type * use client * clean up * adjust styles * color-code events * rename borderColor to color * restore class name * add feature flag * update class name --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
139e47fe3b |
feat: include EventType.seatsPerTimeSlot in bookings get handler response (#24813)
- Add seatsPerTimeSlot field to EventType selection in bookings query - Refactor conditional array pushes to use if statements instead of && operator to fix lint warnings Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
af61b6d341 |
feat: move bookings tabs to sidebar navigation (#24605)
* feat: move bookings tabs to sidebar navigation - Add bookings sub-items (Upcoming, Unconfirmed, Recurring, Past, Cancelled) to sidebar navigation - Remove HorizontalTabs component from bookings view - Add redirect from /bookings to /bookings/upcoming for default navigation - Parent Bookings menu item now automatically navigates to Upcoming sub-item Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * clean up * add e2e tests * address feedback * add horizontal tab back * useBuildHref * update preserveQueryParams logic * put back lint rule --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |
||
|
|
3418a25a85 |
fix: seed script command (#24668)
* feat: add seed-all command to run all seed scripts - Add seed-all command to packages/prisma/package.json - Create scripts/seed-all.ts to run seed.ts, seed-insights.ts, and seed-pbac-organization.ts in sequence - Update Prisma configuration to use seed-all as the default seed command - Add GitHub workflow to test seed-all command with a real PostgreSQL database Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: use correct path resolution in seed-all script Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: simplify database verification step in test workflow Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: use seed-all in cache-db action instead of separate workflow - Update cache-db action to use seed-all command - Remove test-seed-all.yml workflow as requested Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix error * change command name * fix integration tests * run basic seed by default --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Keith Williams <keithwillcode@gmail.com> |
||
|
|
c7c8564b63 |
fix(insights): convert string filter values to numbers for integer columns (#24730)
## What does this PR do? Fixes PostgreSQL error "operator does not exist: integer = text" when filtering by `bookingStatusOrder` and `bookingUserId` fields. Frontend sends filter values as strings, but these database columns are integers requiring type conversion. Changes: - Convert `bookingStatusOrder` filter values from strings to numbers - Convert `bookingUserId` filter values from strings to numbers - Update tests to use numeric values for `bookingStatusOrder` filters - Add test for string-to-number conversion in `bookingUserId` filter - Fix `Prisma.Sql` composition in 3 integration tests ## Mandatory Tasks (DO NOT REMOVE) - [x] I have self-reviewed the code (A decent size PR without self-review might be rejected). - [x] N/A - 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. - [x] I confirm automated tests are in place that prove my fix is effective or that my feature works. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Converts string filter values to numbers for integer columns in Insights routing to prevent PostgreSQL type errors. Fixes filtering by bookingStatusOrder and bookingUserId when the frontend sends strings. - **Bug Fixes** - Cast bookingStatusOrder and bookingUserId filter values to numbers and use = ANY([...]). - Update tests to expect numeric arrays; add test for string-to-number conversion on bookingUserId. - Correct Prisma.sql composition in three integration tests before calling $queryRaw. <!-- End of auto-generated description by cubic. --> |
||
|
|
fcd9480f9f |
fix: update seed-insights.ts Prisma connection handling for v6.16 (#24660)
* fix: update seed-insights.ts to use correct Prisma import and connection handling - Change prisma import from named export to default export to match Prisma v6.16 changes - Update promise chain from .then().catch() to .catch().finally() for proper connection cleanup - Comment out duplicate runSeed() call that was causing the script to execute twice - Fixes TypeError: Cannot read properties of undefined (reading '$connect') Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix implementation --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> |