From a9e6c3a35caf30961a7446e7aea1f2b9bfc54ea4 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Sun, 5 Mar 2023 00:19:03 +0530 Subject: [PATCH] feat: support for importing insomnia collections (#74) --- .../Sidebar/ImportCollection/index.js | 15 ++ .../utils/importers/insomnia-collection.js | 186 ++++++++++++++++++ 2 files changed, 201 insertions(+) create mode 100644 packages/bruno-app/src/utils/importers/insomnia-collection.js diff --git a/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js b/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js index 8fc8cb32de..4960719117 100644 --- a/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js +++ b/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js @@ -1,6 +1,7 @@ import React from 'react'; import importBrunoCollection from 'utils/importers/bruno-collection'; import importPostmanCollection from 'utils/importers/postman-collection'; +import importInsomniaCollection from 'utils/importers/insomnia-collection'; import { toastError } from 'utils/common/error'; import Modal from 'components/Modal'; @@ -21,6 +22,14 @@ const ImportCollection = ({ onClose, handleSubmit }) => { .catch((err) => toastError(err, 'Postman Import collection failed')); }; + const handleImportInsomniaCollection = () => { + importInsomniaCollection() + .then((collection) => { + handleSubmit(collection); + }) + .catch((err) => toastError(err, 'Insomnia Import collection failed')); + }; + return (
@@ -36,6 +45,12 @@ const ImportCollection = ({ onClose, handleSubmit }) => { > Postman Collection
+
+ Insomnia Collection +
); diff --git a/packages/bruno-app/src/utils/importers/insomnia-collection.js b/packages/bruno-app/src/utils/importers/insomnia-collection.js new file mode 100644 index 0000000000..56870f203e --- /dev/null +++ b/packages/bruno-app/src/utils/importers/insomnia-collection.js @@ -0,0 +1,186 @@ +import each from 'lodash/each'; +import get from 'lodash/get'; +import fileDialog from 'file-dialog'; +import { uuid } from 'utils/common'; +import { BrunoError } from 'utils/common/error'; +import { validateSchema, transformItemsInCollection, hydrateSeqInCollection } from './common'; + +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 parseGraphQL = (text) => { + try { + const graphql = JSON.parse(text); + + return { + query: graphql.query, + variables: JSON.stringify(graphql.variables, null, 2) + } + } catch (e) { + return { + query: '', + variables: {} + } + } +} + + +const transformInsomniaRequestItem = (request) => { + const brunoRequestItem = { + uid: uuid(), + name: request.name, + type: 'http-request', + request: { + url: request.url, + method: request.method, + headers: [], + params: [], + body: { + mode: 'none', + json: null, + text: null, + xml: null, + formUrlEncoded: [], + multipartForm: [] + } + } + }; + + each(request.headers, (header) => { + brunoRequestItem.request.headers.push({ + uid: uuid(), + name: header.name, + value: header.value, + description: header.description, + enabled: !header.disabled + }); + }); + + each(request.parameters, (param) => { + brunoRequestItem.request.params.push({ + uid: uuid(), + name: param.name, + value: param.value, + description: param.description, + enabled: !param.disabled + }); + }); + + const mimeType = get(request, 'body.mimeType', ''); + + if (mimeType === 'application/json') { + brunoRequestItem.request.body.mode = 'json'; + brunoRequestItem.request.body.json = request.body.text; + } else if (mimeType === 'application/x-www-form-urlencoded') { + brunoRequestItem.request.body.mode = 'formUrlEncoded'; + each(request.body.params, (param) => { + brunoRequestItem.request.body.formUrlEncoded.push({ + uid: uuid(), + name: param.name, + value: param.value, + description: param.description, + enabled: !param.disabled + }); + }); + } else if (mimeType === 'multipart/form-data') { + brunoRequestItem.request.body.mode = 'multipartForm'; + each(request.body.params, (param) => { + brunoRequestItem.request.body.multipartForm.push({ + uid: uuid(), + name: param.name, + value: param.value, + description: param.description, + enabled: !param.disabled + }); + }); + } else if (mimeType === 'text/plain') { + brunoRequestItem.request.body.mode = 'text'; + brunoRequestItem.request.body.text = request.body.text; + } else if (mimeType === 'text/xml') { + brunoRequestItem.request.body.mode = 'xml'; + brunoRequestItem.request.body.xml = request.body.text; + } else if (mimeType === 'application/graphql') { + brunoRequestItem.type = 'graphql-request'; + brunoRequestItem.request.body.mode = 'graphql'; + brunoRequestItem.request.body.graphql = parseGraphQL(request.body.text); + } + + + return brunoRequestItem; +}; + +const parseInsomniaCollection = (data) => { + const brunoCollection = { + name: '', + uid: uuid(), + version: "1", + items: [], + environments: [] + }; + + return new Promise((resolve, reject) => { + try { + const insomniaExport = JSON.parse(data); + const insomniaResources = get(insomniaExport, 'resources', []); + const insomniaCollection = insomniaResources.find(resource => resource._type === 'workspace' && resource.scope === 'collection'); + + if (!insomniaCollection) { + reject(new BrunoError('Collection not found inside Insomnia export')); + } + + brunoCollection.name = insomniaCollection.name; + + const requestsAndFolders = insomniaResources.filter( + (resource) => resource._type === 'request' || resource._type === 'request_group' + ) || []; + + function createFolderStructure(resources, parentId = null) { + const requestGroups = resources.filter((resource) => resource._type === 'request_group' && resource.parentId === parentId) || []; + const requests = resources.filter((resource) => resource._type === 'request' && resource.parentId === parentId); + + const folders = requestGroups.map((folder) => { + const requests = resources.filter((resource) => resource._type === 'request' && resource.parentId === folder._id); + + return { + uid: uuid(), + name: folder.name, + type: 'folder', + items: createFolderStructure(resources, folder._id).concat(requests.map(transformInsomniaRequestItem)), + } + }); + + return folders.concat(requests.map(transformInsomniaRequestItem)); + } + + brunoCollection.items = createFolderStructure(requestsAndFolders, insomniaCollection._id), + + resolve(brunoCollection); + } catch (err) { + reject(new BrunoError('An error occurred while parsing the Insomnia collection')); + } + }); +}; + +const importCollection = () => { + return new Promise((resolve, reject) => { + fileDialog({ accept: 'application/json' }) + .then(readFile) + .then(parseInsomniaCollection) + .then(transformItemsInCollection) + .then(hydrateSeqInCollection) + .then(validateSchema) + .then((collection) => resolve(collection)) + .catch((err) => { + console.log(err); + reject(new BrunoError('Import collection failed')); + }); + }); +}; + +export default importCollection; \ No newline at end of file