From 123fe7d5420a176a9213e05c0fe166049607cbb5 Mon Sep 17 00:00:00 2001 From: Pragadesh-45 <54320162+Pragadesh-45@users.noreply.github.com> Date: Thu, 25 Sep 2025 22:53:08 +0530 Subject: [PATCH] Merge pull request #5557 from Pragadesh-45/feat/default-location feat: default location for collections --- .../components/Preferences/General/index.js | 52 +++++++++++- .../Collection/CloneCollection/index.js | 5 +- .../Sidebar/Collections/Collection/index.js | 3 +- .../Sidebar/CreateCollection/index.js | 7 +- .../src/components/StatusBar/index.js | 2 +- .../bruno-app/src/components/Welcome/index.js | 2 +- .../src/providers/ReduxStore/slices/app.js | 3 + .../bruno-electron/src/store/preferences.js | 6 ++ .../collection/bruno.json | 5 ++ .../collection/collection.bru | 5 ++ .../collection/environments/Test.bru | 3 + .../collection/request.bru | 11 +++ .../default-collection-location.spec.js | 84 +++++++++++++++++++ .../init-user-data/collection-security.json | 10 +++ .../init-user-data/preferences.json | 9 ++ 15 files changed, 199 insertions(+), 8 deletions(-) create mode 100644 tests/preferences/default-collection-location/collection/bruno.json create mode 100644 tests/preferences/default-collection-location/collection/collection.bru create mode 100644 tests/preferences/default-collection-location/collection/environments/Test.bru create mode 100644 tests/preferences/default-collection-location/collection/request.bru create mode 100644 tests/preferences/default-collection-location/default-collection-location.spec.js create mode 100644 tests/preferences/default-collection-location/init-user-data/collection-security.json create mode 100644 tests/preferences/default-collection-location/init-user-data/preferences.json diff --git a/packages/bruno-app/src/components/Preferences/General/index.js b/packages/bruno-app/src/components/Preferences/General/index.js index 0f72e6b07..14eff0709 100644 --- a/packages/bruno-app/src/components/Preferences/General/index.js +++ b/packages/bruno-app/src/components/Preferences/General/index.js @@ -3,6 +3,7 @@ import get from 'lodash/get'; import { useFormik } from 'formik'; import { useSelector, useDispatch } from 'react-redux'; import { savePreferences } from 'providers/ReduxStore/slices/app'; +import { browseDirectory } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import * as Yup from 'yup'; import toast from 'react-hot-toast'; @@ -35,7 +36,8 @@ const General = ({ close }) => { }) .test('isValidTimeout', 'Request Timeout must be equal or greater than 0', (value) => { return value === undefined || Number(value) >= 0; - }) + }), + defaultCollectionLocation: Yup.string().max(1024) }); const formik = useFormik({ @@ -50,7 +52,8 @@ const General = ({ close }) => { }, timeout: preferences.request.timeout, storeCookies: get(preferences, 'request.storeCookies', true), - sendCookies: get(preferences, 'request.sendCookies', true) + sendCookies: get(preferences, 'request.sendCookies', true), + defaultCollectionLocation: get(preferences, 'general.defaultCollectionLocation', '') }, validationSchema: preferencesSchema, onSubmit: async (values) => { @@ -79,6 +82,9 @@ const General = ({ close }) => { timeout: newPreferences.timeout, storeCookies: newPreferences.storeCookies, sendCookies: newPreferences.sendCookies + }, + general: { + defaultCollectionLocation: newPreferences.defaultCollectionLocation } })) .then(() => { @@ -99,6 +105,19 @@ const General = ({ close }) => { formik.setFieldValue('customCaCertificate.filePath', null); }; + const browseDefaultLocation = () => { + dispatch(browseDirectory()) + .then((dirPath) => { + if (typeof dirPath === 'string') { + formik.setFieldValue('defaultCollectionLocation', dirPath); + } + }) + .catch((error) => { + formik.setFieldValue('defaultCollectionLocation', ''); + console.error(error); + }); + }; + return (
@@ -231,6 +250,35 @@ const General = ({ close }) => { {formik.touched.timeout && formik.errors.timeout ? (
{formik.errors.timeout}
) : null} +
+ + +
+ + Browse + +
+
+ {formik.touched.defaultCollectionLocation && formik.errors.defaultCollectionLocation ? ( +
{formik.errors.defaultCollectionLocation}
+ ) : null}
{isLoading ? : null} -
+
} placement="bottom-start">
{
{ menuDropdownTippyRef.current.hide(); setShowCloneCollectionModalOpen(true); diff --git a/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js b/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js index 3eb6707e0..642cf1ca9 100644 --- a/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js +++ b/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js @@ -1,5 +1,5 @@ import React, { useRef, useEffect } from 'react'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { useFormik } from 'formik'; import * as Yup from 'yup'; import { browseDirectory } from 'providers/ReduxStore/slices/collections/actions'; @@ -14,18 +14,21 @@ import Help from 'components/Help'; import { multiLineMsg } from "utils/common"; import { formatIpcError } from "utils/common/error"; import { toggleSidebarCollapse } from 'providers/ReduxStore/slices/app'; +import get from 'lodash/get'; const CreateCollection = ({ onClose }) => { const inputRef = useRef(); const dispatch = useDispatch(); const [isEditing, toggleEditing] = useState(false); + const preferences = useSelector((state) => state.app.preferences); + const defaultLocation = get(preferences, 'general.defaultCollectionLocation', ''); const formik = useFormik({ enableReinitialize: true, initialValues: { collectionName: '', collectionFolderName: '', - collectionLocation: '' + collectionLocation: defaultLocation }, validationSchema: Yup.object({ collectionName: Yup.string() diff --git a/packages/bruno-app/src/components/StatusBar/index.js b/packages/bruno-app/src/components/StatusBar/index.js index 25b984ffe..9ce6de680 100644 --- a/packages/bruno-app/src/components/StatusBar/index.js +++ b/packages/bruno-app/src/components/StatusBar/index.js @@ -82,7 +82,7 @@ const StatusBar = () => { diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/app.js b/packages/bruno-app/src/providers/ReduxStore/slices/app.js index 59495aec8..fa2c6fd3e 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/app.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/app.js @@ -25,6 +25,9 @@ const initialState = { font: { codeFont: 'default' }, + general: { + defaultCollectionLocation: '' + }, beta: { grpc: false } diff --git a/packages/bruno-electron/src/store/preferences.js b/packages/bruno-electron/src/store/preferences.js index 004d0e860..586d9bf95 100644 --- a/packages/bruno-electron/src/store/preferences.js +++ b/packages/bruno-electron/src/store/preferences.js @@ -47,6 +47,9 @@ const defaultPreferences = { }, onboarding: { hasLaunchedBefore: false + }, + general: { + defaultCollectionLocation: '' } }; @@ -89,6 +92,9 @@ const preferencesSchema = Yup.object().shape({ }), onboarding: Yup.object({ hasLaunchedBefore: Yup.boolean() + }), + general: Yup.object({ + defaultCollectionLocation: Yup.string().max(1024).nullable() }) }); diff --git a/tests/preferences/default-collection-location/collection/bruno.json b/tests/preferences/default-collection-location/collection/bruno.json new file mode 100644 index 000000000..03a26e1f7 --- /dev/null +++ b/tests/preferences/default-collection-location/collection/bruno.json @@ -0,0 +1,5 @@ +{ + "version": "1", + "name": "collection", + "type": "collection" +} diff --git a/tests/preferences/default-collection-location/collection/collection.bru b/tests/preferences/default-collection-location/collection/collection.bru new file mode 100644 index 000000000..408d3bd10 --- /dev/null +++ b/tests/preferences/default-collection-location/collection/collection.bru @@ -0,0 +1,5 @@ +meta { + name: collection + type: collection + version: 1.0.0 +} \ No newline at end of file diff --git a/tests/preferences/default-collection-location/collection/environments/Test.bru b/tests/preferences/default-collection-location/collection/environments/Test.bru new file mode 100644 index 000000000..e597f9c24 --- /dev/null +++ b/tests/preferences/default-collection-location/collection/environments/Test.bru @@ -0,0 +1,3 @@ +vars { + host: https://www.httpfaker.org +} diff --git a/tests/preferences/default-collection-location/collection/request.bru b/tests/preferences/default-collection-location/collection/request.bru new file mode 100644 index 000000000..baa0764c4 --- /dev/null +++ b/tests/preferences/default-collection-location/collection/request.bru @@ -0,0 +1,11 @@ +meta { + name: request + type: http + seq: 1 +} + +post { + url: {{host}}/api/echo + body: text + auth: none +} \ No newline at end of file diff --git a/tests/preferences/default-collection-location/default-collection-location.spec.js b/tests/preferences/default-collection-location/default-collection-location.spec.js new file mode 100644 index 000000000..8194d854c --- /dev/null +++ b/tests/preferences/default-collection-location/default-collection-location.spec.js @@ -0,0 +1,84 @@ +import { test, expect } from '../../../playwright'; + +test.describe('Default Collection Location Feature', () => { + test('Should hydrate the default location from preferences', async ({ pageWithUserData: page }) => { + // open preferences + await page.locator('.preferences-button').click(); + + // verify the default location is pre-filled + const defaultLocationInput = page.locator('.default-collection-location-input'); + await expect(defaultLocationInput).toHaveValue('/tmp/bruno-collections'); + + // close the preferences + await page.locator('[data-test-id="modal-close-button"]').click(); + + // wait for 2 seconds + await page.waitForTimeout(2000); + }); + + test('Should save empty default location', async ({ pageWithUserData: page }) => { + // open preferences + await page.locator('.preferences-button').click(); + + // clear the default location field + const defaultLocationInput = page.locator('.default-collection-location-input'); + await defaultLocationInput.clear(); + + // save preferences + await page.getByRole('button', { name: 'Save' }).click(); + + // verify success message + await expect(page.locator('text=Preferences saved successfully')).toBeVisible(); + + // wait for 2 seconds + await page.waitForTimeout(2000); + }); + + test('Should save a valid default location', async ({ pageWithUserData: page }) => { + // open preferences + await page.locator('.preferences-button').click(); + + // set a default location + const defaultLocationInput = page.locator('.default-collection-location-input'); + + // fill the default location input + await defaultLocationInput.fill('/tmp/bruno-collections'); + + // save preferences + await page.getByRole('button', { name: 'Save' }).click(); + + // verify success message + await expect(page.locator('text=Preferences saved successfully')).toBeVisible(); + + // wait for 2 seconds + await page.waitForTimeout(2000); + }); + + test('Should use default location in Create Collection modal', async ({ pageWithUserData: page }) => { + // test Create Collection modal + await page.locator('[data-testid="create-collection"]').click(); + + // verify the default location is pre-filled + const collectionLocationInput = page.getByLabel('Location'); + await expect(collectionLocationInput).toHaveValue('/tmp/bruno-collections'); + + // cancel the collection creation + await page.getByRole('button', { name: 'Cancel' }).click(); + + // wait for 2 seconds + await page.waitForTimeout(2000); + }); + + test('Should use default location in Clone Collection modal', async ({ pageWithUserData: page }) => { + // open the clone collection modal + await page.locator('[data-testid="collection-actions"]').click(); + await page.getByTestId('clone-collection').click(); + + // verify the default location is pre-filled + const cloneLocationInput = page.getByLabel('Location'); + await expect(cloneLocationInput).toHaveValue('/tmp/bruno-collections'); + + // wait for 2 seconds + await page.waitForTimeout(2000); + }); +}); diff --git a/tests/preferences/default-collection-location/init-user-data/collection-security.json b/tests/preferences/default-collection-location/init-user-data/collection-security.json new file mode 100644 index 000000000..e60afe806 --- /dev/null +++ b/tests/preferences/default-collection-location/init-user-data/collection-security.json @@ -0,0 +1,10 @@ +{ + "collections": [ + { + "path": "{{projectRoot}}/tests/preferences/default-collection-location/collection", + "securityConfig": { + "jsSandboxMode": "developer" + } + } + ] +} \ No newline at end of file diff --git a/tests/preferences/default-collection-location/init-user-data/preferences.json b/tests/preferences/default-collection-location/init-user-data/preferences.json new file mode 100644 index 000000000..fa1553037 --- /dev/null +++ b/tests/preferences/default-collection-location/init-user-data/preferences.json @@ -0,0 +1,9 @@ +{ + "maximized": true, + "lastOpenedCollections": ["{{projectRoot}}/tests/preferences/default-collection-location/collection"], + "preferences": { + "general": { + "defaultCollectionLocation": "/tmp/bruno-collections" + } + } +}