Skip to content

Commit 828cb19

Browse files
authored
fix: improve environment variable comparison by stripping UIDs (#7100)
1 parent a86f0e4 commit 828cb19

File tree

4 files changed

+48
-9
lines changed

4 files changed

+48
-9
lines changed

packages/bruno-app/src/components/EnvironmentVariablesTable/index.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { variableNameRegex } from 'utils/common/regex';
1313
import toast from 'react-hot-toast';
1414
import { Tooltip } from 'react-tooltip';
1515
import { getGlobalEnvironmentVariables } from 'utils/collections';
16+
import { stripEnvVarUid } from 'utils/environments';
1617

1718
const MIN_H = 35 * 2;
1819
const MIN_COLUMN_WIDTH = 80;
@@ -187,13 +188,13 @@ const EnvironmentVariablesTable = ({
187188
}, [environment.uid, hasDraftForThisEnv, draft?.variables]);
188189

189190
const savedValuesJson = useMemo(() => {
190-
return JSON.stringify(environment.variables || []);
191+
return JSON.stringify((environment.variables || []).map(stripEnvVarUid));
191192
}, [environment.variables]);
192193

193194
// Sync modified state
194195
useEffect(() => {
195196
const currentValues = formik.values.filter((variable) => variable.name && variable.name.trim() !== '');
196-
const currentValuesJson = JSON.stringify(currentValues);
197+
const currentValuesJson = JSON.stringify(currentValues.map(stripEnvVarUid));
197198
const hasActualChanges = currentValuesJson !== savedValuesJson;
198199
setIsModified(hasActualChanges);
199200
}, [formik.values, savedValuesJson, setIsModified]);
@@ -202,11 +203,11 @@ const EnvironmentVariablesTable = ({
202203
useEffect(() => {
203204
const timeoutId = setTimeout(() => {
204205
const currentValues = formik.values.filter((variable) => variable.name && variable.name.trim() !== '');
205-
const currentValuesJson = JSON.stringify(currentValues);
206+
const currentValuesJson = JSON.stringify(currentValues.map(stripEnvVarUid));
206207
const hasActualChanges = currentValuesJson !== savedValuesJson;
207208

208209
const existingDraftVariables = hasDraftForThisEnv ? draft?.variables : null;
209-
const existingDraftJson = existingDraftVariables ? JSON.stringify(existingDraftVariables) : null;
210+
const existingDraftJson = existingDraftVariables ? JSON.stringify(existingDraftVariables.map(stripEnvVarUid)) : null;
210211

211212
if (hasActualChanges) {
212213
if (currentValuesJson !== existingDraftJson) {
@@ -318,7 +319,8 @@ const EnvironmentVariablesTable = ({
318319
const variablesToSave = formik.values.filter((variable) => variable.name && variable.name.trim() !== '');
319320
const savedValues = environment.variables || [];
320321

321-
const hasChanges = JSON.stringify(variablesToSave) !== JSON.stringify(savedValues);
322+
// Compare without UIDs since they can be different but the actual data is the same
323+
const hasChanges = JSON.stringify(variablesToSave.map(stripEnvVarUid)) !== JSON.stringify(savedValues.map(stripEnvVarUid));
322324
if (!hasChanges) {
323325
toast.error('No changes to save');
324326
return;
@@ -441,8 +443,8 @@ const EnvironmentVariablesTable = ({
441443
</tr>
442444
)}
443445
fixedItemHeight={35}
444-
computeItemKey={(index, item) => item.variable.uid}
445-
itemContent={(index, { variable, index: actualIndex }) => {
446+
computeItemKey={(virtualIndex, item) => `${environment.uid}-${item.index}`}
447+
itemContent={(virtualIndex, { variable, index: actualIndex }) => {
446448
const isLastRow = actualIndex === formik.values.length - 1;
447449
const isEmptyRow = !variable.name || variable.name.trim() === '';
448450
const isLastEmptyRow = isLastRow && isEmptyRow;

packages/bruno-app/src/components/Preferences/General/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ const General = () => {
4747
.test('isNumber', 'Save Delay must be a number', (value) => {
4848
return value === undefined || !isNaN(value);
4949
})
50-
.test('isValidInterval', 'Save Delay must be at least 100ms', (value) => {
51-
return value === undefined || Number(value) >= 100;
50+
.test('isValidInterval', 'Save Delay must be at least 500ms', (value) => {
51+
return value === undefined || Number(value) >= 500;
5252
})
5353
}).test('intervalRequired', 'Save Delay is required when Auto Save is enabled', (value) => {
5454
// If autosave is enabled, interval must be provided

packages/bruno-app/src/utils/environments.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,12 @@ export const buildEnvVariable = ({ envVariable: obj, withUuid = false }) => {
5050
...envVariable
5151
};
5252
};
53+
54+
/**
55+
* Strips the UID from an environment variable for comparison purposes.
56+
* This is useful when comparing variables where UIDs may differ but the actual data is the same.
57+
*/
58+
export const stripEnvVarUid = (variable) => {
59+
const { name, value, type, enabled, secret } = variable;
60+
return { name, value, type, enabled, secret };
61+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { test, expect } from '../../../playwright';
2+
import { createCollection, createEnvironment, closeAllCollections } from '../../utils/page';
3+
4+
test.describe('Environment Variables Focus Retention', () => {
5+
test.afterEach(async ({ page }) => {
6+
if (!page.isClosed()) {
7+
await closeAllCollections(page);
8+
}
9+
});
10+
11+
test('should keep focus on name input after save hotkey', async ({ page, createTmpDir }) => {
12+
await createCollection(page, 'env-focus', await createTmpDir('env-focus'));
13+
await createEnvironment(page, 'Focus Env', 'collection');
14+
15+
const nameInput = page.locator('input[name="0.name"]');
16+
await nameInput.waitFor({ state: 'visible' });
17+
await nameInput.click();
18+
await page.keyboard.type('apiKey');
19+
await expect(nameInput).toBeFocused();
20+
21+
await page.keyboard.press('Control+s');
22+
await expect(page.getByText('Changes saved successfully').last()).toBeVisible({ timeout: 5000 });
23+
24+
// intentionally wait a few seconds because the focus is lost after a while
25+
await page.waitForTimeout(1000);
26+
await expect(nameInput).toBeFocused();
27+
});
28+
});

0 commit comments

Comments
 (0)