diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js index b24d5f9f4..930845c60 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js @@ -28,8 +28,8 @@ const EnvironmentDetails = ({ environment, setIsModified, collection, searchQuer const [newName, setNewName] = useState(''); const [nameError, setNameError] = useState(''); const activeTabUid = useSelector((state) => state.tabs.activeTabUid); - const activeTab = useSelector((state) => state.tabs.tabs.find((t) => t.uid === activeTabUid)?.tabState?.envTab) || 'variables'; - const setActiveTab = (tab) => dispatch(updateTabState({ uid: activeTabUid, tabState: { envTab: tab } })); + const activeTab = useSelector((state) => state.tabs.tabs.find((t) => t.uid === activeTabUid)?.tabState?.environment?.tab) || 'variables'; + const setActiveTab = (tab) => dispatch(updateTabState({ uid: activeTabUid, tabState: { environment: { tab } } })); // Use the immediate query on a tab switch (debounced value lags and briefly // flashes the unfiltered table). diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js index 957124401..4bb0436ab 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js @@ -43,7 +43,7 @@ const EnvironmentList = ({ }) => { const dispatch = useDispatch(); const activeTabUid = useSelector((state) => state.tabs.activeTabUid); - const activeEnvTab = useSelector((state) => state.tabs.tabs.find((t) => t.uid === activeTabUid)?.tabState?.envTab) || 'variables'; + const activeEnvTab = useSelector((state) => state.tabs.tabs.find((t) => t.uid === activeTabUid)?.tabState?.environment?.tab) || 'variables'; const envSearchQuery = useSelector((state) => state.app.envVarSearch?.collection?.[activeEnvTab]?.query ?? ''); const isEnvSearchExpanded = useSelector((state) => state.app.envVarSearch?.collection?.[activeEnvTab]?.expanded ?? false); const setEnvSearchQuery = (q) => dispatch(setEnvVarSearchQuery({ context: 'collection', tab: activeEnvTab, query: q })); diff --git a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js index 0096c2ebb..0b2f1977b 100644 --- a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js +++ b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js @@ -28,8 +28,8 @@ const EnvironmentDetails = ({ environment, setIsModified, collection, searchQuer const [newName, setNewName] = useState(''); const [nameError, setNameError] = useState(''); const activeTabUid = useSelector((state) => state.tabs.activeTabUid); - const activeTab = useSelector((state) => state.tabs.tabs.find((t) => t.uid === activeTabUid)?.tabState?.envTab) || 'variables'; - const setActiveTab = (tab) => dispatch(updateTabState({ uid: activeTabUid, tabState: { envTab: tab } })); + const activeTab = useSelector((state) => state.tabs.tabs.find((t) => t.uid === activeTabUid)?.tabState?.environment?.tab) || 'variables'; + const setActiveTab = (tab) => dispatch(updateTabState({ uid: activeTabUid, tabState: { environment: { tab } } })); // Use the immediate query on a tab switch (debounced value lags and briefly // flashes the unfiltered table). diff --git a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js index 540fe8353..29e707232 100644 --- a/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js +++ b/packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js @@ -44,7 +44,7 @@ const EnvironmentList = ({ const dispatch = useDispatch(); const globalEnvs = useSelector((state) => state?.globalEnvironments?.globalEnvironments); const activeTabUid = useSelector((state) => state.tabs.activeTabUid); - const activeEnvTab = useSelector((state) => state.tabs.tabs.find((t) => t.uid === activeTabUid)?.tabState?.envTab) || 'variables'; + const activeEnvTab = useSelector((state) => state.tabs.tabs.find((t) => t.uid === activeTabUid)?.tabState?.environment?.tab) || 'variables'; const envSearchQuery = useSelector((state) => state.app.envVarSearch?.global?.[activeEnvTab]?.query ?? ''); const isEnvSearchExpanded = useSelector((state) => state.app.envVarSearch?.global?.[activeEnvTab]?.expanded ?? false); const setEnvSearchQuery = (q) => dispatch(setEnvVarSearchQuery({ context: 'global', tab: activeEnvTab, query: q })); diff --git a/packages/bruno-app/src/utils/snapshot/index.js b/packages/bruno-app/src/utils/snapshot/index.js index e5ef5cb67..5331fed98 100644 --- a/packages/bruno-app/src/utils/snapshot/index.js +++ b/packages/bruno-app/src/utils/snapshot/index.js @@ -472,6 +472,11 @@ export const serializeTab = (tab, collection) => { }; } + const isEnvironmentTab = tab.type === 'environment-settings' || tab.type === 'global-environment-settings'; + if (isEnvironmentTab && tab.tabState?.environment?.tab) { + serialized.environment = { tab: tab.tabState.environment.tab }; + } + return serialized; }; @@ -650,6 +655,10 @@ export const deserializeTab = (snapshotTab, collection) => { } } + if (snapshotTab.environment?.tab) { + tab.tabState = { environment: { tab: snapshotTab.environment.tab } }; + } + return tab; }; diff --git a/packages/bruno-electron/src/services/snapshot/index.js b/packages/bruno-electron/src/services/snapshot/index.js index d8c29c373..9688e08f9 100644 --- a/packages/bruno-electron/src/services/snapshot/index.js +++ b/packages/bruno-electron/src/services/snapshot/index.js @@ -45,6 +45,9 @@ const tabSchema = yup.object({ tab: yup.string(), format: yup.string().nullable(), viewTab: yup.string().nullable() + }).optional(), + environment: yup.object({ + tab: yup.string() }).optional() }); diff --git a/tests/snapshots/environment/environment.spec.ts b/tests/snapshots/environment/environment.spec.ts index cdc70837d..199591399 100644 --- a/tests/snapshots/environment/environment.spec.ts +++ b/tests/snapshots/environment/environment.spec.ts @@ -2,6 +2,7 @@ import path from 'path'; import fs from 'fs'; import { test, expect, closeElectronApp } from '../../../playwright'; import { + buildCommonLocators, createCollection, createEnvironment, openCollection, @@ -358,4 +359,59 @@ test.describe('Snapshot: Collection Environment Persistence', () => { expect(entry?.selectedEnvironment).toBe('local-bad'); expect(entry?.environmentPath).toContain('local-bad'); }); + + const envSubTab = (page: any, key: string) => { + const { environment } = buildCommonLocators(page); + return key === 'secrets' ? environment.secretsTab() : environment.variablesTab(); + }; + + for (const subTab of ['variables', 'secrets']) { + test(`persists the "${subTab}" environment-settings sub-tab across snapshot saves and restarts`, async ({ launchElectronApp, createTmpDir }) => { + // One restart plus environment creation; the default budget is tight on slower machines. + test.setTimeout(60000); + const userDataPath = await createTmpDir(`snap-env-subtab-${subTab}`); + const collectionPath = await createTmpDir(`snap-env-subtab-col-${subTab}`); + const collectionRoot = path.join(collectionPath, 'SubTabCollection'); + + const app = await launchElectronApp({ userDataPath }); + const page = await waitForReadyPage(app); + + await test.step(`Open environment settings and switch to the "${subTab}" sub-tab`, async () => { + await createCollection(page, 'SubTabCollection', collectionPath); + await openCollection(page, 'SubTabCollection'); + await createEnvironment(page, 'local', 'collection'); + + const tab = envSubTab(page, subTab); + await tab.click(); + await expect(tab).toHaveClass(/active/); + }); + + await test.step('Close app and assert the snapshot stores the selected sub-tab', async () => { + await page.waitForTimeout(2000); + await closeElectronApp(app); + + const snapshot = readSnapshot(userDataPath); + expect(snapshot).not.toBeNull(); + + const collections = Array.isArray(snapshot?.collections) ? snapshot.collections : []; + const collectionEntry = collections.find((collection: any) => collection?.pathname === collectionRoot); + const environmentTab = (Array.isArray(collectionEntry?.tabs) ? collectionEntry.tabs : []) + .find((tab: any) => tab?.type === 'environment-settings'); + + expect(environmentTab?.environment?.tab).toBe(subTab); + }); + + await test.step(`Restart app and verify the "${subTab}" sub-tab is restored`, async () => { + const app2 = await launchElectronApp({ userDataPath }); + const page2 = await waitForReadyPage(app2); + + await openCollection(page2, 'SubTabCollection'); + // Focus the restored Environments tab; the sub-tab only renders while it is active. + await buildCommonLocators(page2).environment.collectionEnvTab().click(); + await expect(envSubTab(page2, subTab)).toHaveClass(/active/); + + await closeElectronApp(app2); + }); + }); + } });