* feat: add seat tracking infrastructure for monthly proration
Add seat change logging infrastructure with operationId for idempotency.
This PR adds the foundation for monthly proration billing by tracking
seat additions and removals, gated behind the monthly-proration feature flag.
- Add operationId field to SeatChangeLog for idempotency
- Update SeatChangeLogRepository to support upsert with operationId
- Add feature flag guard in SeatChangeTrackingService
- Integrate seat tracking in team member invites
- Integrate seat tracking in bulk user deletions
- Integrate seat tracking in team service operations
- Integrate seat tracking in DSYNC user creation
When monthly-proration feature flag is disabled, seat logging is skipped
and behavior remains unchanged.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: add monthly proration processing
Add monthly proration billing processing that works on top of the seat
tracking infrastructure. This PR implements the core proration logic,
webhook handlers, and integration with Stripe billing.
- Enhance MonthlyProrationService to process seat change logs
- Add payment webhook handlers (invoice.payment_succeeded, invoice.payment_failed)
- Update subscription webhook to sync billing period on renewals
- Update TeamBillingService to skip real-time updates when proration enabled
- Enhance StripeBillingService with proration capabilities
- Add Tasker enhancements for processing queues
- Update team creation/upgrade routes
Depends on: feat/monthly-proration-seat-tracking
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: remove unused logger from SeatChangeTrackingService
* fix: description for calculation
* fix null check on trial
* chore: no more prisma calls
* add feature flag check
* fix stub
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-22 11:23:38 +00:00
Amit SharmaGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: store utm params in stripe on signup
* fix: fallback to cookie when query params don't contain valid UTM data
Changed from else-if to separate if statement so that when query
params exist but don't contain valid UTM data, the cookie fallback
is still tried. Previously, any request with non-UTM query params
would skip the stored cookie data entirely.
Co-Authored-By: unknown <>
* fix: e2e
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
## 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
* feat: add assigned badge to team event types
Add an 'Assigned' badge to Round Robin and Collective event types
when the current user is a host/participant of the event type.
This provides visibility to users without edit permissions that
they are included in the rotation.
Changes:
- Add isCurrentUserHost flag in getEventTypesFromGroup handler
- Display blue 'Assigned' badge in event types listing view
- Add i18n translation for 'assigned' text
Co-Authored-By: ali@cal.com <ali@cal.com>
* refactor: remove redundant isTeamEvent check for assigned badge
Co-Authored-By: ali@cal.com <ali@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: ali@cal.com <ali@cal.com>
* chore: add new view for two step slot selection for embed
* fix: make sure two step slot selection is false by default
* chore: update embed playground to showcase two step slot selection
* chore: add tests
* chore: update embed snippet generator code to include two step slot selection
* chore: update docs
* fix: back button styling
* chore: implement feedback from cubic
* fix: add missing isEnableTwoStepSlotSelectionVisible properties to test mock store
Co-Authored-By: unknown <>
* chore: implement PR feedback
* chore: update slot selection modal
* chore: add prop to hide available times header
* fix: scope two-step slot selection visibility to mobile only
Restores the isMobile check in the timeslot visibility guard to ensure
desktop embeds continue to show the booking UI when two-step slot
selection is enabled. The feature should only hide the timeslot list
on mobile devices.
Addresses Cubic AI review feedback (confidence 9/10).
Co-Authored-By: unknown <>
* fixup: use translations for loading instead of actual word
* fix: type check
* fix: add window.matchMedia mock for jsdom test environment
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: add window.matchMedia mock to packages/testing/src/setupVitest.ts
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: unit tests failing
* add a width style to the two-step slot selection embed container.
* refactor: rename enableTwoStepSlotSelection to useSlotsViewOnSmallScreen
- Rename external-facing embed config option from enableTwoStepSlotSelection to useSlotsViewOnSmallScreen
- Update URL parameter parsing in embed-iframe.ts
- Update type definitions in types.ts and index.d.ts
- Update internal variable names to slotsViewOnSmallScreen for consistency
- Update documentation, playground examples, and tests
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
* Add config to prefill all booking fields so that slot has confirm button along with it
* chore: implement PR feedback
* fix: move twoStepSlotSelection embed outside misc-embeds div to fix e2e test
The e2e test was failing because the misc-embeds div content was
intercepting pointer events on mobile viewport. This follows the same
pattern used for skeletonDemo - the embed is now outside misc-embeds
and the div is hidden when testing this namespace.
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: prevent pointer event interception in twoStepSlotSelection embed
Hide heading and note elements and set pointer-events: none on container
elements while keeping pointer-events: auto on the iframe container.
This prevents the container from intercepting clicks on the iframe
during mobile viewport e2e tests.
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: hide all non-essential content for twoStepSlotSelection e2e test
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: disable pointer-events on body for twoStepSlotSelection e2e test
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: remove pointer-events: auto on container to let clicks pass through to iframe
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: explicitly set pointer-events: none on container and inline-embed-container
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: also set pointer-events: none on html element to prevent interception
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: make .place div fill viewport for twoStepSlotSelection e2e test
Co-Authored-By: rajiv@cal.com <sahalrajiv6900@gmail.com>
* fix: failing embed tests
* fixup
* fixup fixup
* fix: failing tests
* fix: update checks for verifying prefilled date
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
* feat: add OAuth client developer settings page with approval workflow
- Add new developer OAuth page at /settings/developer/oAuth for users to submit OAuth client requests
- Transform admin OAuth page into management dashboard for reviewing/approving submissions
- Add OAuthClientApprovalStatus enum (PENDING, APPROVED, REJECTED) to track submission status
- Add userId and createdAt fields to OAuthClient model for tracking submissions
- Create email notifications for admin (new submission) and user (approval)
- Add sidebar navigation link in developer section below API keys
- Add comprehensive translations for new UI strings
- Create OAuthClientRepository for data access following repository pattern
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: re-export generateSecret for backward compatibility
Co-Authored-By: peer@cal.com <peer@cal.com>
* feat: make logo mandatory and list items clickable for OAuth clients
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: add missing translation keys and remove client secret from details dialog
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: address cubic AI reviewer comments
- Remove duplicate 'there' JSON key in common.json
- Add select clause to findByUserId to avoid exposing clientSecret
- Add @@index([userId]) to OAuthClient model for query performance
- Update migration to include the index
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: address PR review comments - fix indentation and use useCopy hook
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: change react-dom/server import to fix Turbopack compatibility
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* Revert "fix: change react-dom/server import to fix Turbopack compatibility"
This reverts commit c3e0b709c2d88fd221143cb4ce9cd25bb8c94277.
* fix: use email service pattern for OAuth client notifications
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: add try-catch around email sending to handle Turbopack react-dom/server issue
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* Revert "fix: add try-catch around email sending to handle Turbopack react-dom/server issue"
This reverts commit fc9d47cd773505ebc5ee2696718aad4a8a98be77.
* fix: improve OAuth client UI with skeleton loaders and smaller dialog styling
- Replace 'Loading...' text with proper skeleton loaders in both developer and admin OAuth client views
- Make client_id and copy button smaller in dialogs using size='sm' and text-sm styling
- Add 'client_id' translation key to common.json for proper i18n
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: improve skeleton loader to match actual OAuth client list structure
- Remove divide-y from container and use conditional border-b on rows
- Match the exact structure from oauth-clients-view.tsx L126-160
- Use proper spacing for text elements (mt-1 instead of space-y-2)
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix skeleton
* rename the selected oauth client dialog
* fix: address PR feedback - admin auth, dropdown styling, sidebar label
- Add defense-in-depth admin authorization check in updateClientStatus handler
- Fix broken dropdown menu by using DropdownItem with StartIcon prop
- Fix sidebar menu label from 'oAuth' to 'oauth_clients' to match developer view
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* update common.json
* feat: show client secret in approval email for confidential OAuth clients
- Add regenerateSecret method to OAuthClientRepository
- Regenerate secret when admin approves a PENDING confidential client
- Include client secret in approval notification email
- Add one-time warning message about storing the secret securely
- Only regenerate on first approval (not re-approvals)
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* feat: add Website URL field, fix logo styling, show client secret after approval
- Add Website URL field to OAuth client forms (admin and developer views)
- Fix Upload Logo section styling by wrapping in Label div with proper gap
- Display client secret in dialog after admin approves a confidential OAuth client
- Add websiteUrl field to Prisma schema with migration
- Update tRPC handlers and repository to support websiteUrl
- Add translation keys for new UI elements
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix: move clientSecret variable declaration outside if block for proper scoping
Co-Authored-By: peer@cal.com <peer@cal.com>
* refactor: dont expose client secret in emails
* refactor: dont regenerate secret upon status change
* refactor: reuse existing hash function
* refactor: rename admin/oAuth to admin/oauth page
* refactor: deduplicate oauth repositories
* refactor: remove withGlobalPrisma from oauth repository
* refactor: developer oauth page
* refactor: oauth status by default accepted
* refactor: request oauth status when creating
* refactor ux
* fix: address Cubic AI code review feedback
- Add purpose field to plain text email body for accessibility
- Convert NewOAuthClientButton to inline JSX to avoid React anti-pattern
- Trigger re-approval when redirectUri changes for security
- Add e.preventDefault() for Space key to prevent page scroll
- Change default approvalStatus to PENDING for defense-in-depth
- Use oauth_clients translation key for consistency
- Add meaningful alt text to Avatar for accessibility
- Remove onClick from DialogClose to prevent double-run close effects
- Return NOT_FOUND for non-owner delete to prevent resource enumeration
Co-Authored-By: unknown <>
* common.json file
* refactor: delete all prisma migrations
* refactor: have just 1 prisma migration
* revert: some devin changes
* fix: typecheck
* test: owner OAuth crud
* test: admin OAuth approval / rejection
* fix: address Cubic AI review feedback (confidence 9/10 issues)
- schema.prisma: Remove @default("") from purpose field to make it required
- schema.prisma: Use UTC-aware timezone expression for createdAt default
- OAuthClientFormFields.tsx: Localize redirect URI placeholder using t()
- common.json: Add redirect_uri_placeholder translation key
Co-Authored-By: unknown <>
* cubic changes
* refactor: dont log sensitive info and rethrow error
* cubic feedback
* refactor: make oauth client purpose optional
* refactor: admin/oauth not allowed if not logged in
* refactor: admin view skeleton
* refactor: rename state
* refactor: get rid of redundant mapping
* refactor: remove redundant handler
* refactor: remove redundant handler
* refactor: re-usable new oauth client button
* refactor: dialogs
* refactor: modals
* refactor: handler names, dialog, skeleton
* fix: purpose being null
* refactor: rename handler and delete old oauth admin page
* fix: purpose in submission
* refactor: handler names
* refactor: rename
* refactor: update handler
* refactor: rename approvalStatus -> status
* refactor: simplify modal
* refactor: name
* dont require repproval if redirectUri changes
* fix: remove integration sync index creation
* refactor: require re-approval if redirectUri updated
* fix: flaky e2e test
* fix: flaky e2e test
* fix: flaky e2e test
* fix: remove duplicate common.json keys
* refactor: replace team@cal.com with SUPPORT_MAIL_ADDRESS
* refactor: generate client secret on handler level
* fix: authorization code only available to approved clients
* refactor: cubic review dont display exclamation
* refactor: cubic review website_url in common json
* fix: dont default in ui to approved status
* refactor: optiona logo in schema create handler
* fix: tests
* fix: tests
* fix: /authorize redirect if client not approved or show error
* test: authorize page with invalid client id
* refactor: dont allow refreshing tokens unless approved client
* fix: flaky e2e test
* fix: flaky e2e test
* fix: flaky e2e test
* fix: flaky e2e test
* fix: flaky e2e test
* fix: flaky e2e test
* chore: warn that pending client is not usable
* fix: approve and reject buttons
* fix: /authorize show error if client not approved
* refactor: info message about editing oauth client and status
* change info alert to warning
* try to fix ci test
* debug: failing e2e test
* fix: improve session propagation in oauth-client-admin E2E test
- Add navigateToAdminOAuthPage helper that waits for listClients API call
- If the API call doesn't arrive (session issue), reload page to force session refresh
- This fixes the CI flakiness where admin page wasn't loading due to session not having ADMIN role
Co-Authored-By: lauris@cal.com <lauris@cal.com>
* fix: register waitForResponse before navigating in E2E test
- Register the listClients waitForResponse promise BEFORE page.goto()
- This ensures the response isn't missed during page load
- Also register the promise before reload in the catch block
Co-Authored-By: lauris@cal.com <lauris@cal.com>
* fix: rename oAuth folder to oauth for case-sensitive filesystems
The admin OAuth page route was at /settings/admin/oAuth (capital A) but the
code references /settings/admin/oauth (lowercase). This caused 404 errors
on case-sensitive filesystems (Linux).
Also improved the E2E test navigation helper to retry with delays if the
admin page doesn't load immediately, handling session propagation timing.
Co-Authored-By: lauris@cal.com <lauris@cal.com>
* test style
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: eunjae@cal.com <hey@eunjae.dev>
Co-authored-by: Lauris Skraucis <lauris.skraucis@gmail.com>
Co-authored-by: supalarry <laurisskraucis@gmail.com>
Co-authored-by: cubic-dev-ai[bot] <1082092+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: lauris@cal.com <lauris@cal.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
2026-01-21 12:23:51 -03:00
Eunjae LeeGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add option to hide duration selector in booking page for multiple durations
- Add 'hideDurationSelectorInBookingPage' field to event type metadata schema
- Add checkbox under Default Duration select in event type settings
- Modify Duration component to hide selector when setting is enabled
- URL params can still set duration when selector is hidden
- Add i18n translation for the new checkbox label
- Add e2e tests for the new functionality
Co-Authored-By: ali@cal.com <ali@cal.com>
* fix: rename checkbox label to 'Hide duration selector'
Co-Authored-By: ali@cal.com <ali@cal.com>
* fix: replace text locator with data-testid in E2E test
Replace `text=Multiple duration` locator with `page.getByTestId("event-types").locator('a[title="Multiple duration"]')` to follow E2E test best practices.
Co-Authored-By: unknown <>
* fix: add data-testid to hide duration selector checkbox for E2E tests
Co-Authored-By: ali@cal.com <ali@cal.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: ali@cal.com <ali@cal.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
* Early return if date range is empty
* test: add tests for empty workingHours early return optimization
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Volnei Munhoz <volnei@cal.com>
PR #27012 introduced logic to disable apps without valid keys during seeding.
This caused the alby payment app tests to fail because the alby app was
disabled in the App table when its environment keys weren't configured.
This fix adds an ensureAppEnabled helper function that enables the app
in the App table before running the tests, treating it as a mock/test
setup step.
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Add 40 minutes to the multipleDurationOptions array in EventSetupTab
- Add comprehensive tests for 40-minute slot generation including:
- Full day slot generation
- Correct time intervals
- Default duration handling
- Same day booking with time constraints
- Multiple date ranges
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: ali@cal.com <ali@cal.com>
## What does this PR do?
Fixes a bug where the UI shows team members who match segment criteria even when they don't have host entries in the database. When `assignAllTeamMembers` is `true` and segment filtering is enabled, members would appear in the Assignment tab but wouldn't actually be assigned during booking because they lack host entries.
**The Problem:**
- The filtering logic in `EditWeightsForAllTeamMembers` short-circuited when `assignAllTeamMembers` was true, showing all segment-matching members regardless of whether they had host entries
- The `handleSave` function only updates hosts that already exist in the `value` array, filtering out members without host entries
- This created a misleading UI where members appeared but wouldn't be assigned
**The Fix:**
- Removed the `assignAllTeamMembers` prop from `EditWeightsForAllTeamMembers` component entirely since the filtering should always check for existing host entries
- Updated the filter in `EditWeightsForAllTeamMembers.tsx` to always check for existing host entries in the `value` array
- Added `filterMemberIds` prop to `Segment` component to filter matching team members to only show those who are hosts of the event-type
- `AddMembersWithSwitch` now passes the list of non-fixed host user IDs to the Segment component via `filterMemberIds`
## 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.
- [ ] I confirm automated tests are in place that prove my fix is effective or that my feature works.
## How should this be tested?
1. Create a team event type with round-robin scheduling
2. Enable "Assign all team members" toggle
3. Enable segment filtering with criteria that matches some team members
4. Verify that only members who have host entries (are actually assigned to the event type) appear in the "Edit team member weights" sheet
5. Members matching segment criteria but without host entries should NOT be displayed
## 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 the filtering logic correctly shows only members with host entries in both `EditWeightsForAllTeamMembers` and `Segment` components
- [ ] Confirm this aligns with the actual booking behavior (members without host entries won't be assigned)
- [ ] Check that `filterMemberIds` prop is correctly passed through `AddMembersWithSwitch` → `MembersSegmentWithToggle` → `Segment` → `MatchingTeamMembers`
- [ ] Verify the filter `value.filter((host) => !host.isFixed).map((host) => host.userId)` correctly extracts non-fixed host IDs
---
Link to Devin run: https://app.devin.ai/sessions/3333b41226d0452e98ef7ac358511f5b
Requested by: @hariombalhara
2026-01-20 07:01:49 +05:30
Anik Dhabal BabuGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* ci(companion): add separate typecheck workflow to catch type errors
This adds a new companion-typecheck.yml workflow that runs TypeScript type
checking for the companion app. This would have caught the missing useEffect
import issue in PR #26931.
Changes:
- Add new companion-typecheck.yml workflow file
- Update pr.yml to call the new workflow when companion files change
- Add typecheck-companion to the required jobs list
Co-Authored-By: anik@cal.com <adhabal2002@gmail.com>
* add lint checks
* test
* remove
* update typecheck
* address review
* chore:- hide apps with missing required keys from app store
* update
* Delete packages/app-store/_utils/hasRequiredAppKeys.test.ts
* Update validateAppKeys.ts
* Update validateAppKeys.ts
* Update validateAppKeys.test.ts
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-19 19:32:30 +00:00
Dhairyashil ShindeGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>peer@cal.com <peer@cal.com>
* feat: hide navigation when ?standalone=true URL parameter is present
Co-Authored-By: peer@cal.com <peer@cal.com>
* feat: standalone page config to use in companion
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: peer@cal.com <peer@cal.com>
2026-01-19 19:27:14 +00:00
Eunjae LeeGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* 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>
* fix: update transaction timeout for large managed event-types
* test: add findMany mock for batch update optimization in handleChildrenEventTypes tests
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: reduce batch size to 50 and use skipDuplicates for workflow linkage
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* test: add comprehensive tests for batch execution and retry behavior
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: use logger instead of console.log and fix type error
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* test: update test file to mock logger instead of console.log
Co-Authored-By: morgan@cal.com <morgan@cal.com>
* fix: type issues
* fixup! fix: type issues
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: keith@cal.com <keithwillcode@gmail.com>
2026-01-19 20:37:21 +04:00
sean-brydonGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: redesign team creation flow to match onboarding-v3 design
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* feat: skip invite options and go directly to email invite step
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* feat: invalidate teams query on submit to refresh teams list
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: use server action to invalidate server-side teams cache
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: conditionally render avatar in browser view to remove extra padding
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix browser view
* test: update team creation E2E tests to use new onboarding-v3 flow
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* test: update auth-index.e2e.ts to use new team creation flow
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* test: update team-management.e2e.ts to use new team creation flow
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: add error handling for createTeam and improve CSV parsing for quoted fields
Co-Authored-By: sean@cal.com <Sean@brydon.io>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix init
* remove comment
* fix to v2
* type fix
* edge case
* test fix to suit the date storage method
* fix for atoms
* backward compatibility
* fix test mock
* test fix?
* testing a theory
* address cubic
- Add interpolation: { escapeValue: false } to AttendeeRequestEmail.tsx
- Add interpolation: { escapeValue: false } to attendee-request-email.ts
- Add interpolation: { escapeValue: false } to bookings-single-view.tsx
This prevents special characters like '/' from being HTML-encoded to '/'
in booking confirmation emails and success page dialogs.
Fixes#26938
2026-01-17 04:53:38 +00:00
Eesh MidhaGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
## 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
2026-01-16 11:19:25 +01:00
Peer RichelsenGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix(user-dropdown): make SSR-safe and fix ESLint warning for Beacon
* fix: added ssr guard in second useEffect and added type for beacon instead of ts-ignoring
* fix: add dependency array to Beacon useEffect
Address review feedback by adding [user?.username] dependency array
to the Beacon session-data useEffect, improving performance by
preventing unnecessary re-runs on every render.
Co-authored-by: albin-baby-2002 <albinbaby2002@gmail.com>
Co-Authored-By: unknown <>
* test: add automated tests for UserDropdown Beacon functionality
Add comprehensive tests for:
- Beacon session-data calls with correct payload
- Handling of undefined Beacon (no errors)
- Username change triggering useEffect re-run
- SSR safety (window undefined check)
- Component rendering states (loading, user available, no user)
Co-authored-by: albin-baby-2002 <albinbaby2002@gmail.com>
Co-Authored-By: unknown <>
* refactor: remove useless comments and misleading SSR test
- Remove redundant comments above vi.mock calls (per keithwillcode feedback)
- Remove SSR safety test that provided false coverage since jsdom always has window defined (per Cubic feedback)
- The 'should not throw error when Beacon is undefined' test already covers graceful handling
Co-Authored-By: unknown <>
* fix: remove unused @ts-expect-error directives
The Window interface is augmented with optional Beacon and Support properties,
so TypeScript allows deleting them without errors.
Co-Authored-By: unknown <>
* fix: handle lazy-loaded Beacon with polling
When Beacon loads lazily after component mount, the useEffect now polls
every second until Beacon becomes available, then sends session data
and clears the interval. This ensures session info is always sent even
when HelpScout loads asynchronously.
Added test to verify lazy loading behavior works correctly.
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: albin-baby-2002 <albinbaby2002@gmail.com>
* introduce a dependsOn permission string
* fix permissions toggle
* add DFS to allow permission chains
* Update packages/features/pbac/utils/permissionTraversal.ts
Co-authored-by: Eunjae Lee <hey@eunjae.dev>
* fix splitPerms to work with attributes or dotted resources
* CodeRabbit Generated Unit Tests: Add unit tests for permissions hooks, registry, and traversal
* Fix UTG issues (iteration 1)
---------
Co-authored-by: Sean Brydon <sean@cal.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Eunjae Lee <hey@eunjae.dev>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2026-01-15 16:42:45 +00:00
sean-brydonGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* refactor: migrate MembershipRole usages to PBAC permission checks
- Refactor get.handler.ts to use PermissionCheckService for canUpdateTeams
- Refactor checkForInvalidAppCredentials.ts to use getTeamIdsWithPermission
- Refactor outOfOffice.utils.ts to use checkPermission for ooo.update
- Refactor checkIfOrgNeedsUpgrade.handler.ts to use organization.manageBilling
- Refactor getActiveOnOptions.handler.ts to use eventType.update permission
- Refactor WorkflowRepository.ts to use workflow.update permission
- Refactor organization.tsx to use team.update permission
- Refactor getEventTypesByViewer.ts to use eventType.update permission
- Refactor getPublicEvent.ts to use team.read permission for private teams
- Update CreateNewOutOfOfficeEntryButton.tsx to use canUpdateOOO prop
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: use organization.update permission instead of team.update for org management
Co-Authored-By: sean@cal.com <Sean@brydon.io>
* fix: rename teamsWithEventTypeManagePermission to teamsWithEventTypeUpdatePermission
Renamed variable to match the permission string being used (eventType.update)
Co-Authored-By: sean@cal.com <Sean@brydon.io>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-15 15:59:00 +01:00
Keith WilliamsGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* perf(app-store): convert services to factory functions to narrow SDK type exports
This change converts CRM, Calendar, Payment, and Analytics services from
exporting classes to exporting factory functions that return interface types.
This prevents SDK types (HubSpot, Stripe, etc.) from leaking into the type
system when TypeScript emits .d.ts files.
Services modified:
- CRM: hubspot, salesforce, closecom, pipedrive-crm, zoho-bigin, zohocrm
- Calendar: all 13 calendar services
- Payment: stripe, paypal, alby, btcpayserver, hitpay, mock-payment-app
- Analytics: dub
Video adapters were audited and already use factory pattern.
WIP: Salesforce CRM service has a type error that needs fixing.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix(salesforce): add type assertion for appOptions in factory function
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: update remaining consumers to use factory functions
- getAnalytics.ts: call factory function instead of new
- getConnectedApps.ts: call factory function instead of new
- salesforce/CrmService.ts: fix type assertion with default value
- salesforce/routingForm/incompleteBookingAction.ts: use factory function
- salesforce/routingFormBookingFormHandler.ts: use factory function
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix(salesforce): add SalesforceCRM interface for Salesforce-specific methods
- Create SalesforceCRM interface extending CRM with findUserEmailFromLookupField and incompleteBookingWriteToRecord methods
- Add createSalesforceCrmServiceWithSalesforceType factory function for internal Salesforce modules
- Update routing form files to use the new factory function with proper typing
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix(salesforce): correct return type in SalesforceCRM interface
The findUserEmailFromLookupField method returns { email: string; recordType: RoutingReasons } | undefined,
not string | undefined. Updated the interface to match the actual implementation.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: update all call sites to use factory functions
- Update calendar API add files to use factory functions (7 files)
- Update Google Calendar test files to use factory functions (3 files)
- Update Salesforce test files to use SalesforceCRM interface
- Add testMode parameter to createSalesforceCrmServiceWithSalesforceType
- Remove unused @ts-expect-error directive in bookingScenario.ts
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: add GoogleCalendar interface and update factory functions for service-specific methods
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: add type annotation to attendee parameter in google-calendar.e2e.ts
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: update selected-calendars/route.ts to use GoogleCalendar factory function
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: update remaining GoogleCalendarService call sites to use factory function
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: remove explicit type annotation in google-calendar.e2e.ts to fix type error
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: update test mocks to use factory function pattern for calendar and payment services
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: convert MockPaymentService to factory function in setupVitest.ts
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix(api-v2): call calendar service factory functions instead of using new
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* perf(trpc): add TypeScript project references to reduce build file count
- Add tsconfig.build.json to app-store with composite settings for declaration emit
- Add tsconfig.server.build.json to trpc with project references
- Add types and typesVersions to app-store package.json to redirect type resolution to dist-types
- Add build:types script to app-store for generating declarations
- Add dist-types to .gitignore
This reduces the tRPC build file count from 7,733 to 5,618 files (27% reduction)
by having TypeScript resolve to prebuilt .d.ts files instead of source files.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix(app-store): add fallback to typesVersions for CI compatibility
The typesVersions now prefers dist-types but falls back to source files
when dist-types don't exist. This fixes CI type-check failures while
still allowing the optimization when dist-types are built.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* Added build dependency for tRPC on app-store
* fix(app-store): exclude test directories from tsconfig.build.json
Exclude __tests__, __mocks__, and tests directories from the build
config to prevent test utility files (which import from outside rootDir)
from being included in the declaration emit.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix(turbo): add build:types task definition for app-store
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix(turbo): remove circular build dependency between trpc and app-store
The build:types task for app-store transitively imports from @calcom/features,
which imports from @calcom/trpc. This creates a circular build dependency when
@calcom/trpc#build depends on @calcom/app-store#build:types.
Solution: Remove the turbo dependency. The typesVersions fallback pattern
['./dist-types/*', './*'] will use source files when dist-types/ doesn't exist,
and use prebuilt declarations when they do exist (for faster builds).
Also exclude dist-types from regular tsconfig.json to prevent 'Cannot write file'
errors when dist-types/ exists.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* refactor(app-store): rename dist-types to types for consistency
Rename the prebuilt TypeScript declarations folder from dist-types to types
to match the convention used by @calcom/trpc and other packages in the monorepo.
Updated files:
- tsconfig.build.json: declarationDir and exclude
- tsconfig.json: exclude
- package.json: typesVersions paths
- turbo.json: build:types outputs
- .gitignore: ignore path
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix(api-v2): update ICS calendar test to mock factory function instead of class prototype
The IcsFeedCalendarService is now a factory function, not a class, so
jest.spyOn(IcsFeedCalendarService.prototype, 'listCalendars') no longer works.
Updated to use jest.spyOn(appStore, 'IcsFeedCalendarService').mockImplementation()
to mock the factory function return value instead.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* refactor(app-store): rename factory functions to Build* naming convention
- Rename Calendar factory functions from create*CalendarService to BuildCalendarService
- Rename CRM factory functions from create*CrmService to BuildCrmService
- Rename Payment factory functions from PaymentService to BuildPaymentService
- Rename Analytics factory function from createDubAnalyticsService to BuildAnalyticsService
- Update all index.ts re-exports to use new names
- Update all call sites throughout the codebase
- Update test mocks to use new factory function names
This makes it clear that these are factory functions, not class constructors.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix(app-store): update remaining CalendarService and PaymentService imports to Build* names
- Update api/add.ts files for applecalendar, caldavcalendar, exchange2013calendar, exchange2016calendar, exchangecalendar, ics-feedcalendar
- Update mock-payment-app index.ts to export BuildPaymentService
- Fix googlecalendar test import alias for createInMemoryDelegationCredentialForBuildCalendarService
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix(tests): update payment service mocks to use BuildPaymentService
- Update setupVitest.ts to use BuildPaymentService instead of PaymentService
- Update handlePayment.test.ts mock to use BuildPaymentService
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* refactor: address PR review comments - rename to Build* and remove unused code
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* refactor: remove explanatory comments and fix indentation
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* chore: update .gitignore to use *.tsbuildinfo pattern
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix(api-v2): update IcsFeedCalendarService to BuildIcsFeedCalendarService in e2e test
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* style: format CalendarService.test.ts
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* Delete apps/ui-playground/next-env.d.ts
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>