From 3cc2e3d4fa662427f373cfde7740d61ca3c9fb82 Mon Sep 17 00:00:00 2001 From: Easwaran Prem K Date: Sat, 14 Oct 2023 12:29:51 +0530 Subject: [PATCH] Feature: Support Import postman environment - Fixes issue #193 --- .../EnvironmentList/index.js | 2 + .../ImportEnvironment/index.js | 33 +++++++++ .../Environments/EnvironmentSettings/index.js | 2 + .../ReduxStore/slices/collections/actions.js | 26 +++++++ .../utils/importers/postman-environment.js | 71 +++++++++++++++++++ packages/bruno-electron/src/ipc/collection.js | 22 ++++++ 6 files changed, 156 insertions(+) create mode 100644 packages/bruno-app/src/components/Environments/EnvironmentSettings/ImportEnvironment/index.js create mode 100644 packages/bruno-app/src/utils/importers/postman-environment.js diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js index b80cd92a5..e310eb0c1 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js @@ -4,6 +4,7 @@ import usePrevious from 'hooks/usePrevious'; import EnvironmentDetails from './EnvironmentDetails'; import CreateEnvironment from '../CreateEnvironment/index'; import StyledWrapper from './StyledWrapper'; +import ImportEnvironment from "components/Environments/EnvironmentSettings/ImportEnvironment"; const EnvironmentList = ({ collection }) => { const { environments } = collection; @@ -65,6 +66,7 @@ const EnvironmentList = ({ collection }) => {
setOpenCreateModal(true)}> + Create
+ diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/ImportEnvironment/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/ImportEnvironment/index.js new file mode 100644 index 000000000..1b0fd9dd9 --- /dev/null +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/ImportEnvironment/index.js @@ -0,0 +1,33 @@ +import toast from "react-hot-toast"; +import {toastError} from "utils/common/error"; +import {useDispatch} from "react-redux"; +import {importEnvironment} from "providers/ReduxStore/slices/collections/actions"; +import importPostmanEnvironment from "utils/importers/postman-environment"; +import React from "react"; + +const ImportEnvironment = ({title, collectionUid}) => { + const dispatch = useDispatch(); + + const handleImportPostmanEnvironment = () => { + importPostmanEnvironment() + .then((environment) => { + dispatch(importEnvironment(environment.name, environment.variables, collectionUid)) + .then(() => { + toast.success('Environment imported successfully'); + }) + .catch(() => toast.error('An error occurred while importing the environment')); + }) + .catch((err) => toastError(err, 'Postman Import environment failed')); + }; + + return( + + ); +}; + +export default ImportEnvironment; \ No newline at end of file diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js index 855e0fb31..39c410eed 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js @@ -3,6 +3,7 @@ import React, { useState } from 'react'; import CreateEnvironment from './CreateEnvironment'; import EnvironmentList from './EnvironmentList'; import StyledWrapper from './StyledWrapper'; +import ImportEnvironment from "components/Environments/EnvironmentSettings/ImportEnvironment"; const EnvironmentSettings = ({ collection, onClose }) => { const { environments } = collection; @@ -28,6 +29,7 @@ const EnvironmentSettings = ({ collection, onClose }) => { > + Create Environment + diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js index 80c823454..1b36ed65a 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -722,6 +722,32 @@ export const addEnvironment = (name, collectionUid) => (dispatch, getState) => { }); }; +export const importEnvironment = (name, variables, collectionUid) => (dispatch, getState) => { + return new Promise((resolve, reject) => { + const state = getState(); + const collection = findCollectionByUid(state.collections.collections, collectionUid); + if (!collection) { + return reject(new Error('Collection not found')); + } + + ipcRenderer + .invoke('renderer:import-environment', collection.pathname, name, variables) + .then( + dispatch( + updateLastAction({ + collectionUid, + lastAction: { + type: 'ADD_ENVIRONMENT', + payload: name + } + }) + ) + ) + .then(resolve) + .catch(reject); + }); +}; + export const copyEnvironment = (name, baseEnvUid, collectionUid) => (dispatch, getState) => { return new Promise((resolve, reject) => { const state = getState(); diff --git a/packages/bruno-app/src/utils/importers/postman-environment.js b/packages/bruno-app/src/utils/importers/postman-environment.js new file mode 100644 index 000000000..61c62311c --- /dev/null +++ b/packages/bruno-app/src/utils/importers/postman-environment.js @@ -0,0 +1,71 @@ +import each from 'lodash/each'; +import fileDialog from 'file-dialog'; +import { BrunoError } from 'utils/common/error'; + +const readFile = (files) => { + return new Promise((resolve, reject) => { + const fileReader = new FileReader(); + fileReader.onload = (e) => resolve(e.target.result); + fileReader.onerror = (err) => reject(err); + fileReader.readAsText(files[0]); + }); +}; + +const isSecret = (type) => { + return type === 'secret'; +}; + +const importPostmanEnvironmentVariables = (brunoEnvironment, values) => { + brunoEnvironment.variables = brunoEnvironment.variables || []; + + each(values, (i) => { + const brunoEnvironmentVariable = { + name: i.key, + value: i.value, + enabled: i.enabled, + secret: isSecret(i.type) + }; + + brunoEnvironment.variables.push(brunoEnvironmentVariable); + }); +}; + +const importPostmanEnvironment = (environment) => { + const brunoEnvironment = { + name: environment.name, + variables: [] + }; + + importPostmanEnvironmentVariables(brunoEnvironment, environment.values); + return brunoEnvironment; +}; + +const parsePostmanEnvironment = (str) => { + return new Promise((resolve, reject) => { + try { + let environment = JSON.parse(str); + return resolve(importPostmanEnvironment(environment)); + } catch (err) { + console.log(err); + if (err instanceof BrunoError) { + return reject(err); + } + return reject(new BrunoError('Unable to parse the postman environment json file')); + } + }); +}; + +const importEnvironment = () => { + return new Promise((resolve, reject) => { + fileDialog({ accept: 'application/json' }) + .then(readFile) + .then(parsePostmanEnvironment) + .then((environment) => resolve(environment)) + .catch((err) => { + console.log(err); + reject(new BrunoError('Import Environment failed')); + }); + }); +}; + +export default importEnvironment; diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js index 944a04f01..b5d4f0541 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -184,6 +184,28 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection } }); + // copy environment + ipcMain.handle('renderer:import-environment', async (event, collectionPathname, name, variables) => { + try { + const envDirPath = path.join(collectionPathname, 'environments'); + if (!fs.existsSync(envDirPath)) { + await createDirectory(envDirPath); + } + + const envFilePath = path.join(envDirPath, `${name}.bru`); + if (fs.existsSync(envFilePath)) { + throw new Error(`environment: ${envFilePath} already exists`); + } + + const content = envJsonToBru({ + variables: variables + }); + await writeFile(envFilePath, content); + } catch (error) { + return Promise.reject(error); + } + }); + // save environment ipcMain.handle('renderer:save-environment', async (event, collectionPathname, environment) => { try {