mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-21 15:33:11 +01:00
feat: updates
This commit is contained in:
parent
5afafb5944
commit
8ab8af6b3f
@ -53,6 +53,7 @@ const EnvironmentSelector = ({ collection }) => {
|
||||
<StyledWrapper>
|
||||
<div className="flex items-center cursor-pointer environment-selector">
|
||||
<Dropdown onCreate={onDropdownCreate} icon={<Icon />} placement="bottom-end">
|
||||
<div className="label-item font-medium">Collection Environments</div>
|
||||
{environments && environments.length
|
||||
? environments.map((e) => (
|
||||
<div
|
||||
|
@ -6,7 +6,7 @@ import EnvironmentSettings from '../EnvironmentSettings';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { selectGlobalEnvironment } from 'providers/ReduxStore/slices/globalEnvironments';
|
||||
import { selectGlobalEnvironment } from 'providers/ReduxStore/slices/global-environments';
|
||||
|
||||
const EnvironmentSelector = () => {
|
||||
const dispatch = useDispatch();
|
||||
@ -53,6 +53,7 @@ const EnvironmentSelector = () => {
|
||||
<StyledWrapper>
|
||||
<div className="flex items-center cursor-pointer environment-selector mr-3">
|
||||
<Dropdown onCreate={onDropdownCreate} icon={<Icon />} placement="bottom-end" transparent={true}>
|
||||
<div className="label-item font-medium">Global Environments</div>
|
||||
{globalEnvironments && globalEnvironments.length
|
||||
? globalEnvironments.map((e) => (
|
||||
<div
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Modal from 'components/Modal/index';
|
||||
import Portal from 'components/Portal/index';
|
||||
import { useFormik } from 'formik';
|
||||
import { copyGlobalEnvironment } from 'providers/ReduxStore/slices/globalEnvironments';
|
||||
import { copyGlobalEnvironment } from 'providers/ReduxStore/slices/global-environments';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
@ -5,7 +5,7 @@ import * as Yup from 'yup';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import Portal from 'components/Portal';
|
||||
import Modal from 'components/Modal';
|
||||
import { addGlobalEnvironment } from 'providers/ReduxStore/slices/globalEnvironments';
|
||||
import { addGlobalEnvironment } from 'providers/ReduxStore/slices/global-environments';
|
||||
|
||||
const CreateEnvironment = ({ onClose }) => {
|
||||
const dispatch = useDispatch();
|
||||
|
@ -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'));
|
||||
|
@ -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();
|
||||
|
@ -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 (
|
||||
<StyledWrapper>
|
||||
{openCreateModal && <CreateEnvironment onClose={() => setOpenCreateModal(false)} />}
|
||||
{openImportModal && <ImportEnvironment onClose={() => setOpenImportModal(false)} />}
|
||||
{openManageSecretsModal && <ManageSecrets onClose={() => setOpenManageSecretsModal(false)} />}
|
||||
|
||||
<div className="flex">
|
||||
|
@ -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 (
|
||||
<Portal>
|
||||
<Modal size="sm" title="Import Global Environment" hideFooter={true} handleConfirm={onClose} handleCancel={onClose}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleImportPostmanEnvironment}
|
||||
className="flex justify-center flex-col items-center w-full dark:bg-zinc-700 rounded-lg border-2 border-dashed border-zinc-300 dark:border-zinc-400 p-12 text-center hover:border-zinc-400 focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-2"
|
||||
>
|
||||
<IconDatabaseImport size={64} />
|
||||
<span className="mt-2 block text-sm font-semibold">Import your Postman environments</span>
|
||||
</button>
|
||||
</Modal>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImportEnvironment;
|
@ -1,31 +0,0 @@
|
||||
import React from 'react';
|
||||
import Portal from 'components/Portal';
|
||||
import Modal from 'components/Modal';
|
||||
|
||||
const ManageSecrets = ({ onClose }) => {
|
||||
return (
|
||||
<Portal>
|
||||
<Modal size="sm" title="Manage Secrets" hideFooter={true} handleConfirm={onClose} handleCancel={onClose}>
|
||||
<div>
|
||||
<p>In any collection, there are secrets that need to be managed.</p>
|
||||
<p className="mt-2">These secrets can be anything such as API keys, passwords, or tokens.</p>
|
||||
<p className="mt-4">Bruno offers two approaches to manage secrets in collections.</p>
|
||||
<p className="mt-2">
|
||||
Read more about it in our{' '}
|
||||
<a
|
||||
href="https://docs.usebruno.com/secrets-management/overview"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-link hover:underline"
|
||||
>
|
||||
docs
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</Modal>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ManageSecrets;
|
@ -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();
|
||||
|
@ -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 }) => {
|
||||
<SharedButton onClick={() => setTab('create')}>
|
||||
<span>Create Global Environment</span>
|
||||
</SharedButton>
|
||||
|
||||
<span className="mx-4">Or</span>
|
||||
|
||||
<SharedButton onClick={() => setTab('import')}>
|
||||
<span>Import Environment</span>
|
||||
</SharedButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@ -40,9 +47,11 @@ const EnvironmentSettings = ({ globalEnvironments, activeGlobalEnvironmentUid, o
|
||||
if (!environments || !environments.length) {
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<Modal size="md" title="Environments" handleCancel={onClose} hideCancel={true} hideFooter={true}>
|
||||
<Modal size="md" title="Global Environments" handleCancel={onClose} hideCancel={true} hideFooter={true}>
|
||||
{tab === 'create' ? (
|
||||
<CreateEnvironment onClose={() => setTab('default')} />
|
||||
) : tab === 'import' ? (
|
||||
<ImportEnvironment onClose={() => setTab('default')} />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
@ -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();
|
||||
|
@ -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 = () => {
|
||||
|
@ -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);
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user