Skip to content

Comments

feat: add calendar cache status and actions#22532

Merged
emrysal merged 28 commits intomainfrom
devin/calendar-cache-tooltip-1752595047
Jul 22, 2025
Merged

feat: add calendar cache status and actions#22532
emrysal merged 28 commits intomainfrom
devin/calendar-cache-tooltip-1752595047

Conversation

@zomars
Copy link
Contributor

@zomars zomars commented Jul 15, 2025

Summary

imagen imagen

This pull request introduces a new feature to manage calendar cache data, including the ability to view cache status and delete cached data. It also includes several supporting updates to repositories, APIs, and UI components. Below is a summary of the most important changes grouped by theme.

New Feature: Calendar Cache Management

  • Added a deleteCache mutation to the TRPC calendarsRouter, enabling users to delete cached calendar data by credential ID. ([packages/trpc/server/routers/viewer/calendars/_router.tsxR27-R33](https://github.com/calcom/cal.com/pull/22532/files#diff-9e053175cc6dfb5717313e0587a730fff132f9d3c1200204f0ce8dac53a19280R27-R33))
  • Introduced the deleteCacheHandler to handle cache deletion logic, including validation of user access to the specified credential. ([packages/trpc/server/routers/viewer/calendars/deleteCache.handler.tsR1-R33](https://github.com/calcom/cal.com/pull/22532/files#diff-572888b8e0555167a5787847f29d5a46623eff170491acc0654e916f5b4afd18R1-R33))
  • Updated the connectedCalendarsHandler to enrich calendar data with cache status (cacheUpdatedAt) by querying the CalendarCacheRepository. ([packages/trpc/server/routers/viewer/calendars/connectedCalendars.handler.tsR27-R39](https://github.com/calcom/cal.com/pull/22532/files#diff-3f6a556ad60f26d0162770fcd81b5bddeb6ab0437552ac792045c3cd2608d710R27-R39))

UI Enhancements

  • Created a new CredentialActionsDropdown component to display cache status and provide options to delete cached data or disconnect integrations. ([packages/features/apps/components/CredentialActionsDropdown.tsxR1-R134](https://github.com/calcom/cal.com/pull/22532/files#diff-c78273434b95ab8276bb5eb24d9bc088b10af029388bdcd08cbe478f44269b31R1-R134))
  • Replaced the DisconnectIntegration component with CredentialActionsDropdown in the SelectedCalendarsSettingsWebWrapper UI, integrating the new cache management functionality. ([[1]](https://github.com/calcom/cal.com/pull/22532/files#diff-831b0874e07f01721f87926262c5c9674ff9d7443741dfb71ceb849656345b00L5-R5), [[2]](https://github.com/calcom/cal.com/pull/22532/files#diff-831b0874e07f01721f87926262c5c9674ff9d7443741dfb71ceb849656345b00L70-L81), [[3]](https://github.com/calcom/cal.com/pull/22532/files#diff-831b0874e07f01721f87926262c5c9674ff9d7443741dfb71ceb849656345b00L125-L135))

Repository and Database Updates

  • Added a getCacheStatusByCredentialIds method to the CalendarCacheRepository and its mock implementation to fetch cache statuses for multiple credentials. ([[1]](https://github.com/calcom/cal.com/pull/22532/files#diff-b36c72c0db751ba0cafe234dfa150817672869825333c22b074c4977a6135b8dR30-R32), [[2]](https://github.com/calcom/cal.com/pull/22532/files#diff-ceffbae9ef3da413495feac73a341672e77ffaf493cf67ada0b637ead80ded38R26-R30), [[3]](https://github.com/calcom/cal.com/pull/22532/files#diff-4cf8d3089fad7b6c8fe4172d8d42147f136b65baf30b726e57b9b10d179d4a99R172-R188))
  • Introduced a new updateManyByCredentialId method in the SelectedCalendarRepository to update multiple calendars by credential ID. ([packages/lib/server/repository/selectedCalendar.tsR400-R406](https://github.com/calcom/cal.com/pull/22532/files#diff-ccb4eecfa701e5b0c7d6ba87dcc550cdf3700a63ee252849045611599ecb9273R400-R406))
  • Added an updatedAt column to the CalendarCache table in the database schema and Prisma model to track the last update timestamp. ([[1]](https://github.com/calcom/cal.com/pull/22532/files#diff-9f597bd98bbcfdcf4861ee7bf0c238e7dfe54b456ceb69b852aaf3979c4102cfR1-R8), [[2]](https://github.com/calcom/cal.com/pull/22532/files#diff-56fa4d384ba6fb94b130e9eb42c5cad00734b025ebd6c197f76873469725ae87R1718))

Localization and Strings

  • Added new localization strings for cache management actions, such as "Cache Status," "Delete cached data," and "Cache deleted successfully." ([apps/web/public/static/locales/en/common.jsonR3376-R3382](https://github.com/calcom/cal.com/pull/22532/files#diff-57de4b8e5231f1d699891d98b0381d56e9e24537b0ca5420d1fba4f0597370bcR3376-R3382))

Miscellaneous

  • Updated package.json to replace ts-node with npx tsx for running the dev:cron script. ([apps/web/package.jsonL11-R11](https://github.com/calcom/cal.com/pull/22532/files#diff-14b60f636e1a2b0061da57aaf231cb1ed15a5dc0c592425ed82e58fec95d42d8L11-R11))

Review & Testing Checklist for Human

🔴 High Priority (5 items)

  • Verify deleteCache tRPC mutation exists - The component references trpc.viewer.calendars.deleteCache.useMutation() but this mutation implementation is not visible in the PR changes. Check if this endpoint exists or needs to be created.
  • End-to-end testing with Google Calendar - Install a Google Calendar integration and verify the credential-level dropdown appears, shows cache status, and deletion flow works correctly with confirmation dialog.
  • Test cache status display logic - Verify that cacheUpdatedAt timestamps are correctly formatted and displayed only for Google Calendar credentials with actual cache data.
  • Confirm repository pattern correctness - Test that getCacheStatusByCredentialIds() returns accurate data and the credential-to-cache mapping works properly in the UI.
  • Verify dropdown conditional rendering - Ensure the dropdown only appears for Google Calendar credentials and handles edge cases (no cache, disabled integrations, etc.).

Recommended Test Plan:

  1. Connect a Google Calendar integration to trigger cache creation
  2. Navigate to /apps/installed/calendar
  3. Verify dropdown appears on Google Calendar credential with cache status and timestamp
  4. Test "Delete cached data" action shows confirmation dialog
  5. Confirm cache deletion works and UI updates appropriately
  6. Test "Remove App" functionality still works correctly

Diagram

%%{ init : { "theme" : "default" }}%%
graph TD
    UI["CredentialActionsDropdown.tsx<br/>(New Component)"]:::major-edit
    Handler["connectedCalendars.handler.ts<br/>(Updated tRPC Handler)"]:::major-edit
    RepoInterface["calendar-cache.repository.interface.ts<br/>(Updated Interface)"]:::minor-edit
    RepoImpl["calendar-cache.repository.ts<br/>(Updated Implementation)"]:::minor-edit
    RepoMock["calendar-cache.repository.mock.ts<br/>(Updated Mock)"]:::minor-edit
    Translations["common.json<br/>(Added Translation Keys)"]:::minor-edit
    
    UI -->|"Uses repository via tRPC"| Handler
    Handler -->|"Calls getCacheStatusByCredentialIds"| RepoImpl
    RepoImpl -->|"Implements"| RepoInterface
    RepoMock -->|"Implements"| RepoInterface
    UI -->|"Uses translation keys"| Translations
    
    subgraph Legend
        L1[Major Edit]:::major-edit
        L2[Minor Edit]:::minor-edit
        L3[Context/No Edit]:::context
    end

    classDef major-edit fill:#90EE90
    classDef minor-edit fill:#87CEEB
    classDef context fill:#FFFFFF
Loading

Notes

  • Session Details: Requested by @zomars, implemented in Devin session: https://app.devin.ai/sessions/24545e0980df465995521419432a2a52
  • SelectedCalendar.updatedAt Usage: Currently only updated in backend via Google webhook handler but not displayed in frontend. Frontend uses cacheUpdatedAt from CalendarCache. Consider if SelectedCalendar.updatedAt update should be removed.
  • Import Path Resolution: Had to fix UI component import paths during development - watch for potential module resolution issues in different environments.
  • Testing Limitation: Local testing was limited due to no installed calendar integrations - end-to-end verification with real Google Calendar data is essential.

- Add updatedAt field to CalendarCache schema with migration
- Create tRPC cacheStatus endpoint for fetching cache timestamps
- Add action dropdown to CalendarSwitch for Google Calendar entries
- Display formatted last updated timestamp in dropdown
- Add placeholder for cache deletion functionality
- Include translation strings for dropdown content

The dropdown only appears for Google Calendar integrations that have
active cache entries and provides cache management options for future
extensibility.

Co-Authored-By: zomars@cal.com <zomars@me.com>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 15, 2025

Walkthrough

This update introduces several new features and modifications related to calendar cache management and credential actions. A new database column (updatedAt) is added to the CalendarCache table and schema to track cache update times. The backend now supports fetching and deleting cache status by credential, with new repository methods and a TRPC mutation (deleteCache). The connected calendars API enriches responses with cache update timestamps. On the frontend, a CredentialActionsDropdown React component is introduced, providing UI for cache deletion and credential disconnection, and is integrated into the calendar settings view. Additional localization strings and a utility script for Google Calendar webhook testing are also included.


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added the ❗️ migrations contains migration files label Jul 15, 2025
@vercel
Copy link

vercel bot commented Jul 15, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
cal ⬜️ Ignored (Inspect) Visit Preview Jul 18, 2025 8:13pm
cal-eu ⬜️ Ignored (Inspect) Visit Preview Jul 18, 2025 8:13pm

@keithwillcode keithwillcode added core area: core, team members only foundation labels Jul 15, 2025
@delve-auditor
Copy link

delve-auditor bot commented Jul 15, 2025

No security or compliance issues detected. Reviewed everything up to 5fd11f9.

Security Overview
  • 🔎 Scanned files: 17 changed file(s)
Detected Code Changes
Change Type Relevant files
Enhancement ► CalendarService.ts
    Update SelectedCalendar.updatedAt for calendar credentials
► CredentialActionsDropdown.tsx
    Add new calendar credential actions component
► calendar-cache.repository.ts
    Add cache status retrieval functionality
Configuration changes ► schema.prisma
    Add updatedAt field to CalendarCache table
► migration.sql
    Add calendar cache updatedAt column
Other ► common.json
    Add new cache-related translations
► package.json
    Update dev:cron command

Reply to this PR with @delve-auditor followed by a description of what change you want and we'll auto-submit a change to this PR to implement it.

- Remove problematic satisfies clause in selectedCalendar.ts
- Add missing cacheStatus parameter to ConnectedCalendarList component
- Fixes type errors that were preventing CI from passing

Co-Authored-By: zomars@cal.com <zomars@me.com>
@github-actions
Copy link
Contributor

github-actions bot commented Jul 15, 2025

E2E results are ready!

- Remove separate cacheStatus tRPC endpoint as requested
- Return cache status as separate field in connectedCalendars response
- Update UI components to use cache data from connectedCalendars
- Fix Prisma type incompatibilities in repository files

Co-Authored-By: zomars@cal.com <zomars@me.com>
…e status

- Fix Prisma.SortOrder usage in membership.ts orderBy clauses
- Remove problematic satisfies clause in selectedCalendar.ts
- Fix TeamSelect type reference in team.ts
- Update SelectedCalendarsSettingsWebWrapper to properly pass cacheStatus data flow

Co-Authored-By: zomars@cal.com <zomars@me.com>
zomars and others added 3 commits July 15, 2025 13:21
…ription logic

- Fix timestamp HTML entity encoding with interpolation escapeValue: false
- Only show dropdown for subscribed Google calendars (googleChannelId exists)
- Hide delete option when no cache data exists
- Include updatedAt and googleChannelId fields upstream in user repository
- Update data flow to pass subscription status through components

Co-Authored-By: zomars@cal.com <zomars@me.com>
…cache refresh

- Add updateManyByCredentialId method to SelectedCalendarRepository
- Update fetchAvailabilityAndSetCache to refresh SelectedCalendar timestamps
- Ensure webhook flow updates both CalendarCache and SelectedCalendar records
- Maintain proper timestamp tracking for calendar cache operations

Co-Authored-By: zomars@cal.com <zomars@me.com>
zomars and others added 4 commits July 16, 2025 09:25
Introduces test-gcal-webhooks.sh to start Tunnelmole, extract the public URL, and update GOOGLE_WEBHOOK_URL in the .env file. Handles process management, rate limits, and ensures environment configuration for Google Calendar webhooks.
Replaces 'ts-node' with 'npx tsx' in the dev:cron script for running cron-tester.ts, likely to improve compatibility or leverage tsx features.
Renamed 'last_updated' to 'cache_last_updated' in locale file for clarity and updated CalendarSwitch to use the new string. Also added dark mode text color support for cache status display.
…ove App

- Create CredentialActionsDropdown component consolidating cache and app removal actions
- Add deleteCache tRPC mutation for credential-level cache deletion
- Update connectedCalendars handler to include cacheUpdatedAt at credential level
- Move dropdown from individual CalendarSwitch to credential level in SelectedCalendarsSettingsWebWrapper
- Remove cache-related props from CalendarSwitch component
- Add translation strings for cache management actions
- Consolidate all credential-level actions (cache management + Remove App) in one dropdown

Co-Authored-By: zomars@cal.com <zomars@me.com>
- Remove duplicate cache-related keys at lines 51-56
- Keep properly positioned keys later in file
- Addresses GitHub comment from zomars about duplicate keys

Co-Authored-By: zomars@cal.com <zomars@me.com>
@vercel vercel bot temporarily deployed to Preview – api July 16, 2025 17:52 Inactive
zomars added 2 commits July 17, 2025 12:02
Replaces the DisconnectIntegration component with an inline confirmation dialog for removing app credentials. Adds disconnect mutation logic and updates UI to improve user experience and consistency.
@zomars zomars marked this pull request as ready for review July 17, 2025 19:13
@zomars zomars requested review from a team July 17, 2025 19:13
@zomars zomars requested a review from a team as a code owner July 17, 2025 19:13
@dosubot dosubot bot added calendar-apps area: calendar, google calendar, outlook, lark, microsoft 365, apple calendar ✨ feature New feature or request labels Jul 17, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (3)
apps/web/public/static/locales/en/common.json (1)

3376-3379: Potential duplicate key: cache_last_updated
A key with the same name was already introduced earlier in this file. JSON objects cannot contain duplicate keys – only the last occurrence will be retained at runtime, silently shadowing the previous one and breaking i18n calls that expect the first value.

-  "cache_last_updated": "Last updated: {{timestamp}}",
+  // 🔄  remove or rename – a key with this name already exists above

Please deduplicate (or rename) before shipping.

packages/trpc/server/routers/viewer/calendars/deleteCache.handler.ts (2)

17-22: Use repository pattern instead of direct Prisma calls.

This code violates the established architectural pattern by making direct Prisma calls outside a repository. Based on previous review feedback, all database operations should go through repositories.

Consider creating a method in a credential repository for this validation:

-  const credential = await prisma.credential.findFirst({
-    where: {
-      id: credentialId,
-      userId: user.id,
-    },
-  });
+  const credentialRepository = new CredentialRepository();
+  const credential = await credentialRepository.findByIdAndUserId(credentialId, user.id);

28-30: Use CalendarCacheRepository for cache deletion.

Direct Prisma calls should be avoided. Use the existing CalendarCacheRepository for cache operations.

-  await prisma.calendarCache.deleteMany({
-    where: { credentialId },
-  });
+  const cacheRepository = new CalendarCacheRepository();
+  await cacheRepository.deleteCacheByCredentialId(credentialId);

Note: You may need to add the deleteCacheByCredentialId method to the repository interface and implementation.

🧹 Nitpick comments (5)
apps/web/public/static/locales/en/common.json (1)

3376-3382: Nit: group related keys for maintainability
Consider keeping the new cache-related strings together (status / last-updated / actions / confirmations) and adding a brief comment block; this makes it easier for translators to locate context in large files.

packages/features/apps/components/CredentialActionsDropdown.tsx (1)

88-94: Consider using dynamic locale for date formatting.

The date formatting is hardcoded to "en-US" locale. Consider using the user's locale for better internationalization support.

-                    {t("cache_last_updated", {
-                      timestamp: new Intl.DateTimeFormat("en-US", {
-                        dateStyle: "short",
-                        timeStyle: "short",
-                      }).format(new Date(cacheUpdatedAt)),
-                      interpolation: { escapeValue: false },
-                    })}
+                    {t("cache_last_updated", {
+                      timestamp: new Intl.DateTimeFormat(undefined, {
+                        dateStyle: "short",
+                        timeStyle: "short",
+                      }).format(new Date(cacheUpdatedAt)),
+                    })}
scripts/test-gcal-webhooks.sh (3)

4-9: Mark constants as read-only & quote interpolations

  1. Prefix immutable config vars with readonly to prevent accidental reassignment.
  2. Quote $TM_PORT in the pgrep pattern to avoid glob/word-splitting surprises when the port is changed to a value containing spaces (unlikely but defensive).
-readonly LOG_FILE="/tmp/tmole.log"
-readonly ENV_FILE="../.env"
-readonly TM_PORT=3000
-readonly TM_KEYWORD="https://.*\.tunnelmole\.net"
-TMOLE_RUNNING=$(pgrep -f "tmole $TM_PORT")
+readonly LOG_FILE="/tmp/tmole.log"
+readonly ENV_FILE="../.env"
+readonly TM_PORT=3000
+readonly TM_KEYWORD='https://.*\.tunnelmole\.net'
+# Quote port in pattern to avoid word-splitting
+TMOLE_RUNNING=$(pgrep -f "tmole ${TM_PORT}")

35-38: Quote $TM_PORT when invoking tmole

Without quotes Bash will perform pathname expansion if someone sets TM_PORT to a glob-like value, leading to a cryptic failure.

-  tmole $TM_PORT > "$LOG_FILE" 2>&1 &
+  tmole "$TM_PORT" > "$LOG_FILE" 2>&1 &

41-43: Loop index i is unused – silence Shellcheck & intent-clarify

Shellcheck SC2034 flags i as unused. Replace with _ or switch to seq for clarity.

-for i in {1..20}; do
+for _ in {1..20}; do
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f95cff and 77bbc37.

📒 Files selected for processing (18)
  • apps/web/package.json (1 hunks)
  • apps/web/pages/api/integrations/[...args].ts (1 hunks)
  • apps/web/public/static/locales/en/common.json (1 hunks)
  • packages/app-store/googlecalendar/lib/CalendarService.ts (1 hunks)
  • packages/features/apps/components/CredentialActionsDropdown.tsx (1 hunks)
  • packages/features/calendar-cache/calendar-cache.repository.interface.ts (1 hunks)
  • packages/features/calendar-cache/calendar-cache.repository.mock.ts (1 hunks)
  • packages/features/calendar-cache/calendar-cache.repository.ts (1 hunks)
  • packages/lib/getConnectedDestinationCalendars.ts (1 hunks)
  • packages/lib/server/repository/selectedCalendar.ts (2 hunks)
  • packages/lib/server/repository/user.ts (1 hunks)
  • packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsWebWrapper.tsx (5 hunks)
  • packages/prisma/migrations/20250715160635_add_calendar_cache_updated_at/migration.sql (1 hunks)
  • packages/prisma/schema.prisma (1 hunks)
  • packages/trpc/server/routers/viewer/calendars/_router.tsx (2 hunks)
  • packages/trpc/server/routers/viewer/calendars/connectedCalendars.handler.ts (2 hunks)
  • packages/trpc/server/routers/viewer/calendars/deleteCache.handler.ts (1 hunks)
  • scripts/test-gcal-webhooks.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
apps/web/public/static/locales/en/common.json (1)

undefined

<retrieved_learning>
Learnt from: bandhan-majumder
PR: #22359
File: packages/lib/server/locales/en/common.json:1336-1339
Timestamp: 2025-07-14T16:31:45.201Z
Learning: When making localization changes for new features, it's often safer to add new strings rather than modify existing ones to avoid breaking existing functionality that depends on the original strings. This approach allows for feature-specific customization while maintaining backward compatibility.
</retrieved_learning>

🧬 Code Graph Analysis (2)
packages/trpc/server/routers/viewer/calendars/_router.tsx (1)
packages/trpc/server/routers/viewer/calendars/deleteCache.handler.ts (1)
  • deleteCacheHandler (13-33)
packages/features/apps/components/CredentialActionsDropdown.tsx (1)
packages/ui/components/dropdown/Dropdown.tsx (5)
  • Dropdown (12-12)
  • DropdownMenuTrigger (15-26)
  • DropdownMenuContent (34-51)
  • DropdownMenuItem (63-71)
  • DropdownItem (161-181)
🪛 Shellcheck (0.10.0)
scripts/test-gcal-webhooks.sh

[warning] 41-41: i appears unused. Verify use (or export if used externally).

(SC2034)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Production builds / Build Atoms
  • GitHub Check: Type check / check-types
  • GitHub Check: Production builds / Build API v2
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Tests / Unit
  • GitHub Check: Security Check
🔇 Additional comments (24)
packages/lib/server/repository/user.ts (1)

899-900: LGTM – Prisma schema includes required fields

The SelectedCalendar model in packages/prisma/schema.prisma already defines both fields:

  • updatedAt DateTime? @updatedAt
  • googleChannelId String? (with @@unique([googleChannelId, eventTypeId]))

No further changes are needed here.

packages/features/calendar-cache/calendar-cache.repository.mock.ts (1)

27-30: LGTM! Consistent mock implementation.

The getCacheStatusByCredentialIds method follows the established pattern in this mock class - logging the skip message and returning an appropriate default value (empty array).

packages/app-store/googlecalendar/lib/CalendarService.ts (1)

1022-1024: Update selected calendar timestamps after cache refresh - looks good!

This change correctly updates the updatedAt timestamp for all selected calendars associated with the credential after successfully fetching and caching availability data. The empty update object {} will trigger Prisma's automatic updatedAt field update, which provides the cache status information displayed in the new UI components.

Regarding the past review comment about frontend usage: Yes, this data is actively used in the frontend through the new CredentialActionsDropdown component to display cache status and enable cache management actions.

apps/web/pages/api/integrations/[...args].ts (1)

74-75: Good cleanup of response handling logic.

This change improves the code by removing the unnecessary return of the response object. Since the response is handled by reference and the function should complete the response handling, returning undefined is more appropriate than returning the response object itself.

packages/features/calendar-cache/calendar-cache.repository.interface.ts (1)

30-32: Well-designed interface addition for cache status tracking.

The new getCacheStatusByCredentialIds method is properly designed with:

  • Clear method name indicating batch cache status retrieval
  • Appropriate input type for credential ID array
  • Well-structured return type with nullable updatedAt for missing cache entries
  • Consistent async/await pattern

This supports the new cache management feature effectively.

packages/trpc/server/routers/viewer/calendars/_router.tsx (2)

1-2: Necessary import addition for zod validation.

The zod import is correctly added to support the input validation in the new deleteCache mutation.


27-33: Well-implemented cache deletion mutation.

The new deleteCache mutation follows established patterns:

  • Properly uses authedProcedure for authentication
  • Validates input with appropriate zod schema
  • Follows the dynamic import pattern for consistency
  • The corresponding handler (shown in relevant code snippets) properly validates credential ownership before deletion
packages/lib/server/repository/selectedCalendar.ts (2)

260-260: Good simplification of the findMany method.

Removing the intermediate variable and satisfies operator makes the code more concise while maintaining the same functionality. This is a clean improvement.


400-405: Well-implemented bulk update method.

The new updateManyByCredentialId method is properly designed:

  • Clear method name indicating bulk update operation
  • Appropriate parameter types using Prisma types
  • Correct use of updateMany for bulk operations
  • Proper filtering by credential ID
  • Consistent with existing repository patterns

This method supports the cache management feature by enabling efficient bulk timestamp updates.

packages/lib/getConnectedDestinationCalendars.ts (1)

21-28: LGTM! Type extension correctly supports cache management feature.

The addition of updatedAt and googleChannelId fields to the UserWithCalendars type properly extends the interface to support the new cache status tracking functionality. This aligns well with the broader cache management feature implementation.

packages/trpc/server/routers/viewer/calendars/connectedCalendars.handler.ts (2)

27-36: LGTM! Proper repository pattern usage and clean enrichment logic.

The implementation correctly uses the CalendarCacheRepository instead of direct Prisma calls, addressing previous review feedback. The cache status enrichment logic is clean and efficient, properly mapping credential IDs to cache timestamps.


39-39: Good integration with cache status data.

The enriched connected calendars with cache update timestamps are properly returned, enabling the UI to display cache status information.

packages/features/calendar-cache/calendar-cache.repository.ts (1)

173-188: LGTM! Efficient cache status aggregation using repository pattern.

The implementation correctly uses Prisma's groupBy with _max aggregation to efficiently retrieve the latest cache update timestamp per credential. This follows the repository pattern properly and provides the data needed for the cache status feature.

packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsWebWrapper.tsx (5)

5-5: Good component replacement for enhanced functionality.

Replacing DisconnectIntegration with CredentialActionsDropdown provides a more comprehensive interface for calendar credential management, including the new cache management capabilities.


70-79: LGTM! Proper props configuration for new dropdown component.

The CredentialActionsDropdown is correctly configured with all necessary props including the new cacheUpdatedAt field for cache status display and appropriate flags for controlling functionality.


98-98: Good explicit null handling for delegation credential ID.

The explicit conversion to null when delegationCredentialId is falsy provides better type safety and clarity.


123-132: Consistent dropdown usage in error alert.

The same CredentialActionsDropdown component is properly used in the error alert case, maintaining consistency across different calendar states.


162-162: Minor formatting improvement.

The blank line addition improves code readability by separating the query definition from the following logic.

packages/features/apps/components/CredentialActionsDropdown.tsx (6)

1-27: Well-structured imports and interface definition.

The imports are properly organized and the CredentialActionsDropdownProps interface is well-defined with appropriate optional parameters and type safety.


29-41: Proper component initialization and state management.

The component correctly destructures props and manages state for dropdown visibility and modal dialogs using React hooks.


42-65: Well-implemented TRPC mutations with proper error handling.

The mutations include appropriate success/error handling with toast notifications and cache invalidation to keep the UI synchronized.


67-73: Efficient conditional rendering logic.

The component uses clear boolean flags and early return pattern to avoid unnecessary rendering when no actions are available.


75-128: Well-structured dropdown UI with good UX patterns.

The dropdown properly displays cache status with formatted timestamps and provides clear visual separation between different action types. The destructive actions are appropriately styled with the "destructive" color variant.


130-154: Confirmation dialogs properly address destructive action concerns.

Both destructive actions (cache deletion and app removal) now have confirmation dialogs with appropriate danger styling, addressing the previous review feedback about requiring confirmation for destructive actions.

zomars added 2 commits July 18, 2025 13:08
Added a default value of NOW() for the updatedAt column in the CalendarCache table to ensure existing and future rows have a valid timestamp. Updated the Prisma schema to reflect this change and provide compatibility for legacy data and raw inserts.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/prisma/migrations/20250715160635_add_calendar_cache_updated_at/migration.sql (1)

1-6: Warning header is now stale – update for accuracy
The comment still claims the column is added “without a default value,” which is no longer true and may mislead future maintainers.

-  Warnings:
-
-  - Added the required column `updatedAt` to the `CalendarCache` table without a default value. This is not possible if the table is not empty.
+  Note:
+
+  - `updatedAt` is added with `DEFAULT NOW()` to back-fill existing rows safely.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 77bbc37 and 5fd11f9.

📒 Files selected for processing (4)
  • apps/web/package.json (1 hunks)
  • apps/web/public/static/locales/en/common.json (1 hunks)
  • packages/prisma/migrations/20250715160635_add_calendar_cache_updated_at/migration.sql (1 hunks)
  • packages/prisma/schema.prisma (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/prisma/schema.prisma
  • apps/web/package.json
  • apps/web/public/static/locales/en/common.json
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: vijayraghav-io
PR: calcom/cal.com#21072
File: packages/app-store/office365calendar/api/webhook.ts:120-123
Timestamp: 2025-07-18T17:57:16.370Z
Learning: The office365calendar webhook handler in packages/app-store/office365calendar/api/webhook.ts is specifically designed for Office365 calendar integration, not as a generic webhook handler. Therefore, it's safe to assume that fetchAvailabilityAndSetCache method will be implemented in the Office365CalendarService, making explicit validation checks unnecessary.
packages/prisma/migrations/20250715160635_add_calendar_cache_updated_at/migration.sql (1)
Learnt from: vijayraghav-io
PR: calcom/cal.com#16579
File: packages/prisma/schema.prisma:149-153
Timestamp: 2025-07-16T07:14:49.225Z
Learning: In Cal.com's schema design, the team prefers to keep Boolean fields nullable (Boolean?) with defaults rather than making them non-nullable (Boolean) to avoid expensive database migrations that would update existing rows.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Production builds / Build Atoms
  • GitHub Check: Production builds / Build Docs
  • GitHub Check: Production builds / Build API v2
  • GitHub Check: Tests / Unit
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Linters / lint
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Type check / check-types
  • GitHub Check: Security Check
🔇 Additional comments (1)
packages/prisma/migrations/20250715160635_add_calendar_cache_updated_at/migration.sql (1)

8-9: Fix looks good – runtime-safe column addition
Adding the column with DEFAULT NOW() resolves the previous blocker on non-empty tables. ✅

return setDestinationCalendarHandler({ ctx, input });
}),

deleteCache: authedProcedure
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT I would've gone for the more standard clearCache nomeclature.

const { user } = ctx;
const { credentialId } = input;

const credential = await prisma.credential.findFirst({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT I think you tried to rectify this and try to get Devin to use the repo

Copy link
Contributor

@emrysal emrysal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few nits, but overall happy for this to go in, we should refactor repository access in a bit.

@emrysal emrysal merged commit cb78692 into main Jul 22, 2025
45 checks passed
@emrysal emrysal deleted the devin/calendar-cache-tooltip-1752595047 branch July 22, 2025 02:57
zomars added a commit that referenced this pull request Jul 22, 2025
* feat: add calendar cache status dropdown

- Add updatedAt field to CalendarCache schema with migration
- Create tRPC cacheStatus endpoint for fetching cache timestamps
- Add action dropdown to CalendarSwitch for Google Calendar entries
- Display formatted last updated timestamp in dropdown
- Add placeholder for cache deletion functionality
- Include translation strings for dropdown content

The dropdown only appears for Google Calendar integrations that have
active cache entries and provides cache management options for future
extensibility.

Co-Authored-By: zomars@cal.com <zomars@me.com>

* fix: resolve Prisma type incompatibilities in repository files

- Remove problematic satisfies clause in selectedCalendar.ts
- Add missing cacheStatus parameter to ConnectedCalendarList component
- Fixes type errors that were preventing CI from passing

Co-Authored-By: zomars@cal.com <zomars@me.com>

* refactor: integrate cache status into connectedCalendars handler

- Remove separate cacheStatus tRPC endpoint as requested
- Return cache status as separate field in connectedCalendars response
- Update UI components to use cache data from connectedCalendars
- Fix Prisma type incompatibilities in repository files

Co-Authored-By: zomars@cal.com <zomars@me.com>

* fix: resolve Prisma type incompatibilities and fix data flow for cache status

- Fix Prisma.SortOrder usage in membership.ts orderBy clauses
- Remove problematic satisfies clause in selectedCalendar.ts
- Fix TeamSelect type reference in team.ts
- Update SelectedCalendarsSettingsWebWrapper to properly pass cacheStatus data flow

Co-Authored-By: zomars@cal.com <zomars@me.com>

* Discard changes to packages/lib/server/repository/membership.ts

* Discard changes to packages/lib/server/repository/team.ts

* fix: improve calendar cache dropdown with proper formatting and subscription logic

- Fix timestamp HTML entity encoding with interpolation escapeValue: false
- Only show dropdown for subscribed Google calendars (googleChannelId exists)
- Hide delete option when no cache data exists
- Include updatedAt and googleChannelId fields upstream in user repository
- Update data flow to pass subscription status through components

Co-Authored-By: zomars@cal.com <zomars@me.com>

* feat: update SelectedCalendar.updatedAt when Google webhooks trigger cache refresh

- Add updateManyByCredentialId method to SelectedCalendarRepository
- Update fetchAvailabilityAndSetCache to refresh SelectedCalendar timestamps
- Ensure webhook flow updates both CalendarCache and SelectedCalendar records
- Maintain proper timestamp tracking for calendar cache operations

Co-Authored-By: zomars@cal.com <zomars@me.com>

* Add script to automate Tunnelmole webhook setup

Introduces test-gcal-webhooks.sh to start Tunnelmole, extract the public URL, and update GOOGLE_WEBHOOK_URL in the .env file. Handles process management, rate limits, and ensures environment configuration for Google Calendar webhooks.

* Update dev:cron script to use npx tsx

Replaces 'ts-node' with 'npx tsx' in the dev:cron script for running cron-tester.ts, likely to improve compatibility or leverage tsx features.

* Update cache status string and improve CalendarSwitch UI

Renamed 'last_updated' to 'cache_last_updated' in locale file for clarity and updated CalendarSwitch to use the new string. Also added dark mode text color support for cache status display.

* refactor: move cache management to credential-level dropdown with Remove App

- Create CredentialActionsDropdown component consolidating cache and app removal actions
- Add deleteCache tRPC mutation for credential-level cache deletion
- Update connectedCalendars handler to include cacheUpdatedAt at credential level
- Move dropdown from individual CalendarSwitch to credential level in SelectedCalendarsSettingsWebWrapper
- Remove cache-related props from CalendarSwitch component
- Add translation strings for cache management actions
- Consolidate all credential-level actions (cache management + Remove App) in one dropdown

Co-Authored-By: zomars@cal.com <zomars@me.com>

* fix: remove duplicate translation keys in common.json

- Remove duplicate cache-related keys at lines 51-56
- Keep properly positioned keys later in file
- Addresses GitHub comment from zomars about duplicate keys

Co-Authored-By: zomars@cal.com <zomars@me.com>

* fix: rename translation key to cache_last_updated

- Address GitHub comment from zomars
- Rename 'last_updated' to 'cache_last_updated' for specificity
- Update usage in CredentialActionsDropdown component

Co-Authored-By: zomars@cal.com <zomars@me.com>

* fix: remove duplicate last_updated translation key

Co-Authored-By: zomars@cal.com <zomars@me.com>

* fix: add confirmation dialog for cache deletion and use repository pattern

- Add confirmation dialog for destructive cache deletion action
- Replace direct Prisma calls with CalendarCacheRepository pattern
- Add getCacheStatusByCredentialIds method to repository interface
- Fix import paths for UI components
- Address GitHub review comments from zomars

Co-Authored-By: zomars@cal.com <zomars@me.com>

* Update CredentialActionsDropdown.tsx

* Update common.json

* Update common.json

* fix: remove nested div wrapper to resolve HTML structure error

- Remove wrapping div around DisconnectIntegration component
- Fixes nested <p> tag validation error preventing Remove App functionality
- Maintains existing confirmation dialog patterns

Co-Authored-By: zomars@cal.com <zomars@me.com>

* Fix API handler response termination logic

Removed unnecessary return values after setting status in the integrations API handler. This clarifies response handling and prevents returning the response object when not needed. Resolves "API handler should not return a value, received object".

* fix: 400 is correct error code for computing slot for past booking (#22574)

* fix

* add test

* chore: release v5.5.1

* Refactor credential disconnect to use confirmation dialog

Replaces the DisconnectIntegration component with an inline confirmation dialog for removing app credentials. Adds disconnect mutation logic and updates UI to improve user experience and consistency.

* Set default value for CalendarCache.updatedAt

Added a default value of NOW() for the updatedAt column in the CalendarCache table to ensure existing and future rows have a valid timestamp. Updated the Prisma schema to reflect this change and provide compatibility for legacy data and raw inserts.

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Benny Joo <sldisek783@gmail.com>
Co-authored-by: emrysal <me@alexvanandel.com>
This was referenced Sep 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

calendar-apps area: calendar, google calendar, outlook, lark, microsoft 365, apple calendar core area: core, team members only ✨ feature New feature or request foundation ❗️ migrations contains migration files ready-for-e2e

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants