mirror of
https://github.com/supabase/supabase.git
synced 2026-05-07 06:27:16 +08:00
fix: resolve undefined project ref in TabsStateContextProvider (#43222)
This pull request refactors how the `TabsStateContextProvider` receives
the project reference and updates related imports for consistency and
maintainability. The main change is to pass `projectRef` explicitly as a
prop instead of fetching it internally, which improves context control
and makes the component easier to test and reuse. Additionally, the PR
updates import paths to use absolute aliases and removes an unused
function.
This fixes an issue which you can replicate by:
1. Go to SQL editor
2. Open any snippet
3. Delete the local storage `supabase_studio_tabs_{project ref}`
4. Refresh the page while still the snippet is open
This will make the snippet to enter in a ghost state where the tab name
is not visible but you see the content.
---------
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import { PropsWithChildren } from 'react'
|
||||
import { DatabaseSelectorStateContextProvider } from 'state/database-selector'
|
||||
import { RoleImpersonationStateContextProvider } from 'state/role-impersonation-state'
|
||||
import { StorageExplorerStateContextProvider } from 'state/storage-explorer'
|
||||
import { TableEditorStateContextProvider } from 'state/table-editor'
|
||||
import { TabsStateContextProvider } from 'state/tabs'
|
||||
|
||||
import { DatabaseSelectorStateContextProvider } from '@/state/database-selector'
|
||||
import { RoleImpersonationStateContextProvider } from '@/state/role-impersonation-state'
|
||||
import { StorageExplorerStateContextProvider } from '@/state/storage-explorer'
|
||||
import { TableEditorStateContextProvider } from '@/state/table-editor'
|
||||
import { TabsStateContextProvider } from '@/state/tabs'
|
||||
|
||||
type ProjectContextProviderProps = {
|
||||
projectRef: string | undefined
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { buildTableEditorUrl } from 'components/grid/SupabaseGrid.utils'
|
||||
import { ENTITY_TYPE } from 'data/entity-types/entity-type-constants'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useParams } from 'common'
|
||||
import { partition } from 'lodash'
|
||||
import { NextRouter } from 'next/router'
|
||||
import { type NextRouter } from 'next/router'
|
||||
import { createContext, PropsWithChildren, useContext, useEffect, useState } from 'react'
|
||||
import { proxy, subscribe, useSnapshot } from 'valtio'
|
||||
|
||||
import { buildTableEditorUrl } from '@/components/grid/SupabaseGrid.utils'
|
||||
import { ENTITY_TYPE } from '@/data/entity-types/entity-type-constants'
|
||||
|
||||
export const editorEntityTypes = {
|
||||
table: ['r', 'v', 'm', 'f', 'p'],
|
||||
sql: ['sql'],
|
||||
@@ -387,7 +388,7 @@ function createTabsState(projectRef: string) {
|
||||
onClearDashboardHistory()
|
||||
router.push(`/project/${router.query.ref}/${editor === 'table' ? 'editor' : 'sql'}`)
|
||||
},
|
||||
handleTabDragEnd: (oldIndex: number, newIndex: number, tabId: string, router: any) => {
|
||||
handleTabDragEnd: (oldIndex: number, newIndex: number, tabId: string, router: NextRouter) => {
|
||||
// Make permanent if needed
|
||||
const draggedTab = store.tabsMap[tabId]
|
||||
if (draggedTab?.isPreview) {
|
||||
@@ -415,20 +416,20 @@ export type TabsState = ReturnType<typeof createTabsState>
|
||||
export const TabsStateContext = createContext<TabsState>(createTabsState(''))
|
||||
|
||||
export const TabsStateContextProvider = ({ children }: PropsWithChildren) => {
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const [state, setState] = useState(createTabsState(project?.ref ?? ''))
|
||||
const { ref: projectRef } = useParams()
|
||||
const [state, setState] = useState(createTabsState(projectRef ?? ''))
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window !== 'undefined' && !!project?.ref) {
|
||||
setState(createTabsState(project?.ref ?? ''))
|
||||
if (typeof window !== 'undefined' && !!projectRef) {
|
||||
setState(createTabsState(projectRef ?? ''))
|
||||
}
|
||||
}, [project?.ref])
|
||||
}, [projectRef])
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window !== 'undefined' && project?.ref) {
|
||||
if (typeof window !== 'undefined' && projectRef) {
|
||||
return subscribe(state, () => {
|
||||
localStorage.setItem(
|
||||
getTabsStorageKey(project?.ref),
|
||||
getTabsStorageKey(projectRef),
|
||||
JSON.stringify({
|
||||
activeTab: state.activeTab,
|
||||
openTabs: state.openTabs,
|
||||
@@ -437,14 +438,14 @@ export const TabsStateContextProvider = ({ children }: PropsWithChildren) => {
|
||||
})
|
||||
)
|
||||
localStorage.setItem(
|
||||
getRecentItemsStorageKey(project?.ref),
|
||||
getRecentItemsStorageKey(projectRef),
|
||||
JSON.stringify({
|
||||
items: state.recentItems,
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
}, [project?.ref, state])
|
||||
}, [projectRef, state])
|
||||
|
||||
return <TabsStateContext.Provider value={state}>{children}</TabsStateContext.Provider>
|
||||
}
|
||||
@@ -472,37 +473,3 @@ export function createTabId<T extends TabType>(type: T, params: CreateTabIdParam
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from local storage when feature flag is disabled
|
||||
export function removeTabsByEditor(ref: string, editor: 'table' | 'sql') {
|
||||
// Recent items
|
||||
const recentItems = getSavedRecentItems(ref)
|
||||
const filteredRecentItems = recentItems.filter((item) =>
|
||||
editor === 'sql' ? item.type !== 'sql' : item.type === 'sql'
|
||||
)
|
||||
localStorage.setItem(
|
||||
getRecentItemsStorageKey(ref),
|
||||
JSON.stringify({ items: filteredRecentItems })
|
||||
)
|
||||
|
||||
// Tabs
|
||||
const tabs = getSavedTabs(ref)
|
||||
const filteredTabsMap = Object.fromEntries(
|
||||
Object.entries(tabs.tabsMap).filter(([, tab]) =>
|
||||
editor === 'sql' ? tab.type !== 'sql' : tab.type === 'sql'
|
||||
)
|
||||
)
|
||||
|
||||
const filteredOpenTabs = tabs.openTabs.filter((tabId) => filteredTabsMap[tabId])
|
||||
localStorage.setItem(
|
||||
getTabsStorageKey(ref),
|
||||
JSON.stringify({
|
||||
activeTab: filteredOpenTabs.includes(tabs.activeTab ?? '')
|
||||
? tabs.activeTab
|
||||
: filteredOpenTabs[0] ?? null,
|
||||
openTabs: filteredOpenTabs,
|
||||
tabsMap: filteredTabsMap,
|
||||
previewTabId: tabs.previewTabId,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user