mirror of
https://github.com/supabase/supabase.git
synced 2026-10-12 21:05:06 +03:00
fix(studio): fix multiple Sentry errors (#44715)
## Summary - [**SUPABASE-APP-E2R**](https://supabase.sentry.io/issues/SUPABASE-APP-E2R): Guard against undefined entries in notifications array in `AdvisorButton` (optional chaining on `.some()` callbacks) - [**SUPABASE-APP-EBA**](https://supabase.sentry.io/issues/SUPABASE-APP-EBA): Remove render-time `handleError()` throw in `useEdgeFunctionsDiff` — the hook already handles missing body data gracefully - [**SUPABASE-APP-BVN**](https://supabase.sentry.io/issues/SUPABASE-APP-BVN) / [**SUPABASE-APP-BTV**](https://supabase.sentry.io/issues/SUPABASE-APP-BTV): Guard `localStorage` access in `FeaturePreviewContext` with try-catch, matching the established pattern in `useLocalStorage.ts` (Safari private browsing) - [**SUPABASE-APP-AV3**](https://supabase.sentry.io/issues/SUPABASE-APP-AV3): Filter stale folder IDs before passing `expandedIds` to `react-accessible-treeview` in the SQL editor nav ## Test plan - [x] Verify AdvisorButton renders without errors when notifications data has sparse pages - [x] Verify branch merge page loads when edge function body fetch fails - [x] Verify feature previews initialize correctly in Safari private browsing - [x] Verify SQL editor folder expand/collapse works after deleting a folder <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Feature preview now falls back safely when browser storage is unavailable * Notifications display updated to tolerate missing entries without errors * Private snippets navigation no longer preserves expansion state for removed nodes * **Refactor** * Streamlined error aggregation in edge functions diff processing <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
1 parent
2538b56b71
commit
3cb440e844
4 files changed
+27
-22
No files matched your search
@@ -39,10 +39,14 @@ export const FeaturePreviewContextProvider = ({ children }: PropsWithChildren<{}
|
||||
setFlags(
|
||||
featurePreviews.reduce((a, b) => {
|
||||
const defaultOptIn = b.isDefaultOptIn
|
||||
const localStorageValue = localStorage.getItem(b.key)
|
||||
return {
|
||||
...a,
|
||||
[b.key]: !localStorageValue ? defaultOptIn : localStorageValue === 'true',
|
||||
try {
|
||||
const localStorageValue = window.localStorage.getItem(b.key)
|
||||
return {
|
||||
...a,
|
||||
[b.key]: !localStorageValue ? defaultOptIn : localStorageValue === 'true',
|
||||
}
|
||||
} catch {
|
||||
return { ...a, [b.key]: defaultOptIn }
|
||||
}
|
||||
}, {})
|
||||
)
|
||||
@@ -57,8 +61,12 @@ export const FeaturePreviewContextProvider = ({ children }: PropsWithChildren<{}
|
||||
const value = {
|
||||
flags,
|
||||
onUpdateFlag: (key: string, value: boolean) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
window.localStorage.setItem(key, value.toString())
|
||||
try {
|
||||
if (typeof window !== 'undefined' && window.localStorage) {
|
||||
window.localStorage.setItem(key, value ? 'true' : 'false')
|
||||
}
|
||||
} catch {
|
||||
// Silently fail in restricted storage modes (e.g. Safari private browsing)
|
||||
}
|
||||
const updatedFlags = { ...flags, [key]: value }
|
||||
setFlags(updatedFlags)
|
||||
|
||||
@@ -20,8 +20,8 @@ export const AdvisorButton = ({ projectRef }: { projectRef?: string }) => {
|
||||
const notifications = useMemo(() => {
|
||||
return notificationsData?.pages.flatMap((page) => page) ?? []
|
||||
}, [notificationsData?.pages])
|
||||
const hasUnreadNotifications = notifications.some((x) => x.status === 'new')
|
||||
const hasCriticalNotifications = notifications.some((x) => x.priority === 'Critical')
|
||||
const hasUnreadNotifications = notifications.some((x) => x?.status === 'new')
|
||||
const hasCriticalNotifications = notifications.some((x) => x?.priority === 'Critical')
|
||||
|
||||
const hasCriticalIssues =
|
||||
hasCriticalNotifications ||
|
||||
|
||||
@@ -171,6 +171,16 @@ export const SQLEditorNav = ({ sort = 'inserted_at' }: SQLEditorNavProps) => {
|
||||
[folders, privateSnippets]
|
||||
)
|
||||
|
||||
const privateSnippetsTreeNodeIds = useMemo(
|
||||
() => new Set(privateSnippetsTreeState.map((node) => node.id.toString())),
|
||||
[privateSnippetsTreeState]
|
||||
)
|
||||
|
||||
const validExpandedFolderIds = useMemo(
|
||||
() => expandedFolderIds.filter((id) => privateSnippetsTreeNodeIds.has(id)),
|
||||
[expandedFolderIds, privateSnippetsTreeNodeIds]
|
||||
)
|
||||
|
||||
const privateSnippetsLastItemIds = useMemo(
|
||||
() => getLastItemIds(privateSnippetsTreeState),
|
||||
[privateSnippetsTreeState]
|
||||
@@ -644,7 +654,7 @@ export const SQLEditorNav = ({ sort = 'inserted_at' }: SQLEditorNavProps) => {
|
||||
setExpandedFolderIds(expandedFolderIds.filter((x) => x !== folderId))
|
||||
}
|
||||
}}
|
||||
expandedIds={expandedFolderIds}
|
||||
expandedIds={validExpandedFolderIds}
|
||||
nodeRenderer={({ element, ...props }) => {
|
||||
const isOpened = Object.values(tabs.tabsMap).some(
|
||||
(tab) => tab.metadata?.sqlId === element.metadata?.id
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
type EdgeFunctionsData,
|
||||
} from '@/data/edge-functions/edge-functions-query'
|
||||
import { edgeFunctionsKeys } from '@/data/edge-functions/keys'
|
||||
import { handleError } from '@/data/fetchers'
|
||||
|
||||
interface UseEdgeFunctionsDiffProps {
|
||||
currentBranchRef?: string
|
||||
@@ -163,18 +162,6 @@ export const useEdgeFunctionsDiff = ({
|
||||
isCurrentFunctionsLoading ||
|
||||
isMainFunctionsLoading
|
||||
|
||||
// Aggregate errors across all queries and handle the first encountered error.
|
||||
const firstError = [
|
||||
...currentBodiesQueries,
|
||||
...mainBodiesQueries,
|
||||
...addedBodiesQueries,
|
||||
...removedBodiesQueries,
|
||||
].find((q) => q.error)?.error
|
||||
|
||||
if (firstError) {
|
||||
handleError(firstError)
|
||||
}
|
||||
|
||||
// Build lookup maps --------------------------------------------------------
|
||||
const currentBodiesMap: Record<string, EdgeFunctionBodyData | undefined> = {}
|
||||
currentBodiesQueries.forEach((q, idx) => {
|
||||
|
||||
Reference in new issue
Block a user