mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
fix(studio): resolve outstanding Sentry issues (#44106)
## Summary Fixes several high-impact Sentry errors reported in production. ### Fixed Issues - **[SUPABASE-APP-EJ3](https://supabase.sentry.io/issues/7356937474/)** — `TypeError: Cannot read properties of undefined (reading 'direct')`. `connectionStringPooler` could be `undefined` when the connection source doesn't match any key in the connection strings map. Added an early return guard in `resolveConnectionString`. - **[SUPABASE-APP-B17](https://supabase.sentry.io/issues/7117468199/)** — `RangeError: Invalid time zone specified: Etc/Unknown`. `dayjs.tz.guess()` returns `"Etc/Unknown"` for some users with misconfigured browser/OS timezones. Added a shared `guessLocalTimezone()` helper that validates the guessed timezone via `Intl.DateTimeFormat` and falls back to UTC. Applied across all 4 call sites. - **[SUPABASE-APP-BCM](https://supabase.sentry.io/issues/7192934901/)** — `TypeError: Cannot convert undefined or null to object`. `Object.entries(definition.properties)` crashed when a JSON schema definition existed but had no `properties` field. Updated the guard to check `definition?.properties` instead of just `definition`. - https://supabase.sentry.io/issues/7357780302/?project=5459134 - https://supabase.sentry.io/issues/7358344652/?project=5459134 - https://supabase.sentry.io/issues/7096737077/?project=5459134 ## Test plan - [ ] Verify connect dialog renders without errors when connection data is still loading - [ ] Verify API docs Entity view handles schema definitions without properties - [ ] Verify charts/tooltips display correct timezone labels --------- Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
This commit is contained in:
1 parent
f70d0923f9
commit
8a26132bde
8 files changed
+24
-7
No files matched your search
@@ -132,7 +132,7 @@ export const OAuthAppsList = () => {
|
||||
|
||||
return filtered.sort((a, b) => {
|
||||
if (sortCol === 'name') {
|
||||
return a.client_name.localeCompare(b.client_name) * orderMultiplier
|
||||
return (a.client_name || '').localeCompare(b.client_name || '') * orderMultiplier
|
||||
}
|
||||
if (sortCol === 'client_type') {
|
||||
return a.client_type.localeCompare(b.client_type) * orderMultiplier
|
||||
|
||||
@@ -18,8 +18,10 @@ export const resolveConnectionString = ({
|
||||
}: {
|
||||
connectionMethod: ConnectionStringMethod
|
||||
useSharedPooler: boolean
|
||||
connectionStringPooler: ConnectionStringPooler
|
||||
connectionStringPooler: ConnectionStringPooler | undefined
|
||||
}) => {
|
||||
if (!connectionStringPooler) return ''
|
||||
|
||||
if (connectionMethod === 'direct') {
|
||||
return connectionStringPooler.direct ?? ''
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import dayjs from 'dayjs'
|
||||
import { guessLocalTimezone } from 'lib/dayjs'
|
||||
import { ALL_TIMEZONES } from './PITR.constants'
|
||||
import type { Time } from './PITR.types'
|
||||
import type { ProjectSelectedAddon } from 'data/subscriptions/types'
|
||||
@@ -17,7 +18,7 @@ export const getDatesBetweenRange = (startDate: dayjs.Dayjs, endDate: dayjs.Dayj
|
||||
}
|
||||
|
||||
export const getClientTimezone = () => {
|
||||
const defaultTz = dayjs.tz.guess()
|
||||
const defaultTz = guessLocalTimezone()
|
||||
const utcTz = ALL_TIMEZONES.find((option) => option.value === 'UTC')
|
||||
const timezone = ALL_TIMEZONES.find((option) => {
|
||||
if (option.utc.includes(defaultTz)) return option
|
||||
|
||||
@@ -39,7 +39,7 @@ export const Entity = ({ language, apikey = '', endpoint = '' }: ContentProps) =
|
||||
|
||||
const definition = jsonSchema?.definitions?.[resource]
|
||||
const columns =
|
||||
definition !== undefined
|
||||
definition?.properties !== undefined
|
||||
? Object.entries(definition.properties).map(([id, val]: any) => ({
|
||||
...val,
|
||||
id,
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
import dayjs from 'dayjs'
|
||||
import { guessLocalTimezone } from 'lib/dayjs'
|
||||
import type { TooltipProps } from 'recharts'
|
||||
import { formatDuration } from '../QueryInsightsTable/QueryInsightsTable.utils'
|
||||
import { isTimeMetric } from './QueryInsightsChart.utils'
|
||||
@@ -7,7 +8,7 @@ export const QueryInsightsChartTooltip = ({ active, payload }: TooltipProps<numb
|
||||
if (!active || !payload?.length) return null
|
||||
|
||||
const time = payload[0]?.payload?.time
|
||||
const localTimeZone = dayjs.tz.guess()
|
||||
const localTimeZone = guessLocalTimezone()
|
||||
|
||||
return (
|
||||
<div className="grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg px-2.5 py-1.5 text-xs shadow-xl">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import dayjs from 'dayjs'
|
||||
import { guessLocalTimezone } from 'lib/dayjs'
|
||||
import { formatBytes } from 'lib/helpers'
|
||||
import { useState } from 'react'
|
||||
import { cn, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from 'ui'
|
||||
@@ -193,7 +194,7 @@ export const CustomTooltip = ({
|
||||
...(maxValueAttribute?.attribute ? [maxValueAttribute.attribute] : []),
|
||||
]
|
||||
|
||||
const localTimeZone = dayjs.tz.guess()
|
||||
const localTimeZone = guessLocalTimezone()
|
||||
|
||||
const rawPayload = payload.map((entry: any) => ({
|
||||
...entry,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DatabaseUpgradeStatus } from '@supabase/shared-types/out/events'
|
||||
import dayjs from 'dayjs'
|
||||
import { guessLocalTimezone } from 'lib/dayjs'
|
||||
import { X } from 'lucide-react'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
@@ -28,7 +29,7 @@ export const ProjectUpgradeFailedBanner = () => {
|
||||
const isFailed = status === DatabaseUpgradeStatus.Failed
|
||||
const initiatedAt = dayjs
|
||||
.utc(initiated_at ?? 0)
|
||||
.tz(dayjs.tz.guess())
|
||||
.tz(guessLocalTimezone())
|
||||
.format('DD MMM YYYY HH:mm:ss')
|
||||
|
||||
const subject = 'Upgrade%20failed%20for%20project'
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
export function guessLocalTimezone(): string {
|
||||
const guess = dayjs.tz.guess()
|
||||
try {
|
||||
Intl.DateTimeFormat(undefined, { timeZone: guess })
|
||||
return guess
|
||||
} catch {
|
||||
return 'UTC'
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user