diff --git a/apps/web/package.json b/apps/web/package.json index 4f7421ebb0f..913cd606545 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -8,7 +8,7 @@ "analyze:browser": "BUNDLE_ANALYZE=browser next build", "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", "test-codegen": "yarn playwright codegen http://localhost:3000", diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index d66de26477e..2c908b8f779 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -3379,5 +3379,12 @@ "timezone_mismatch_tooltip": "You are viewing the report based on your profile timezone ({{userTimezone}}), while your browser is set to timezone ({{browserTimezone}})", "failed_bookings_by_field": "Failed Bookings By Field", "event_type_no_hosts": "No hosts are assigned to event type", + "cache_status": "Cache Status", + "cache_last_updated": "Last updated: {{timestamp}}", + "delete_cached_data": "Delete cached data", + "cache_deleted_successfully": "Cache deleted successfully", + "error_deleting_cache": "Error deleting cache", + "confirm_delete_cache": "Are you sure you want to delete the cached data? This action cannot be undone.", + "yes_delete_cache": "Yes, delete cache", "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑" } diff --git a/packages/app-store/googlecalendar/lib/CalendarService.ts b/packages/app-store/googlecalendar/lib/CalendarService.ts index 07ae5308f62..e593557ed7f 100644 --- a/packages/app-store/googlecalendar/lib/CalendarService.ts +++ b/packages/app-store/googlecalendar/lib/CalendarService.ts @@ -1019,6 +1019,9 @@ export default class GoogleCalendarService implements Calendar { const data = await this.fetchAvailability(parsedArgs); await this.setAvailabilityInCache(parsedArgs, data); } + + // Update SelectedCalendar.updatedAt for all calendars under this credential + await SelectedCalendarRepository.updateManyByCredentialId(this.credential.id, {}); } async createSelectedCalendar( diff --git a/packages/features/apps/components/CredentialActionsDropdown.tsx b/packages/features/apps/components/CredentialActionsDropdown.tsx new file mode 100644 index 00000000000..169e46c4d3a --- /dev/null +++ b/packages/features/apps/components/CredentialActionsDropdown.tsx @@ -0,0 +1,157 @@ +"use client"; + +import { useState } from "react"; + +import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { GOOGLE_CALENDAR_TYPE } from "@calcom/platform-constants"; +import { trpc } from "@calcom/trpc/react"; +import { Button } from "@calcom/ui/components/button"; +import { ConfirmationDialogContent } from "@calcom/ui/components/dialog"; +import { Dialog } from "@calcom/ui/components/dialog"; +import { + Dropdown, + DropdownItem, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@calcom/ui/components/dropdown"; +import { showToast } from "@calcom/ui/components/toast"; + +interface CredentialActionsDropdownProps { + credentialId: number; + integrationType: string; + cacheUpdatedAt?: Date | null; + onSuccess?: () => void; + delegationCredentialId?: string | null; + disableConnectionModification?: boolean; +} + +export default function CredentialActionsDropdown({ + credentialId, + integrationType, + cacheUpdatedAt, + onSuccess, + delegationCredentialId, + disableConnectionModification, +}: CredentialActionsDropdownProps) { + const { t } = useLocale(); + const [dropdownOpen, setDropdownOpen] = useState(false); + const [deleteModalOpen, setDeleteModalOpen] = useState(false); + const [disconnectModalOpen, setDisconnectModalOpen] = useState(false); + + const deleteCacheMutation = trpc.viewer.calendars.deleteCache.useMutation({ + onSuccess: () => { + showToast(t("cache_deleted_successfully"), "success"); + onSuccess?.(); + }, + onError: () => { + showToast(t("error_deleting_cache"), "error"); + }, + }); + + const utils = trpc.useUtils(); + const disconnectMutation = trpc.viewer.credentials.delete.useMutation({ + onSuccess: () => { + showToast(t("app_removed_successfully"), "success"); + onSuccess?.(); + }, + onError: () => { + showToast(t("error_removing_app"), "error"); + }, + async onSettled() { + await utils.viewer.calendars.connectedCalendars.invalidate(); + await utils.viewer.apps.integrations.invalidate(); + }, + }); + + const isGoogleCalendar = integrationType === GOOGLE_CALENDAR_TYPE; + const canDisconnect = !delegationCredentialId && !disableConnectionModification; + const hasCache = isGoogleCalendar && cacheUpdatedAt; + + if (!canDisconnect && !hasCache) { + return null; + } + + return ( + <> + + +