fix: keep recent items labels in sync after renames (#44155)

## What kind of change does this PR introduce?

Bug fix.

## What is the current behavior?

The `Recent items` list shown in the table editor empty-state can keep
showing an old label after a table or SQL snippet is renamed.

That UI is mounted from:
- `/project/[ref]/editor`
- `/project/[ref]/editor/new`

## What is the new behavior?

- Re-adding an existing recent item now refreshes its label and metadata
instead of only bumping the timestamp.
- Updating an open tab label now also updates the matching recent item,
so rename flows stay aligned with the recent-items list.
- The fix is applied in the shared tabs store, so table and SQL editor
tab state stay consistent even though the visible `Recent items` UI
currently appears in the table editor empty-state.
- Adds a small store-level regression test for both cases.

| Before | After |
| --- | --- |
| <img width="1024" height="563" alt="test Table Editor Mallet Toolshed
Supabase-DA49998A-FE09-4197-8EE7-5D5366FABDC7"
src="https://github.com/user-attachments/assets/d0475437-4486-4581-82f8-a84b97b08250"
/> | <img width="1024" height="563" alt="test Table Editor Mallet
Toolshed Supabase-8F2B6CC9-0721-4348-A094-EE94D6919B08"
src="https://github.com/user-attachments/assets/f055be35-4373-4b1b-a2e1-ffe59f12c177"
/> |
This commit is contained in:
Danny White authored and Matt Rossman committed 2026-03-30 16:02:53 -04:00
1 parent a337324c98
commit 585a4cedbf
2 files changed
+81 -2

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
import { beforeEach, describe, expect, it } from 'vitest'
import { createTabsState } from './tabs'
import { ENTITY_TYPE } from '@/data/entity-types/entity-type-constants'
describe('tabs recent items', () => {
beforeEach(() => {
localStorage.clear()
})
it('refreshes an existing recent item label when the tab is re-added', () => {
const store = createTabsState('default')
store.addRecentItem({
id: 'r-1',
type: ENTITY_TYPE.TABLE,
label: 'tasks',
metadata: {
schema: 'public',
name: 'tasks',
tableId: 1,
},
})
store.addRecentItem({
id: 'r-1',
type: ENTITY_TYPE.TABLE,
label: 'routines',
metadata: {
schema: 'public',
name: 'routines',
tableId: 1,
},
})
expect(store.recentItems).toHaveLength(1)
expect(store.recentItems[0].label).toBe('routines')
expect(store.recentItems[0].metadata?.name).toBe('routines')
})
it('keeps recent items aligned when an open tab label changes', () => {
const store = createTabsState('default')
store.addTab({
id: 'r-1',
type: ENTITY_TYPE.TABLE,
label: 'tasks',
metadata: {
schema: 'public',
name: 'tasks',
tableId: 1,
},
isPreview: false,
})
store.updateTab('r-1', { label: 'routines' })
expect(store.tabsMap['r-1'].label).toBe('routines')
expect(store.recentItems[0].label).toBe('routines')
expect(store.recentItems[0].metadata?.name).toBe('routines')
})
})
+19 -2
View File
@@ -110,7 +110,21 @@ function getSavedTabs(ref: string) {
}
}
function createTabsState(projectRef: string) {
const getRecentItemLabel = (tab: Pick<Tab, 'label' | 'metadata'>) =>
tab.label || tab.metadata?.name || 'Untitled'
const syncRecentItemWithTab = (item: RecentItem, tab: Pick<Tab, 'label' | 'metadata'>) => {
const nextLabel = getRecentItemLabel(tab)
item.label = nextLabel
item.metadata = {
...item.metadata,
...tab.metadata,
name: nextLabel,
}
}
export function createTabsState(projectRef: string) {
const recentItems = getSavedRecentItems(projectRef)
const { openTabs, activeTab, tabsMap, previewTabId } = getSavedTabs(projectRef)
@@ -125,6 +139,7 @@ function createTabsState(projectRef: string) {
if (existingItem) {
// If it exists, update its timestamp
existingItem.timestamp = Date.now()
syncRecentItemWithTab(existingItem, tab)
return // Exit the function
}
@@ -132,7 +147,7 @@ function createTabsState(projectRef: string) {
const recentItem: RecentItem = {
id: tab.id, // Set the ID
type: tab.type, // Set the type
label: tab.label || 'Untitled', // Set the label or default to 'Untitled'
label: getRecentItemLabel(tab), // Set the label or default to 'Untitled'
timestamp: Date.now(), // Set the current timestamp
metadata: tab.metadata, // Set the metadata
}
@@ -211,6 +226,8 @@ function createTabsState(projectRef: string) {
if (!!store.tabsMap[id]) {
if ('label' in updates) {
store.tabsMap[id].label = updates.label
const recentItem = store.recentItems.find((item) => item.id === id)
if (recentItem) syncRecentItemWithTab(recentItem, store.tabsMap[id])
}
if ('scrollTop' in updates && store.tabsMap[id].metadata) {
store.tabsMap[id].metadata.scrollTop = updates.scrollTop