diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js index e339bfa1a..8bfbb075e 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js @@ -53,6 +53,7 @@ const EnvironmentSelector = ({ collection }) => {
} placement="bottom-end"> +
Collection Environments
{environments && environments.length ? environments.map((e) => (
{ const dispatch = useDispatch(); @@ -53,6 +53,7 @@ const EnvironmentSelector = () => {
} placement="bottom-end" transparent={true}> +
Global Environments
{globalEnvironments && globalEnvironments.length ? globalEnvironments.map((e) => (
{ const dispatch = useDispatch(); diff --git a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/DeleteEnvironment/index.js b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/DeleteEnvironment/index.js index e4ddb73f8..2edab3be8 100644 --- a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/DeleteEnvironment/index.js +++ b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/DeleteEnvironment/index.js @@ -4,14 +4,14 @@ import toast from 'react-hot-toast'; import Modal from 'components/Modal/index'; import { useDispatch } from 'react-redux'; import StyledWrapper from './StyledWrapper'; -import { deleteGlobalEnvironment } from 'providers/ReduxStore/slices/globalEnvironments'; +import { deleteGlobalEnvironment } from 'providers/ReduxStore/slices/global-environments'; const DeleteEnvironment = ({ onClose, environment }) => { const dispatch = useDispatch(); const onConfirm = () => { dispatch(deleteGlobalEnvironment({ environmentUid: environment.uid })) .then(() => { - toast.success('Environment deleted successfully'); + toast.success('Global Environment deleted successfully'); onClose(); }) .catch(() => toast.error('An error occurred while deleting the environment')); diff --git a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js index efd2fbed1..c33233bc8 100644 --- a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js +++ b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js @@ -10,7 +10,7 @@ import { useFormik } from 'formik'; import * as Yup from 'yup'; import { variableNameRegex } from 'utils/common/regex'; import toast from 'react-hot-toast'; -import { saveGlobalEnvironment } from 'providers/ReduxStore/slices/globalEnvironments'; +import { saveGlobalEnvironment } from 'providers/ReduxStore/slices/global-environments'; const EnvironmentVariables = ({ environment, setIsModified, originalEnvironmentVariables }) => { const dispatch = useDispatch(); diff --git a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/index.js b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/index.js index 130b7e6d8..6516ba833 100644 --- a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/index.js +++ b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/index.js @@ -3,9 +3,10 @@ import usePrevious from 'hooks/usePrevious'; import EnvironmentDetails from './EnvironmentDetails'; import CreateEnvironment from '../CreateEnvironment'; import { IconDownload, IconShieldLock } from '@tabler/icons'; -import ManageSecrets from '../ManageSecrets'; import StyledWrapper from './StyledWrapper'; import ConfirmSwitchEnv from './ConfirmSwitchEnv'; +import ManageSecrets from 'components/Environments/EnvironmentSettings/ManageSecrets/index'; +import ImportEnvironment from '../ImportEnvironment'; const EnvironmentList = ({ environments, activeEnvironmentUid, selectedEnvironment, setSelectedEnvironment, isModified, setIsModified }) => { const [openCreateModal, setOpenCreateModal] = useState(false); @@ -86,6 +87,7 @@ const EnvironmentList = ({ environments, activeEnvironmentUid, selectedEnvironme return ( {openCreateModal && setOpenCreateModal(false)} />} + {openImportModal && setOpenImportModal(false)} />} {openManageSecretsModal && setOpenManageSecretsModal(false)} />}
diff --git a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/ImportEnvironment/index.js b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/ImportEnvironment/index.js new file mode 100644 index 000000000..99900f740 --- /dev/null +++ b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/ImportEnvironment/index.js @@ -0,0 +1,62 @@ +import React from 'react'; +import Portal from 'components/Portal'; +import Modal from 'components/Modal'; +import toast from 'react-hot-toast'; +import { useDispatch } from 'react-redux'; +import importPostmanEnvironment from 'utils/importers/postman-environment'; +import { toastError } from 'utils/common/error'; +import { IconDatabaseImport } from '@tabler/icons'; +import { addGlobalEnvironment } from 'providers/ReduxStore/slices/global-environments'; +import { uuid } from 'utils/common/index'; + +const ImportEnvironment = ({ onClose }) => { + const dispatch = useDispatch(); + + const handleImportPostmanEnvironment = () => { + importPostmanEnvironment() + .then((environments) => { + environments + .filter((env) => + env.name && env.name !== 'undefined' + ? true + : () => { + toast.error('Failed to import environment: env has no name'); + return false; + } + ) + .map((environment) => { + let variables = environment?.variables?.map(v => ({ + ...v, + uid: uuid(), + type: 'text' + })); + dispatch(addGlobalEnvironment({ name: environment.name, variables })) + .then(() => { + toast.success('Global Environment imported successfully'); + }) + .catch(() => toast.error('An error occurred while importing the environment')); + }); + }) + .then(() => { + onClose(); + }) + .catch((err) => toastError(err, 'Postman Import environment failed')); + }; + + return ( + + + + + + ); +}; + +export default ImportEnvironment; diff --git a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/ManageSecrets/index.js b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/ManageSecrets/index.js deleted file mode 100644 index ca025003c..000000000 --- a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/ManageSecrets/index.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import Portal from 'components/Portal'; -import Modal from 'components/Modal'; - -const ManageSecrets = ({ onClose }) => { - return ( - - -
-

In any collection, there are secrets that need to be managed.

-

These secrets can be anything such as API keys, passwords, or tokens.

-

Bruno offers two approaches to manage secrets in collections.

-

- Read more about it in our{' '} - - docs - - . -

-
-
-
- ); -}; - -export default ManageSecrets; diff --git a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/RenameEnvironment/index.js b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/RenameEnvironment/index.js index 66bebe0f2..ff1809383 100644 --- a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/RenameEnvironment/index.js +++ b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/RenameEnvironment/index.js @@ -6,7 +6,7 @@ import { useFormik } from 'formik'; import { renameEnvironment } from 'providers/ReduxStore/slices/collections/actions'; import * as Yup from 'yup'; import { useDispatch } from 'react-redux'; -import { renameGlobalEnvironment } from 'providers/ReduxStore/slices/globalEnvironments'; +import { renameGlobalEnvironment } from 'providers/ReduxStore/slices/global-environments'; const RenameEnvironment = ({ onClose, environment }) => { const dispatch = useDispatch(); diff --git a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/index.js b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/index.js index 1e3052120..c93285f56 100644 --- a/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/index.js +++ b/packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/index.js @@ -4,6 +4,7 @@ import CreateEnvironment from './CreateEnvironment'; import EnvironmentList from './EnvironmentList'; import StyledWrapper from './StyledWrapper'; import { IconFileAlert } from '@tabler/icons'; +import ImportEnvironment from './ImportEnvironment/index'; export const SharedButton = ({ children, className, onClick }) => { return ( @@ -27,6 +28,12 @@ const DefaultTab = ({ setTab }) => { setTab('create')}> Create Global Environment + + Or + + setTab('import')}> + Import Environment +
); @@ -40,9 +47,11 @@ const EnvironmentSettings = ({ globalEnvironments, activeGlobalEnvironmentUid, o if (!environments || !environments.length) { return ( - + {tab === 'create' ? ( setTab('default')} /> + ) : tab === 'import' ? ( + setTab('default')} /> ) : ( <> )} diff --git a/packages/bruno-app/src/providers/App/useIpcEvents.js b/packages/bruno-app/src/providers/App/useIpcEvents.js index 5600b0317..ba0670285 100644 --- a/packages/bruno-app/src/providers/App/useIpcEvents.js +++ b/packages/bruno-app/src/providers/App/useIpcEvents.js @@ -23,7 +23,7 @@ import { collectionAddEnvFileEvent, openCollectionEvent } from 'providers/ReduxS import toast from 'react-hot-toast'; import { useDispatch } from 'react-redux'; import { isElectron } from 'utils/common/platform'; -import { globalEnvironmentsUpdateEvent, updateGlobalEnvironments } from 'providers/ReduxStore/slices/globalEnvironments'; +import { globalEnvironmentsUpdateEvent, updateGlobalEnvironments } from 'providers/ReduxStore/slices/global-environments'; const useIpcEvents = () => { const dispatch = useDispatch(); diff --git a/packages/bruno-app/src/providers/ReduxStore/index.js b/packages/bruno-app/src/providers/ReduxStore/index.js index c7641b506..1af71f7bf 100644 --- a/packages/bruno-app/src/providers/ReduxStore/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/index.js @@ -6,7 +6,7 @@ import appReducer from './slices/app'; import collectionsReducer from './slices/collections'; import tabsReducer from './slices/tabs'; import notificationsReducer from './slices/notifications'; -import globalEnvironmentsReducer from './slices/globalEnvironments'; +import globalEnvironmentsReducer from './slices/global-environments'; const { publicRuntimeConfig } = getConfig(); const isDevEnv = () => { diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/globalEnvironments.js b/packages/bruno-app/src/providers/ReduxStore/slices/global-environments.js similarity index 93% rename from packages/bruno-app/src/providers/ReduxStore/slices/globalEnvironments.js rename to packages/bruno-app/src/providers/ReduxStore/slices/global-environments.js index 81f7fc949..10184c1e7 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/globalEnvironments.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/global-environments.js @@ -1,5 +1,5 @@ import { createSlice } from '@reduxjs/toolkit'; -import { generateUidBasedOnHash, stringifyIfNot, uuid } from 'utils/common/index'; +import { stringifyIfNot, uuid } from 'utils/common/index'; import { environmentSchema } from '@usebruno/schema'; import { cloneDeep } from 'lodash'; @@ -17,12 +17,12 @@ export const globalEnvironmentsSlice = createSlice({ state.activeGlobalEnvironmentUid = action.payload?.activeGlobalEnvironmentUid; }, _addGlobalEnvironment: (state, action) => { - const { name, uid } = action.payload; + const { name, uid, variables = [] } = action.payload; if (name?.length) { state.globalEnvironments.push({ uid, name, - variables: [] + variables }); } }, @@ -87,13 +87,13 @@ export const { _deleteGlobalEnvironment } = globalEnvironmentsSlice.actions; -export const addGlobalEnvironment = ({ name }) => (dispatch, getState) => { +export const addGlobalEnvironment = ({ name, variables = [] }) => (dispatch, getState) => { return new Promise((resolve, reject) => { - const uid = generateUidBasedOnHash(name); + const uid = uuid(); ipcRenderer - .invoke('renderer:create-global-environment', { name, uid }) + .invoke('renderer:create-global-environment', { name, uid, variables }) .then( - dispatch(_addGlobalEnvironment({ name, uid })) + dispatch(_addGlobalEnvironment({ name, uid, variables })) ) .then(resolve) .catch(reject); @@ -105,7 +105,7 @@ export const copyGlobalEnvironment = ({ name, environmentUid: baseEnvUid }) => ( const state = getState(); const globalEnvironments = state.globalEnvironments.globalEnvironments; const baseEnv = globalEnvironments?.find(env => env?.uid == baseEnvUid) - const uid = generateUidBasedOnHash(name); + const uid = uuid(); ipcRenderer .invoke('renderer:create-global-environment', { name, variables: baseEnv.variables }) .then(() => { @@ -195,7 +195,8 @@ export const globalEnvironmentsUpdateEvent = ({ globalEnvironmentVariables }) => const environment = globalEnvironments?.find(env => env?.uid == environmentUid); if (!environment || !environmentUid) { - return reject(new Error('Environment not found')); + console.error('Global Environment not found'); + return resolve(); } let variables = cloneDeep(environment?.variables); diff --git a/packages/bruno-electron/src/index.js b/packages/bruno-electron/src/index.js index 8910d2fe8..47ab8ae7c 100644 --- a/packages/bruno-electron/src/index.js +++ b/packages/bruno-electron/src/index.js @@ -23,7 +23,7 @@ const registerPreferencesIpc = require('./ipc/preferences'); const Watcher = require('./app/watcher'); const { loadWindowState, saveBounds, saveMaximized } = require('./utils/window'); const registerNotificationsIpc = require('./ipc/notifications'); -const registerGlobalEnvironmentsIpc = require('./ipc/globalEnvironments'); +const registerGlobalEnvironmentsIpc = require('./ipc/global-environments'); const lastOpenedCollections = new LastOpenedCollections(); diff --git a/packages/bruno-electron/src/ipc/globalEnvironments.js b/packages/bruno-electron/src/ipc/global-environments.js similarity index 86% rename from packages/bruno-electron/src/ipc/globalEnvironments.js rename to packages/bruno-electron/src/ipc/global-environments.js index e2edb0902..dc7258ee1 100644 --- a/packages/bruno-electron/src/ipc/globalEnvironments.js +++ b/packages/bruno-electron/src/ipc/global-environments.js @@ -6,9 +6,9 @@ const registerGlobalEnvironmentsIpc = (mainWindow) => { // GLOBAL ENVIRONMENTS - ipcMain.handle('renderer:create-global-environment', async (event, { uid, name }) => { + ipcMain.handle('renderer:create-global-environment', async (event, { uid, name, variables }) => { try { - globalEnvironmentsStore.addGlobalEnvironment({ uid, name }); + globalEnvironmentsStore.addGlobalEnvironment({ uid, name, variables }); } catch (error) { return Promise.reject(error); } @@ -30,9 +30,9 @@ const registerGlobalEnvironmentsIpc = (mainWindow) => { } }); - ipcMain.handle('renderer:delete-global-environment', async (event, { uid }) => { + ipcMain.handle('renderer:delete-global-environment', async (event, { environmentUid }) => { try { - globalEnvironmentsStore.deleteGlobalEnvironment({ uid }); + globalEnvironmentsStore.deleteGlobalEnvironment({ environmentUid }); } catch (error) { return Promise.reject(error); } diff --git a/packages/bruno-electron/src/ipc/preferences.js b/packages/bruno-electron/src/ipc/preferences.js index 4c9f5af25..4c9c34d99 100644 --- a/packages/bruno-electron/src/ipc/preferences.js +++ b/packages/bruno-electron/src/ipc/preferences.js @@ -17,7 +17,8 @@ const registerPreferencesIpc = (mainWindow, watcher, lastOpenedCollections) => { // load global environments const globalEnvironments = globalEnvironmentsStore.getGlobalEnvironments(); - const activeGlobalEnvironmentUid = globalEnvironmentsStore.getActiveGlobalEnvironmentUid(); + let activeGlobalEnvironmentUid = globalEnvironmentsStore.getActiveGlobalEnvironmentUid(); + activeGlobalEnvironmentUid = globalEnvironments?.find(env => env?.uid == activeGlobalEnvironmentUid) ? activeGlobalEnvironmentUid : null; mainWindow.webContents.send('main:load-global-environments', { globalEnvironments, activeGlobalEnvironmentUid }); // reload last opened collections diff --git a/packages/bruno-electron/src/store/global-environments.js b/packages/bruno-electron/src/store/global-environments.js index b747a8c52..7c0540d95 100644 --- a/packages/bruno-electron/src/store/global-environments.js +++ b/packages/bruno-electron/src/store/global-environments.js @@ -42,7 +42,6 @@ class GlobalEnvironmentsStore { }); } - getGlobalEnvironments() { let globalEnvironments = this.store.get('environments', []); globalEnvironments = this.decryptGlobalEnvironmentVariables({ globalEnvironments }); @@ -62,12 +61,12 @@ class GlobalEnvironmentsStore { return this.store.set('activeGlobalEnvironmentUid', uid); } - addGlobalEnvironment({ uid, name }) { + addGlobalEnvironment({ uid, name, variables = [] }) { let globalEnvironments = this.getGlobalEnvironments(); globalEnvironments.push({ uid, name, - variables: [] + variables }); this.setGlobalEnvironments(globalEnvironments); } @@ -115,9 +114,13 @@ class GlobalEnvironmentsStore { } } - deleteGlobalEnvironment({ uid }) { + deleteGlobalEnvironment({ environmentUid }) { let globalEnvironments = this.getGlobalEnvironments(); - globalEnvironments = globalEnvironments.filter(env => env?.uid !== uid); + let activeGlobalEnvironmentUid = this.getActiveGlobalEnvironmentUid(); + globalEnvironments = globalEnvironments.filter(env => env?.uid !== environmentUid); + if (environmentUid == activeGlobalEnvironmentUid) { + this.setActiveGlobalEnvironmentUid(null); + } this.setGlobalEnvironments(globalEnvironments); } }