From 1b91f5ae79b66dc8898b1d493b55a9003be3eb77 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Thu, 18 Sep 2025 18:54:28 +0800 Subject: [PATCH 1/3] Address odd bug between data grid contextmenu and overlay (#38809) * Address odd bug between data grid contextmenu and overlay * nit * Smol tweak --- .../interfaces/Auth/Users/DeleteUserModal.tsx | 2 -- .../interfaces/Auth/Users/UsersV2.tsx | 8 ++++++-- .../Integrations/CronJobs/CronJobsTab.tsx | 3 ++- .../Integrations/CronJobs/DeleteCronJob.tsx | 11 +++++++++-- apps/studio/lib/helpers.ts | 17 +++++++++++++++++ 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/apps/studio/components/interfaces/Auth/Users/DeleteUserModal.tsx b/apps/studio/components/interfaces/Auth/Users/DeleteUserModal.tsx index ff513fb397f96..8c59665887861 100644 --- a/apps/studio/components/interfaces/Auth/Users/DeleteUserModal.tsx +++ b/apps/studio/components/interfaces/Auth/Users/DeleteUserModal.tsx @@ -3,7 +3,6 @@ import { toast } from 'sonner' import { useUserDeleteMutation } from 'data/auth/user-delete-mutation' import { User } from 'data/auth/users-infinite-query' -import { timeout } from 'lib/helpers' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' interface DeleteUserModalProps { @@ -29,7 +28,6 @@ export const DeleteUserModal = ({ }) const handleDeleteUser = async () => { - await timeout(200) if (!projectRef) return console.error('Project ref is required') if (selectedUser?.id === undefined) { return toast.error(`Failed to delete user: User ID not found`) diff --git a/apps/studio/components/interfaces/Auth/Users/UsersV2.tsx b/apps/studio/components/interfaces/Auth/Users/UsersV2.tsx index 98d1e3316d8d1..e2819a9bdcab8 100644 --- a/apps/studio/components/interfaces/Auth/Users/UsersV2.tsx +++ b/apps/studio/components/interfaces/Auth/Users/UsersV2.tsx @@ -30,7 +30,7 @@ import { THRESHOLD_COUNT } from 'data/table-rows/table-rows-count-query' import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' -import { isAtBottom } from 'lib/helpers' +import { cleanPointerEventsNoneOnBody, isAtBottom } from 'lib/helpers' import { Button, cn, @@ -680,10 +680,14 @@ export const UsersV2 = () => { setSelectedUserToDelete(undefined)} + onClose={() => { + setSelectedUserToDelete(undefined) + cleanPointerEventsNoneOnBody() + }} onDeleteSuccess={() => { if (selectedUserToDelete?.id === selectedUser) setSelectedUser(undefined) setSelectedUserToDelete(undefined) + cleanPointerEventsNoneOnBody(500) }} /> diff --git a/apps/studio/components/interfaces/Integrations/CronJobs/CronJobsTab.tsx b/apps/studio/components/interfaces/Integrations/CronJobs/CronJobsTab.tsx index 0f1e2e2e85eb4..7240e0d909c97 100644 --- a/apps/studio/components/interfaces/Integrations/CronJobs/CronJobsTab.tsx +++ b/apps/studio/components/interfaces/Integrations/CronJobs/CronJobsTab.tsx @@ -18,7 +18,7 @@ import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { BASE_PATH } from 'lib/constants' -import { isAtBottom } from 'lib/helpers' +import { cleanPointerEventsNoneOnBody, isAtBottom } from 'lib/helpers' import { Button, cn, LoadingLine, Sheet, SheetContent } from 'ui' import { Input } from 'ui-patterns/DataInputs/Input' import { formatCronJobColumns } from './CronJobs.utils' @@ -279,6 +279,7 @@ export const CronjobsTab = () => { setIsClosingCreateCronJobSheet(false) setCronJobForEditing(undefined) setCreateCronJobSheetShown(false) + cleanPointerEventsNoneOnBody(500) }} isClosing={isClosingCreateCronJobSheet} setIsClosing={setIsClosingCreateCronJobSheet} diff --git a/apps/studio/components/interfaces/Integrations/CronJobs/DeleteCronJob.tsx b/apps/studio/components/interfaces/Integrations/CronJobs/DeleteCronJob.tsx index bfe269faf99cb..3e59394213f19 100644 --- a/apps/studio/components/interfaces/Integrations/CronJobs/DeleteCronJob.tsx +++ b/apps/studio/components/interfaces/Integrations/CronJobs/DeleteCronJob.tsx @@ -6,6 +6,7 @@ import { CronJob } from 'data/database-cron-jobs/database-cron-jobs-infinite-que import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' +import { cleanPointerEventsNoneOnBody } from 'lib/helpers' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import TextConfirmModal from 'ui-patterns/Dialogs/TextConfirmModal' @@ -53,7 +54,10 @@ export const DeleteCronJob = ({ cronJob, visible, onClose }: DeleteCronJobProps) onClose()} + onCancel={() => { + onClose() + cleanPointerEventsNoneOnBody() + }} onConfirm={handleDelete} title={`Delete the cron job`} loading={isLoading} @@ -67,8 +71,11 @@ export const DeleteCronJob = ({ cronJob, visible, onClose }: DeleteCronJobProps) onClose()} onConfirm={handleDelete} + onCancel={() => { + onClose() + cleanPointerEventsNoneOnBody() + }} title="Delete this cron job" loading={isLoading} confirmLabel={`Delete cron job ${cronJob.jobname}`} diff --git a/apps/studio/lib/helpers.ts b/apps/studio/lib/helpers.ts index 505b4712eeac2..7143e4cff21a3 100644 --- a/apps/studio/lib/helpers.ts +++ b/apps/studio/lib/helpers.ts @@ -331,3 +331,20 @@ export const formatCurrency = (amount: number | undefined | null): string | null return currencyFormatterDefault.format(amount) } } + +/** + * [Joshen] This is to address an incredibly weird bug that's happening between Data Grid + Shadcn ContextMenu + Shadcn Overlay + * This trifecta is causing a pointer events none style getting left behind on the body element which makes the dashboard become + * unresponsive, hence the attempt to clean things up here + * + * Timeout is made configurable as I've observed it requires a higher timeout sometimes (e.g when closing the cron job sheet) + */ +export const cleanPointerEventsNoneOnBody = (timeoutMs: number = 300) => { + if (typeof window !== 'undefined') { + setTimeout(() => { + if (document.body.style.pointerEvents === 'none') { + document.body.style.pointerEvents = '' + } + }, timeoutMs) + } +} From d70600c0294a42f0575514bc492aec36c9b1107b Mon Sep 17 00:00:00 2001 From: "kemal.earth" <606977+kemaldotearth@users.noreply.github.com> Date: Thu, 18 Sep 2025 15:11:50 +0100 Subject: [PATCH 2/3] fix(studio): query performance tabular nums (#38819) * fix: tabular numbers and right align query perf nums * nit: time consumed column as well --- .../QueryPerformance/QueryPerformanceGrid.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx index 001b8cbba4e98..0fbbd5b0e0fb1 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx @@ -145,7 +145,7 @@ export const QueryPerformanceGrid = ({ queryPerformanceQuery }: QueryPerformance const fillWidth = Math.min(percentage, 100) return ( -
+
+
{isTime && typeof value === 'number' && !isNaN(value) && isFinite(value) ? (

+

{typeof value === 'number' && !isNaN(value) && isFinite(value) ? (

{value.toLocaleString()} @@ -208,7 +208,7 @@ export const QueryPerformanceGrid = ({ queryPerformanceQuery }: QueryPerformance if (col.id === 'max_time' || col.id === 'mean_time' || col.id === 'min_time') { return ( -

+
{typeof value === 'number' && !isNaN(value) && isFinite(value) ? (

{Math.round(value).toLocaleString()}ms @@ -222,7 +222,7 @@ export const QueryPerformanceGrid = ({ queryPerformanceQuery }: QueryPerformance if (col.id === 'rows_read') { return ( -

+
{typeof value === 'number' && !isNaN(value) && isFinite(value) ? (

{value.toLocaleString()} @@ -241,7 +241,7 @@ export const QueryPerformanceGrid = ({ queryPerformanceQuery }: QueryPerformance if (col.id === 'cache_hit_rate') { return ( -

+
{typeof value === 'string' ? (

Date: Thu, 18 Sep 2025 16:57:32 +0200 Subject: [PATCH 3/3] add cf headers for cms draft mode (#38822) * add cf headers for cms draft mode * add env vars to turbo.json allowlist --- apps/www/app/api-v2/cms-posts/route.ts | 3 ++- turbo.json | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/www/app/api-v2/cms-posts/route.ts b/apps/www/app/api-v2/cms-posts/route.ts index 04f64cf768073..9df5606bde040 100644 --- a/apps/www/app/api-v2/cms-posts/route.ts +++ b/apps/www/app/api-v2/cms-posts/route.ts @@ -6,10 +6,11 @@ import { generateReadingTime } from '~/lib/helpers' // Lightweight runtime for better performance export const runtime = 'edge' -// CORS headers for cross-origin requests const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', + 'CF-Access-Client-Id': process.env.CF_ACCESS_CLIENT_ID ?? '', + 'CF-Access-Client-Secret': process.env.CF_ACCESS_CLIENT_SECRET ?? '', } // Lightweight TOC generation for edge runtime diff --git a/turbo.json b/turbo.json index 64a448b08abda..d7ed335d3bb25 100644 --- a/turbo.json +++ b/turbo.json @@ -114,6 +114,8 @@ "dependsOn": ["^build"], "env": [ "ANALYZE", + "CF_ACCESS_CLIENT_ID", + "CF_ACCESS_CLIENT_SECRET", "CMS_API_KEY", "CMS_PREVIEW_SECRET", "CMS_SITE_ORIGIN",