mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-01 00:24:08 +00:00
fix: strip snapshot key for v4-migration tab (#8354)
This commit is contained in:
@@ -26,6 +26,10 @@ const NON_REPLACEABLE_SINGLETON_TAB_TYPES = new Set([
|
||||
'openapi-spec'
|
||||
]);
|
||||
|
||||
const IGNORED_TAB_TYPES = new Set([
|
||||
'v4-migration'
|
||||
]);
|
||||
|
||||
export const SAVE_TRIGGERS = new Map([
|
||||
['app/setSnapshotReady', null],
|
||||
['tabs/addTab', null],
|
||||
@@ -56,6 +60,24 @@ export const SAVE_TRIGGERS = new Map([
|
||||
|
||||
export const isRequestTab = (type) => REQUEST_TAB_TYPES.has(type);
|
||||
|
||||
const isIgnoredTab = (tab) => IGNORED_TAB_TYPES.has(tab?.type);
|
||||
|
||||
const isIgnoredActiveTab = (activeTab) => activeTab?.accessor === 'type' && IGNORED_TAB_TYPES.has(activeTab.value);
|
||||
|
||||
// Strip ignored tab types from a snapshot read on any path (lookups or ipc fallback),
|
||||
// including an active tab that points at one.
|
||||
const sanitizeSnapshotTabs = (tabsSnapshot) => {
|
||||
if (!tabsSnapshot || !Array.isArray(tabsSnapshot.tabs)) {
|
||||
return tabsSnapshot;
|
||||
}
|
||||
|
||||
return {
|
||||
...tabsSnapshot,
|
||||
activeTab: isIgnoredActiveTab(tabsSnapshot.activeTab) ? null : tabsSnapshot.activeTab,
|
||||
tabs: tabsSnapshot.tabs.filter((tab) => !isIgnoredTab(tab))
|
||||
};
|
||||
};
|
||||
|
||||
export const shouldExcludeTab = (tab, transientDirectory) => {
|
||||
return transientDirectory && tab.pathname?.startsWith(transientDirectory);
|
||||
};
|
||||
@@ -107,8 +129,8 @@ const normalizeCollectionSnapshotEntry = (pathname, entry = {}, tabsEntry = {})
|
||||
isMounted: typeof entry.isMounted === 'boolean' ? entry.isMounted : false,
|
||||
activeTab: tabsEntry.activeTab ?? entry.activeTab ?? null,
|
||||
tabs: Array.isArray(tabsEntry.tabs)
|
||||
? tabsEntry.tabs.filter((tab) => isObject(tab))
|
||||
: (Array.isArray(entry.tabs) ? entry.tabs.filter((tab) => isObject(tab)) : [])
|
||||
? tabsEntry.tabs.filter((tab) => isObject(tab) && !isIgnoredTab(tab))
|
||||
: (Array.isArray(entry.tabs) ? entry.tabs.filter((tab) => isObject(tab) && !isIgnoredTab(tab)) : [])
|
||||
};
|
||||
};
|
||||
|
||||
@@ -613,13 +635,15 @@ export const hydrateCollectionTabs = async (
|
||||
) => {
|
||||
const { ipcRenderer } = window;
|
||||
|
||||
const tabsSnapshot = getTabsSnapshotFromLookups(
|
||||
collection.pathname,
|
||||
snapshotLookups,
|
||||
workspacePathname,
|
||||
strictWorkspaceScope
|
||||
)
|
||||
|| await ipcRenderer.invoke('renderer:snapshot:get-tabs', collection.pathname, workspacePathname).catch(() => null);
|
||||
const tabsSnapshot = sanitizeSnapshotTabs(
|
||||
getTabsSnapshotFromLookups(
|
||||
collection.pathname,
|
||||
snapshotLookups,
|
||||
workspacePathname,
|
||||
strictWorkspaceScope
|
||||
)
|
||||
|| await ipcRenderer.invoke('renderer:snapshot:get-tabs', collection.pathname, workspacePathname).catch(() => null)
|
||||
);
|
||||
|
||||
const hasPersistedTabs = Array.isArray(tabsSnapshot?.tabs) && tabsSnapshot.tabs.length > 0;
|
||||
const hasPersistedActiveTab = Boolean(tabsSnapshot?.activeTab);
|
||||
@@ -651,8 +675,10 @@ export const hydrateTabs = async (collections, dispatch, restoreTabs, snapshotLo
|
||||
export const getActiveTabFromSnapshot = async (collectionPathname, collection, snapshotLookups = null, workspacePathname = null) => {
|
||||
const { ipcRenderer } = window;
|
||||
|
||||
const tabsSnapshot = getTabsSnapshotFromLookups(collectionPathname, snapshotLookups, workspacePathname)
|
||||
|| await ipcRenderer.invoke('renderer:snapshot:get-tabs', collectionPathname, workspacePathname).catch(() => null);
|
||||
const tabsSnapshot = sanitizeSnapshotTabs(
|
||||
getTabsSnapshotFromLookups(collectionPathname, snapshotLookups, workspacePathname)
|
||||
|| await ipcRenderer.invoke('renderer:snapshot:get-tabs', collectionPathname, workspacePathname).catch(() => null)
|
||||
);
|
||||
|
||||
if (!tabsSnapshot?.activeTab || !tabsSnapshot?.tabs?.length) return null;
|
||||
|
||||
|
||||
@@ -218,6 +218,27 @@ describe('hydrateSnapshotLookups', () => {
|
||||
|
||||
expect(lookups.hasWorkspaceScopedTabs).toBe(true);
|
||||
});
|
||||
|
||||
it('drops legacy v4 migration tabs from snapshot lookups', () => {
|
||||
const snapshot = {
|
||||
collections: [
|
||||
{
|
||||
pathname: '/collections/legacy',
|
||||
activeTab: { accessor: 'type', value: 'v4-migration' },
|
||||
tabs: [
|
||||
{ type: 'v4-migration', accessor: 'type', permanent: true },
|
||||
{ type: 'variables', accessor: 'type', permanent: true }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const lookups = hydrateSnapshotLookups(snapshot);
|
||||
|
||||
expect(lookups.tabsByCollectionPath['/collections/legacy'].tabs).toEqual([
|
||||
{ type: 'variables', accessor: 'type', permanent: true }
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deserializeTab', () => {
|
||||
@@ -766,4 +787,79 @@ describe('hydrateCollectionTabs', () => {
|
||||
expect(dispatch).toHaveBeenCalledTimes(1);
|
||||
expect(restoreTabs).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not restore legacy v4 migration tabs from direct tab snapshots', async () => {
|
||||
global.window.ipcRenderer.invoke.mockResolvedValue({
|
||||
tabs: [
|
||||
{ type: 'v4-migration', accessor: 'type', permanent: true },
|
||||
{ type: 'variables', accessor: 'type', permanent: true }
|
||||
],
|
||||
activeTab: {
|
||||
accessor: 'type',
|
||||
value: 'v4-migration'
|
||||
}
|
||||
});
|
||||
|
||||
const dispatch = jest.fn();
|
||||
const restoreTabs = jest.fn((payload) => ({
|
||||
type: 'tabs/restoreTabs',
|
||||
payload
|
||||
}));
|
||||
|
||||
await hydrateCollectionTabs(
|
||||
{ uid: 'collection-uid', pathname: '/collections/legacy' },
|
||||
dispatch,
|
||||
restoreTabs,
|
||||
null,
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
expect(restoreTabs).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
tabs: [{ type: 'variables', accessor: 'type', permanent: true }],
|
||||
activeTab: null
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getActiveTabFromSnapshot', () => {
|
||||
beforeEach(() => {
|
||||
global.window = {
|
||||
ipcRenderer: {
|
||||
invoke: jest.fn().mockResolvedValue(null)
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
delete global.window;
|
||||
});
|
||||
|
||||
it('ignores a legacy v4 migration active tab snapshot', async () => {
|
||||
const snapshot = {
|
||||
collections: [
|
||||
{
|
||||
pathname: '/collections/legacy',
|
||||
tabs: [
|
||||
{ type: 'v4-migration', accessor: 'type', permanent: true }
|
||||
],
|
||||
activeTab: {
|
||||
accessor: 'type',
|
||||
value: 'v4-migration'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
const lookups = hydrateSnapshotLookups(snapshot);
|
||||
|
||||
const activeTab = await getActiveTabFromSnapshot(
|
||||
'/collections/legacy',
|
||||
{ uid: 'collection-uid', pathname: '/collections/legacy' },
|
||||
lookups
|
||||
);
|
||||
|
||||
expect(activeTab).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user