Compare commits

...

5 Commits

Author SHA1 Message Date
sanish chirayath
068900866c fix: update preferences saving method in preferences utility (#5617)
* fix: update preferences saving method in preferences utility

* fix: make markAsLaunched asynchronous and improve error handling in onboarding process

* fix: lint errors

---------

Co-authored-by: Bijin Bruno <bijin@usebruno.com>
2025-09-25 18:40:36 +05:30
Pragadesh-45
fa5ac0d460 Merge pull request #5613 from Pragadesh-45/main 2025-09-25 18:40:29 +05:30
Pooja
c8da13bd9b fix: Add null safety checks in GlobalSearchModal (#5625)
* fix: Add null safety checks in GlobalSearchModal
2025-09-25 18:40:19 +05:30
Pragadesh-45
86727c8525 fix: add Linux support for xdg-portal version in Electron app (#5618) 2025-09-25 18:40:13 +05:30
John Vester
901b6daaea Merge pull request #5582 from johnjvester/5579_correct_spelling
5579 - correct spelling error and introduce constant to avoid duplication
2025-09-25 18:40:05 +05:30
10 changed files with 47 additions and 20 deletions

View File

@@ -193,7 +193,7 @@ const EnvironmentSelector = ({ collection }) => {
{/* Modals - Rendered outside dropdown to avoid conflicts */}
{showGlobalSettings && (
<GlobalEnvironmentSettings globalEnvironments={globalEnvironments} onClose={handleCloseSettings} />
<GlobalEnvironmentSettings globalEnvironments={globalEnvironments} collection={collection} onClose={handleCloseSettings} />
)}
{showCollectionSettings && <EnvironmentSettings collection={collection} onClose={handleCloseSettings} />}

View File

@@ -2,7 +2,7 @@ import React, { useRef, useEffect } from 'react';
import cloneDeep from 'lodash/cloneDeep';
import { IconTrash, IconAlertCircle } from '@tabler/icons';
import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import MultiLineEditor from 'components/MultiLineEditor/index';
import StyledWrapper from './StyledWrapper';
import { uuid } from 'utils/common';
@@ -12,11 +12,18 @@ import { variableNameRegex } from 'utils/common/regex';
import toast from 'react-hot-toast';
import { saveGlobalEnvironment } from 'providers/ReduxStore/slices/global-environments';
import { Tooltip } from 'react-tooltip';
import { getGlobalEnvironmentVariables } from 'utils/collections';
const EnvironmentVariables = ({ environment, setIsModified, originalEnvironmentVariables }) => {
const EnvironmentVariables = ({ environment, setIsModified, originalEnvironmentVariables, collection }) => {
const dispatch = useDispatch();
const { storedTheme } = useTheme();
const addButtonRef = useRef(null);
const { globalEnvironments, activeGlobalEnvironmentUid } = useSelector(state => state.globalEnvironments);
let _collection = cloneDeep(collection);
const globalEnvironmentVariables = getGlobalEnvironmentVariables({ globalEnvironments, activeGlobalEnvironmentUid });
_collection.globalEnvironmentVariables = globalEnvironmentVariables;
const formik = useFormik({
enableReinitialize: true,
@@ -93,7 +100,7 @@ const EnvironmentVariables = ({ environment, setIsModified, originalEnvironmentV
useEffect(() => {
if (formik.dirty) {
// Smooth scrolling to the changed parameter is temporarily disabled
// Smooth scrolling to the changed parameter is temporarily disabled
// due to UX issues when editing the first row in a long list of environment variables.
// addButtonRef.current?.scrollIntoView({ behavior: 'smooth' });
}
@@ -149,7 +156,7 @@ const EnvironmentVariables = ({ environment, setIsModified, originalEnvironmentV
<div className="overflow-hidden grow w-full relative">
<MultiLineEditor
theme={storedTheme}
collection={{}}
collection={_collection}
name={`${index}.value`}
value={variable.value}
isSecret={variable.secret}

View File

@@ -5,7 +5,7 @@ import DeleteEnvironment from '../../DeleteEnvironment';
import RenameEnvironment from '../../RenameEnvironment';
import EnvironmentVariables from './EnvironmentVariables';
const EnvironmentDetails = ({ environment, setIsModified }) => {
const EnvironmentDetails = ({ environment, setIsModified, collection }) => {
const [openEditModal, setOpenEditModal] = useState(false);
const [openDeleteModal, setOpenDeleteModal] = useState(false);
const [openCopyModal, setOpenCopyModal] = useState(false);
@@ -37,7 +37,7 @@ const EnvironmentDetails = ({ environment, setIsModified }) => {
</div>
<div>
<EnvironmentVariables environment={environment} setIsModified={setIsModified} />
<EnvironmentVariables environment={environment} setIsModified={setIsModified} collection={collection} />
</div>
</div>
);

View File

@@ -10,7 +10,7 @@ import ImportEnvironment from '../ImportEnvironment';
import { isEqual } from 'lodash';
import ToolHint from 'components/ToolHint/index';
const EnvironmentList = ({ environments, activeEnvironmentUid, selectedEnvironment, setSelectedEnvironment, isModified, setIsModified }) => {
const EnvironmentList = ({ environments, activeEnvironmentUid, selectedEnvironment, setSelectedEnvironment, isModified, setIsModified, collection }) => {
const [openCreateModal, setOpenCreateModal] = useState(false);
const [openImportModal, setOpenImportModal] = useState(false);
const [openManageSecretsModal, setOpenManageSecretsModal] = useState(false);
@@ -143,6 +143,7 @@ const EnvironmentList = ({ environments, activeEnvironmentUid, selectedEnvironme
environment={selectedEnvironment}
setIsModified={setIsModified}
originalEnvironmentVariables={originalEnvironmentVariables}
collection={collection}
/>
</div>
</StyledWrapper>

View File

@@ -39,7 +39,7 @@ const DefaultTab = ({ setTab }) => {
);
};
const EnvironmentSettings = ({ globalEnvironments, onClose }) => {
const EnvironmentSettings = ({ globalEnvironments, collection, onClose }) => {
const [isModified, setIsModified] = useState(false);
const environments = globalEnvironments;
const [selectedEnvironment, setSelectedEnvironment] = useState(null);
@@ -68,6 +68,7 @@ const EnvironmentSettings = ({ globalEnvironments, onClose }) => {
setSelectedEnvironment={setSelectedEnvironment}
isModified={isModified}
setIsModified={setIsModified}
collection={collection}
/>
</Modal>
);

View File

@@ -73,7 +73,8 @@ const GlobalSearchModal = ({ isOpen, onClose }) => {
const itemPathLower = itemPath.toLowerCase();
if (isItemARequest(item)) {
const nameMatch = searchTerms.every(term => item.name.toLowerCase().includes(term));
// add an optional check for the item name to prevent a crash if it doesnt exist.
const nameMatch = searchTerms.every(term => (item.name || '').toLowerCase().includes(term));
const urlMatch = searchTerms.every(term => (item.request?.url || '').toLowerCase().includes(term));
const pathMatch = enablePathMatch && searchTerms.every(term => itemPathLower.includes(term));

View File

@@ -77,11 +77,12 @@ async function onboardUser(mainWindow, lastOpenedCollections) {
}
if (process.env.DISABLE_SAMPLE_COLLECTION_IMPORT !== 'true') {
// Onboarding was added later;
// if a collection already exists, user is old skip onboarding
// Check if user already has collections (indicates they're an existing user)
// Onboarding was added in a later version, so for existing users we should skip it
// to avoid creating sample collections
const collections = await lastOpenedCollections.getAll();
if (collections.length > 0) {
preferencesUtil.markAsLaunched();
await preferencesUtil.markAsLaunched();
return;
}
@@ -89,11 +90,11 @@ async function onboardUser(mainWindow, lastOpenedCollections) {
await importSampleCollection(collectionLocation, mainWindow, lastOpenedCollections);
}
preferencesUtil.markAsLaunched();
await preferencesUtil.markAsLaunched();
} catch (error) {
console.error('Failed to handle onboarding:', error);
// Still mark as launched to prevent retry on next startup
preferencesUtil.markAsLaunched();
await preferencesUtil.markAsLaunched();
}
}

View File

@@ -1,6 +1,7 @@
const fs = require('fs');
const path = require('path');
const isDev = require('electron-is-dev');
const os = require('os');
if (isDev) {
if(!fs.existsSync(path.join(__dirname, '../../bruno-js/src/sandbox/bundle-browser-rollup.js'))) {
@@ -21,6 +22,14 @@ if (isDev && process.env.ELECTRON_USER_DATA_PATH) {
app.setPath('userData', process.env.ELECTRON_USER_DATA_PATH);
}
// Command line switches
if (os.platform() === 'linux') {
// Use portal version 4 that supports current_folder option
// to address https://github.com/usebruno/bruno/issues/5471
// Runtime sets the default version to 3, refs https://github.com/electron/electron/pull/44426
app.commandLine.appendSwitch('xdg-portal-required-version', '4');
}
const menuTemplate = require('./app/menu-template');
const { openCollection } = require('./app/collections');
const LastOpenedCollections = require('./store/last-opened-collections');

View File

@@ -34,6 +34,8 @@ const { cookiesStore } = require('../../store/cookies');
const registerGrpcEventHandlers = require('./grpc-event-handlers');
const { getCertsAndProxyConfig } = require('./cert-utils');
const ERROR_OCCURRED_WHILE_EXECUTING_REQUEST = 'Error occurred while executing the request!';
const saveCookies = (url, headers) => {
if (preferencesUtil.shouldStoreCookies()) {
let setCookieHeaders = [];
@@ -674,7 +676,7 @@ const registerNetworkIpc = (mainWindow) => {
// timeline prop won't be accessible in the usual way in the renderer process if we reject the promise
return {
statusText: error.statusText,
error: error.message || 'Error occured while executing the request!',
error: error.message || ERROR_OCCURRED_WHILE_EXECUTING_REQUEST,
timeline: error.timeline
}
}
@@ -853,7 +855,7 @@ const registerNetworkIpc = (mainWindow) => {
// timeline prop won't be accessible in the usual way in the renderer process if we reject the promise
return {
status: error?.status,
error: error?.message || 'Error occured while executing the request!',
error: error?.message || ERROR_OCCURRED_WHILE_EXECUTING_REQUEST,
timeline: error?.timeline
};
}
@@ -1497,7 +1499,7 @@ const executeRequestOnFailHandler = async (request, error) => {
} catch (handlerError) {
console.error('Error executing onFail handler', handlerError);
// @TODO: This is a temporary solution to display the error message in the response pane. Revisit and handle properly.
error.message = `1. Request failed: ${error.message || 'Error occured while executing the request!'}\n2. Error executing onFail handler: ${handlerError.message || 'Unknown error'}`;
error.message = `1. Request failed: ${error.message || ERROR_OCCURRED_WHILE_EXECUTING_REQUEST}\n2. Error executing onFail handler: ${handlerError.message || 'Unknown error'}`;
}
};

View File

@@ -186,10 +186,15 @@ const preferencesUtil = {
hasLaunchedBefore: () => {
return get(getPreferences(), 'onboarding.hasLaunchedBefore', false);
},
markAsLaunched: () => {
markAsLaunched: async () => {
const preferences = getPreferences();
preferences.onboarding.hasLaunchedBefore = true;
preferencesStore.savePreferences(preferences);
try {
await savePreferences(preferences);
} catch (err) {
console.error('Failed to save preferences in markAsLaunched:', err);
}
}
};