Skip to content

feat: add calendar cache status and actions (#22532)#2

Open
ShashankFC wants to merge 1 commit into
calendar-cache-foundationfrom
introduce-cache-key-overflow
Open

feat: add calendar cache status and actions (#22532)#2
ShashankFC wants to merge 1 commit into
calendar-cache-foundationfrom
introduce-cache-key-overflow

Conversation

@ShashankFC

Copy link
Copy Markdown

Test 1rnnn

Summary by CodeRabbit

  • New Features

    • Added cache management capabilities for integrations, including ability to view cache status with last updated timestamp and delete cached data.
  • Documentation

    • Added localization strings for cache management UI elements.
  • Chores

    • Updated development tooling for cron job execution.
    • Added setup script for Google Cloud webhook configuration.

✏️ Tip: You can customize this high-level summary in your review settings.

nn---n*Replicated from [ai-code-review-evaluation/cal.com-coderabbit#11](https://github.com/ai-code-review-evaluation/cal.com-coderabbit/pull/11)*

* 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>
@ShashankFC

Copy link
Copy Markdown
Author

@cubic-dev-ai review this pull request

@cubic-dev-ai

cubic-dev-ai Bot commented Feb 13, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this pull request

@ShashankFC I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

5 issues found across 17 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/app-store/googlecalendar/lib/CalendarService.ts">

<violation number="1" location="packages/app-store/googlecalendar/lib/CalendarService.ts:1024">
P1: Bug: Passing empty `{}` to `updateMany` will not trigger `@updatedAt` — this is a no-op. Prisma's `@updatedAt` only updates the timestamp when at least one field is actually changed. You need to explicitly set the timestamp.</violation>
</file>

<file name="scripts/test-gcal-webhooks.sh">

<violation number="1" location="scripts/test-gcal-webhooks.sh:68">
P2: `sed -i ''` is macOS/BSD-specific. On GNU/Linux, this fails because `-i` expects the extension as a suffix to the flag (e.g., `sed -i''`) or uses `-i` alone for no-backup in-place editing. Consider a portable alternative.</violation>
</file>

<file name="packages/trpc/server/routers/viewer/calendars/connectedCalendars.handler.ts">

<violation number="1" location="packages/trpc/server/routers/viewer/calendars/connectedCalendars.handler.ts:29">
P1: Missing error handling: if `getCacheStatusByCredentialIds` throws, the entire connected calendars endpoint fails. Cache status is supplementary data — a failure here should not prevent users from seeing their calendars. Wrap the cache lookup in a try/catch and fall back gracefully.</violation>
</file>

<file name="apps/web/package.json">

<violation number="1" location="apps/web/package.json:11">
P2: `tsx` is not a declared dependency — `npx tsx` will download an unpinned version on each first run, making builds non-deterministic. Additionally, `ts-node` is already a devDependency and is still used by other scripts (`check-changed-files`, `translate-locales`). Either add `tsx` to `devDependencies` with a pinned version, or keep using the already-installed `ts-node`.</violation>
</file>

<file name="packages/features/apps/components/CredentialActionsDropdown.tsx">

<violation number="1" location="packages/features/apps/components/CredentialActionsDropdown.tsx:89">
P2: The date formatter hardcodes `"en-US"` locale instead of using the user's current locale from the `i18n` instance already available via `useLocale()`. This means all users will see US-formatted dates regardless of their language setting.

Use `i18n.language` (or derive a proper locale from it) to format dates according to the user's preferences.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

}

// Update SelectedCalendar.updatedAt for all calendars under this credential
await SelectedCalendarRepository.updateManyByCredentialId(this.credential.id, {});

@cubic-dev-ai cubic-dev-ai Bot Feb 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Bug: Passing empty {} to updateMany will not trigger @updatedAt — this is a no-op. Prisma's @updatedAt only updates the timestamp when at least one field is actually changed. You need to explicitly set the timestamp.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app-store/googlecalendar/lib/CalendarService.ts, line 1024:

<comment>Bug: Passing empty `{}` to `updateMany` will not trigger `@updatedAt` — this is a no-op. Prisma's `@updatedAt` only updates the timestamp when at least one field is actually changed. You need to explicitly set the timestamp.</comment>

<file context>
@@ -1019,6 +1019,9 @@ export default class GoogleCalendarService implements Calendar {
     }
+
+    // Update SelectedCalendar.updatedAt for all calendars under this credential
+    await SelectedCalendarRepository.updateManyByCredentialId(this.credential.id, {});
   }
 
</file context>
Suggested change
await SelectedCalendarRepository.updateManyByCredentialId(this.credential.id, {});
await SelectedCalendarRepository.updateManyByCredentialId(this.credential.id, { updatedAt: new Date() });
Fix with Cubic


const credentialIds = connectedCalendars.map((cal) => cal.credentialId);
const cacheRepository = new CalendarCacheRepository();
const cacheStatuses = await cacheRepository.getCacheStatusByCredentialIds(credentialIds);

@cubic-dev-ai cubic-dev-ai Bot Feb 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Missing error handling: if getCacheStatusByCredentialIds throws, the entire connected calendars endpoint fails. Cache status is supplementary data — a failure here should not prevent users from seeing their calendars. Wrap the cache lookup in a try/catch and fall back gracefully.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/trpc/server/routers/viewer/calendars/connectedCalendars.handler.ts, line 29:

<comment>Missing error handling: if `getCacheStatusByCredentialIds` throws, the entire connected calendars endpoint fails. Cache status is supplementary data — a failure here should not prevent users from seeing their calendars. Wrap the cache lookup in a try/catch and fall back gracefully.</comment>

<file context>
@@ -23,8 +24,19 @@ export const connectedCalendarsHandler = async ({ ctx, input }: ConnectedCalenda
 
+  const credentialIds = connectedCalendars.map((cal) => cal.credentialId);
+  const cacheRepository = new CalendarCacheRepository();
+  const cacheStatuses = await cacheRepository.getCacheStatusByCredentialIds(credentialIds);
+
+  const cacheStatusMap = new Map(cacheStatuses.map((cache) => [cache.credentialId, cache.updatedAt]));
</file context>
Fix with Cubic

fi

if grep -q '^GOOGLE_WEBHOOK_URL=' "$ENV_FILE"; then
sed -i '' -E "s|^GOOGLE_WEBHOOK_URL=.*|GOOGLE_WEBHOOK_URL=$TUNNEL_URL|" "$ENV_FILE"

@cubic-dev-ai cubic-dev-ai Bot Feb 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: sed -i '' is macOS/BSD-specific. On GNU/Linux, this fails because -i expects the extension as a suffix to the flag (e.g., sed -i'') or uses -i alone for no-backup in-place editing. Consider a portable alternative.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/test-gcal-webhooks.sh, line 68:

<comment>`sed -i ''` is macOS/BSD-specific. On GNU/Linux, this fails because `-i` expects the extension as a suffix to the flag (e.g., `sed -i''`) or uses `-i` alone for no-backup in-place editing. Consider a portable alternative.</comment>

<file context>
@@ -0,0 +1,79 @@
+fi
+
+if grep -q '^GOOGLE_WEBHOOK_URL=' "$ENV_FILE"; then
+  sed -i '' -E "s|^GOOGLE_WEBHOOK_URL=.*|GOOGLE_WEBHOOK_URL=$TUNNEL_URL|" "$ENV_FILE"
+else
+  echo "GOOGLE_WEBHOOK_URL=$TUNNEL_URL" >> "$ENV_FILE"
</file context>
Fix with Cubic

Comment thread apps/web/package.json
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next",
"dev": "yarn copy-static && next dev --turbopack",
"dev:cron": "ts-node cron-tester.ts",
"dev:cron": "npx tsx cron-tester.ts",

@cubic-dev-ai cubic-dev-ai Bot Feb 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: tsx is not a declared dependency — npx tsx will download an unpinned version on each first run, making builds non-deterministic. Additionally, ts-node is already a devDependency and is still used by other scripts (check-changed-files, translate-locales). Either add tsx to devDependencies with a pinned version, or keep using the already-installed ts-node.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/package.json, line 11:

<comment>`tsx` is not a declared dependency — `npx tsx` will download an unpinned version on each first run, making builds non-deterministic. Additionally, `ts-node` is already a devDependency and is still used by other scripts (`check-changed-files`, `translate-locales`). Either add `tsx` to `devDependencies` with a pinned version, or keep using the already-installed `ts-node`.</comment>

<file context>
@@ -8,7 +8,7 @@
     "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next",
     "dev": "yarn copy-static && next dev --turbopack",
-    "dev:cron": "ts-node cron-tester.ts",
+    "dev:cron": "npx tsx cron-tester.ts",
     "dev-https": "NODE_TLS_REJECT_UNAUTHORIZED=0 next dev --experimental-https",
     "dx": "yarn dev",
</file context>
Suggested change
"dev:cron": "npx tsx cron-tester.ts",
"dev:cron": "ts-node cron-tester.ts",
Fix with Cubic

<div className="text-sm font-medium text-gray-900 dark:text-white">{t("cache_status")}</div>
<div className="text-xs text-gray-500 dark:text-white">
{t("cache_last_updated", {
timestamp: new Intl.DateTimeFormat("en-US", {

@cubic-dev-ai cubic-dev-ai Bot Feb 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: The date formatter hardcodes "en-US" locale instead of using the user's current locale from the i18n instance already available via useLocale(). This means all users will see US-formatted dates regardless of their language setting.

Use i18n.language (or derive a proper locale from it) to format dates according to the user's preferences.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/features/apps/components/CredentialActionsDropdown.tsx, line 89:

<comment>The date formatter hardcodes `"en-US"` locale instead of using the user's current locale from the `i18n` instance already available via `useLocale()`. This means all users will see US-formatted dates regardless of their language setting.

Use `i18n.language` (or derive a proper locale from it) to format dates according to the user's preferences.</comment>

<file context>
@@ -0,0 +1,157 @@
+                  <div className="text-sm font-medium text-gray-900 dark:text-white">{t("cache_status")}</div>
+                  <div className="text-xs text-gray-500 dark:text-white">
+                    {t("cache_last_updated", {
+                      timestamp: new Intl.DateTimeFormat("en-US", {
+                        dateStyle: "short",
+                        timeStyle: "short",
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants