mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
fix: Show active global environment in config modal (#5698)
* fix: Show active global environment in config modal * add: delayShow prop in tooltip
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { IconPlus, IconDownload, IconSettings } from '@tabler/icons';
|
||||
import ToolHint from 'components/ToolHint';
|
||||
|
||||
const EnvironmentListContent = ({
|
||||
environments,
|
||||
@@ -18,17 +19,29 @@ const EnvironmentListContent = ({
|
||||
<div className="dropdown-item no-environment" onClick={() => onEnvironmentSelect(null)}>
|
||||
<span>No Environment</span>
|
||||
</div>
|
||||
<div>
|
||||
{environments.map((env) => (
|
||||
<div
|
||||
key={env.uid}
|
||||
className={`dropdown-item ${env.uid === activeEnvironmentUid ? 'active' : ''}`}
|
||||
onClick={() => onEnvironmentSelect(env)}
|
||||
>
|
||||
<span className="max-w-32 truncate no-wrap">{env.name}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<ToolHint
|
||||
anchorSelect="[data-tooltip-content]"
|
||||
place="right"
|
||||
positionStrategy="fixed"
|
||||
tooltipStyle={{
|
||||
maxWidth: '200px',
|
||||
wordWrap: 'break-word'
|
||||
}}
|
||||
delayShow={1000}
|
||||
>
|
||||
<div>
|
||||
{environments.map((env) => (
|
||||
<div
|
||||
key={env.uid}
|
||||
className={`dropdown-item ${env.uid === activeEnvironmentUid ? 'active' : ''}`}
|
||||
onClick={() => onEnvironmentSelect(env)}
|
||||
data-tooltip-content={env.name}
|
||||
>
|
||||
<span className="max-w-32 truncate no-wrap">{env.name}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ToolHint>
|
||||
<div className="dropdown-item configure-button">
|
||||
<button onClick={onSettingsClick} id="configure-env">
|
||||
<IconSettings size={16} strokeWidth={1.5} />
|
||||
|
||||
@@ -14,6 +14,7 @@ import CreateEnvironment from '../EnvironmentSettings/CreateEnvironment';
|
||||
import ImportEnvironment from '../EnvironmentSettings/ImportEnvironment';
|
||||
import CreateGlobalEnvironment from 'components/GlobalEnvironments/EnvironmentSettings/CreateEnvironment';
|
||||
import ImportGlobalEnvironment from 'components/GlobalEnvironments/EnvironmentSettings/ImportEnvironment';
|
||||
import ToolHint from 'components/ToolHint';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const EnvironmentSelector = ({ collection }) => {
|
||||
@@ -123,7 +124,14 @@ const EnvironmentSelector = ({ collection }) => {
|
||||
<>
|
||||
<div className="flex items-center">
|
||||
<IconDatabase size={14} strokeWidth={1.5} className="env-icon" />
|
||||
<span className="env-text max-w-24 truncate no-wrap">{activeCollectionEnvironment.name}</span>
|
||||
<ToolHint
|
||||
text={activeCollectionEnvironment.name}
|
||||
toolhintId={`collection-env-${activeCollectionEnvironment.uid}`}
|
||||
place="bottom-start"
|
||||
delayShow={1000}
|
||||
>
|
||||
<span className="env-text max-w-24 truncate overflow-hidden inline-block">{activeCollectionEnvironment.name}</span>
|
||||
</ToolHint>
|
||||
</div>
|
||||
{activeGlobalEnvironment && <span className="env-separator">|</span>}
|
||||
</>
|
||||
@@ -131,7 +139,14 @@ const EnvironmentSelector = ({ collection }) => {
|
||||
{activeGlobalEnvironment && (
|
||||
<div className="flex items-center">
|
||||
<IconWorld size={14} strokeWidth={1.5} className="env-icon" />
|
||||
<span className="env-text max-w-24 truncate no-wrap">{activeGlobalEnvironment.name}</span>
|
||||
<ToolHint
|
||||
text={activeGlobalEnvironment.name}
|
||||
toolhintId={`global-env-${activeGlobalEnvironment.uid}`}
|
||||
place="bottom-start"
|
||||
delayShow={1000}
|
||||
>
|
||||
<span className="env-text max-w-24 truncate overflow-hidden inline-block">{activeGlobalEnvironment.name}</span>
|
||||
</ToolHint>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
@@ -193,7 +208,12 @@ const EnvironmentSelector = ({ collection }) => {
|
||||
|
||||
{/* Modals - Rendered outside dropdown to avoid conflicts */}
|
||||
{showGlobalSettings && (
|
||||
<GlobalEnvironmentSettings globalEnvironments={globalEnvironments} collection={collection} onClose={handleCloseSettings} />
|
||||
<GlobalEnvironmentSettings
|
||||
globalEnvironments={globalEnvironments}
|
||||
collection={collection}
|
||||
activeGlobalEnvironmentUid={activeGlobalEnvironmentUid}
|
||||
onClose={handleCloseSettings}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showCollectionSettings && <EnvironmentSettings collection={collection} onClose={handleCloseSettings} />}
|
||||
|
||||
@@ -39,7 +39,7 @@ const DefaultTab = ({ setTab }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const EnvironmentSettings = ({ globalEnvironments, collection, onClose }) => {
|
||||
const EnvironmentSettings = ({ globalEnvironments, collection, activeGlobalEnvironmentUid, onClose }) => {
|
||||
const [isModified, setIsModified] = useState(false);
|
||||
const environments = globalEnvironments;
|
||||
const [selectedEnvironment, setSelectedEnvironment] = useState(null);
|
||||
@@ -64,6 +64,7 @@ const EnvironmentSettings = ({ globalEnvironments, collection, onClose }) => {
|
||||
<Modal size="lg" title="Global Environments" handleCancel={onClose} hideFooter={true}>
|
||||
<EnvironmentList
|
||||
environments={globalEnvironments}
|
||||
activeEnvironmentUid={activeGlobalEnvironmentUid}
|
||||
selectedEnvironment={selectedEnvironment}
|
||||
setSelectedEnvironment={setSelectedEnvironment}
|
||||
isModified={isModified}
|
||||
|
||||
@@ -6,12 +6,15 @@ import { useTheme } from 'providers/Theme';
|
||||
const ToolHint = ({
|
||||
text,
|
||||
toolhintId,
|
||||
anchorSelect,
|
||||
children,
|
||||
tooltipStyle = {},
|
||||
place = 'top',
|
||||
offset,
|
||||
positionStrategy,
|
||||
theme = null,
|
||||
className = ''
|
||||
className = '',
|
||||
delayShow = 200
|
||||
}) => {
|
||||
const { theme: contextTheme } = useTheme();
|
||||
const appliedTheme = theme || contextTheme;
|
||||
@@ -28,17 +31,25 @@ const ToolHint = ({
|
||||
color: toolhintTextColor
|
||||
};
|
||||
|
||||
const toolhintProps_final = anchorSelect
|
||||
? { anchorSelect }
|
||||
: { anchorId: toolhintId };
|
||||
|
||||
return (
|
||||
<>
|
||||
<span id={toolhintId} className={className}>{children}</span>
|
||||
{!anchorSelect && <span id={toolhintId} className={className}>{children}</span>}
|
||||
{anchorSelect && children}
|
||||
|
||||
<StyledWrapper theme={appliedTheme}>
|
||||
<ReactToolHint
|
||||
anchorId={toolhintId}
|
||||
content={text}
|
||||
{...toolhintProps_final}
|
||||
content={anchorSelect ? undefined : text}
|
||||
className="toolhint"
|
||||
offset={offset}
|
||||
place={place}
|
||||
positionStrategy={positionStrategy}
|
||||
noArrow={true}
|
||||
delayShow={delayShow}
|
||||
style={combinedToolhintStyle}
|
||||
/>
|
||||
</StyledWrapper>
|
||||
|
||||
@@ -2320,6 +2320,14 @@ export const collectionsSlice = createSlice({
|
||||
collection.lastAction = null;
|
||||
if (lastAction.payload === environment.name) {
|
||||
collection.activeEnvironmentUid = environment.uid;
|
||||
// Persist the selection to the UI state snapshot
|
||||
const { ipcRenderer } = window;
|
||||
if (ipcRenderer) {
|
||||
ipcRenderer.invoke('renderer:update-ui-state-snapshot', {
|
||||
type: 'COLLECTION_ENVIRONMENT',
|
||||
data: { collectionPath: collection?.pathname, environmentName: environment.name }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ export const addGlobalEnvironment = ({ name, variables = [] }) => (dispatch, get
|
||||
ipcRenderer
|
||||
.invoke('renderer:create-global-environment', { name, uid, variables })
|
||||
.then(() => dispatch(_addGlobalEnvironment({ name, uid, variables })))
|
||||
.then(() => dispatch(_selectGlobalEnvironment({ environmentUid: uid })))
|
||||
.then(() => dispatch(selectGlobalEnvironment({ environmentUid: uid })))
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import { closeAllCollections } from '../../utils/page';
|
||||
|
||||
test.describe('Collection Environment Configuration Selection Tests', () => {
|
||||
test.afterEach(async ({ pageWithUserData: page }) => {
|
||||
// cleanup: close all collections
|
||||
await closeAllCollections(page);
|
||||
});
|
||||
|
||||
test('should open collection environment config with currently active environment selected', async ({
|
||||
pageWithUserData: page
|
||||
}) => {
|
||||
// Open the collection from sidebar
|
||||
await page.locator('#sidebar-collection-name').filter({ hasText: 'collection-env-config-selection' }).click();
|
||||
|
||||
// First, select an environment (prod - development)
|
||||
await page.getByTestId('environment-selector-trigger').click();
|
||||
await page.getByTestId('env-tab-collection').click();
|
||||
|
||||
// Select prod (development environment)
|
||||
await page.locator('.dropdown-item').filter({ hasText: 'prod' }).click();
|
||||
|
||||
// Verify environment was selected
|
||||
await expect(page.locator('.current-environment')).toContainText('prod');
|
||||
|
||||
// Now open the dropdown again and go to configuration
|
||||
await page.getByTestId('environment-selector-trigger').click();
|
||||
await page.getByTestId('env-tab-collection').click();
|
||||
await page.getByText('Configure', { exact: true }).click();
|
||||
|
||||
// Verify the config modal opens with the currently active environment selected
|
||||
const collectionEnvModal = page.locator('.bruno-modal').filter({ hasText: 'Environments' });
|
||||
await expect(collectionEnvModal).toBeVisible();
|
||||
|
||||
// Check that the active environment in the config matches prod
|
||||
const activeEnvItem = collectionEnvModal.locator('.environment-item.active');
|
||||
await expect(activeEnvItem).toContainText('prod');
|
||||
|
||||
// Close the collection environment config modal
|
||||
await page.getByText('×').click();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"version": "1",
|
||||
"name": "collection-env-config-selection",
|
||||
"type": "collection"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
vars {
|
||||
baseUrl: /api/v2
|
||||
name: staging
|
||||
host: staging.example.com
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
vars {
|
||||
baseUrl: /api/v1
|
||||
name: development
|
||||
host: localhost:3000
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
meta {
|
||||
name: test-request
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{baseUrl}}/echo
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
tests {
|
||||
test("should get 200 response", function() {
|
||||
expect(res.getStatus()).to.equal(200);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"collections": [
|
||||
{
|
||||
"path": "{{projectRoot}}/tests/environments/collection-env-config-selection/collection",
|
||||
"securityConfig": {
|
||||
"jsSandboxMode": "safe"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"maximized": true,
|
||||
"lastOpenedCollections": [
|
||||
"{{projectRoot}}/tests/environments/collection-env-config-selection/collection"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"version": "1",
|
||||
"name": "global-env-config-selection",
|
||||
"type": "collection"
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
meta {
|
||||
name: test-request
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/api/echo
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
tests {
|
||||
test("should get 200 response", function() {
|
||||
expect(res.getStatus()).to.equal(200);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { test, expect } from '../../../playwright';
|
||||
import { closeAllCollections } from '../../utils/page';
|
||||
|
||||
test.describe('Global Environment Configuration Selection Tests', () => {
|
||||
test.afterEach(async ({ pageWithUserData: page }) => {
|
||||
// cleanup: close all collections
|
||||
await closeAllCollections(page);
|
||||
});
|
||||
|
||||
test('should open global environment config with currently active environment selected', async ({
|
||||
pageWithUserData: page
|
||||
}) => {
|
||||
// Open the collection from sidebar
|
||||
await page.locator('#sidebar-collection-name').filter({ hasText: 'global-env-config-selection' }).click();
|
||||
|
||||
// Get the currently active environment name
|
||||
const currentEnvName = await page.locator('.current-environment').textContent() as string;
|
||||
|
||||
// Open global environment configuration
|
||||
await page.getByTestId('environment-selector-trigger').click();
|
||||
await page.getByTestId('env-tab-global').click();
|
||||
await page.getByText('Configure', { exact: true }).click();
|
||||
|
||||
// Verify the config modal opens with the currently active environment selected
|
||||
const globalEnvModal = page.locator('.bruno-modal').filter({ hasText: 'Global Environments' });
|
||||
await expect(globalEnvModal).toBeVisible();
|
||||
|
||||
// Check that the active environment in the config matches the current environment
|
||||
const activeEnvItem = globalEnvModal.locator('.environment-item.active');
|
||||
await expect(activeEnvItem).toContainText(currentEnvName);
|
||||
|
||||
// Close the global environment config modal and go to welcome page
|
||||
await page.getByText('×').click();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"collections": [
|
||||
{
|
||||
"path": "{{projectRoot}}/tests/environments/global-env-config-selection/collection",
|
||||
"securityConfig": {
|
||||
"jsSandboxMode": "safe"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"environments": [
|
||||
{
|
||||
"uid": "FlaexlO7lcH7UtEpWsVyz",
|
||||
"name": "Development Environment",
|
||||
"variables": [
|
||||
{
|
||||
"uid": "dev-var-1",
|
||||
"name": "env_type",
|
||||
"value": "development",
|
||||
"type": "text",
|
||||
"secret": false,
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uid": "MsHcnAIonZ3455OfvpTUT",
|
||||
"name": "Production Environment",
|
||||
"variables": [
|
||||
{
|
||||
"uid": "prod-var-1",
|
||||
"name": "env_type",
|
||||
"value": "production",
|
||||
"type": "text",
|
||||
"secret": false,
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"uid": "VdUAdMPcfapMCqjKAeUiI",
|
||||
"name": "Staging Environment",
|
||||
"variables": [
|
||||
{
|
||||
"uid": "staging-var-1",
|
||||
"name": "env_type",
|
||||
"value": "staging",
|
||||
"type": "text",
|
||||
"secret": false,
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"activeGlobalEnvironmentUid": "MsHcnAIonZ3455OfvpTUT"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"maximized": true,
|
||||
"lastOpenedCollections": [
|
||||
"{{projectRoot}}/tests/environments/global-env-config-selection/collection"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user