diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/ExportCollection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/ExportCollection/index.js new file mode 100644 index 00000000..0a1c7cd8 --- /dev/null +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/ExportCollection/index.js @@ -0,0 +1,37 @@ +import React from 'react'; +import exportBrunoCollection from 'utils/collections/export'; +import exportPostmanCollection from 'utils/exporters/postman-collection'; +import { toastError } from 'utils/common/error'; +import cloneDeep from 'lodash/cloneDeep'; +import Modal from 'components/Modal'; +import { transformCollectionToSaveToExportAsFile } from 'utils/collections/index'; + +const ExportCollection = ({ onClose, collection }) => { + const handleExportBrunoCollection = () => { + const collectionCopy = cloneDeep(collection); + exportBrunoCollection(transformCollectionToSaveToExportAsFile(collectionCopy)); + onClose(); + }; + + const handleExportPostmanCollection = () => { + const collectionCopy = cloneDeep(collection); + exportPostmanCollection(collectionCopy); + // exportPostmanCollection(transformCollectionToSaveToExportAsFile(collectionCopy)); + onClose(); + }; + + return ( + +
+
+ Bruno Collection +
+
+ Postman Collection +
+
+
+ ); +}; + +export default ExportCollection; diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js index b150ade8..2f7b876a 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js @@ -14,6 +14,7 @@ import NewRequest from 'components/Sidebar/NewRequest'; import NewFolder from 'components/Sidebar/NewFolder'; import CollectionItem from './CollectionItem'; import RemoveCollection from './RemoveCollection'; +import ExportCollection from './ExportCollection'; import CollectionProperties from './CollectionProperties'; import { doesCollectionHaveItemsMatchingSearchText } from 'utils/collections/search'; import { isItemAFolder, isItemARequest, transformCollectionToSaveToExportAsFile } from 'utils/collections'; @@ -26,6 +27,7 @@ const Collection = ({ collection, searchText }) => { const [showNewFolderModal, setShowNewFolderModal] = useState(false); const [showNewRequestModal, setShowNewRequestModal] = useState(false); const [showRenameCollectionModal, setShowRenameCollectionModal] = useState(false); + const [showExportCollectionModal, setShowExportCollectionModal] = useState(false); const [showRemoveCollectionModal, setShowRemoveCollectionModal] = useState(false); const [collectionPropertiesModal, setCollectionPropertiesModal] = useState(false); const [collectionIsCollapsed, setCollectionIsCollapsed] = useState(collection.collapsed); @@ -68,6 +70,7 @@ const Collection = ({ collection, searchText }) => { }; const handleExportClick = () => { + //EXPORT KOLEKCIE const collectionCopy = cloneDeep(collection); exportCollection(transformCollectionToSaveToExportAsFile(collectionCopy)); }; @@ -115,6 +118,9 @@ const Collection = ({ collection, searchText }) => { {showRemoveCollectionModal && ( setShowRemoveCollectionModal(false)} /> )} + {showExportCollectionModal && ( + setShowExportCollectionModal(false)} /> + )} {collectionPropertiesModal && ( setCollectionPropertiesModal(false)} /> )} @@ -172,7 +178,7 @@ const Collection = ({ collection, searchText }) => { className="dropdown-item" onClick={(e) => { menuDropdownTippyRef.current.hide(); - handleExportClick(true); + setShowExportCollectionModal(true); }} > Export diff --git a/packages/bruno-app/src/utils/collections/export.js b/packages/bruno-app/src/utils/collections/export.js index 64fc0da9..e5a68bc6 100644 --- a/packages/bruno-app/src/utils/collections/export.js +++ b/packages/bruno-app/src/utils/collections/export.js @@ -2,7 +2,7 @@ import * as FileSaver from 'file-saver'; import get from 'lodash/get'; import each from 'lodash/each'; -const deleteUidsInItems = (items) => { +export const deleteUidsInItems = (items) => { each(items, (item) => { delete item.uid; @@ -26,7 +26,7 @@ const deleteUidsInItems = (items) => { * Some of the models in the app are not consistent with the Collection Json format * This function is used to transform the models to the Collection Json format */ -const transformItem = (items = []) => { +export const transformItem = (items = []) => { each(items, (item) => { if (['http-request', 'graphql-request'].includes(item.type)) { item.request.query = item.request.params; @@ -47,14 +47,14 @@ const transformItem = (items = []) => { }); }; -const deleteUidsInEnvs = (envs) => { +export const deleteUidsInEnvs = (envs) => { each(envs, (env) => { delete env.uid; each(env.variables, (variable) => delete variable.uid); }); }; -const deleteSecretsInEnvs = (envs) => { +export const deleteSecretsInEnvs = (envs) => { each(envs, (env) => { each(env.variables, (variable) => { if (variable.secret) { @@ -64,7 +64,7 @@ const deleteSecretsInEnvs = (envs) => { }); }; -const exportCollection = (collection) => { +export const exportCollection = (collection) => { // delete uids delete collection.uid; deleteUidsInItems(collection.items); diff --git a/packages/bruno-app/src/utils/exporters/postman-collection.js b/packages/bruno-app/src/utils/exporters/postman-collection.js new file mode 100644 index 00000000..38fc6fbf --- /dev/null +++ b/packages/bruno-app/src/utils/exporters/postman-collection.js @@ -0,0 +1,151 @@ +import { BrunoError } from 'utils/common/error'; +import map from 'lodash/map'; +import { deleteSecretsInEnvs, deleteUidsInEnvs, deleteUidsInItems } from 'utils/collections/export'; + +export const exportCollection = (collection) => { + delete collection.uid; + deleteUidsInItems(collection.items); + deleteUidsInEnvs(collection.environments); + deleteSecretsInEnvs(collection.environments); + + const generateInfoSection = () => { + return { + name: collection.name, + schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json' + }; + }; + + const generateEventSection = (item) => { + const eventArray = []; + if (item.request.tests.length) { + eventArray.push({ + listen: 'test', + script: { + exec: item.request.tests.split('\n') + // type: 'text/javascript' + } + }); + } + if (item.request.script.req) { + eventArray.push({ + listen: 'prerequest', + script: { + exec: item.request.script.req.split('\n') + // type: 'text/javascript' + } + }); + } + return eventArray; + }; + + const generateHeaders = (headersArray) => { + return map(headersArray, (item) => { + return { + key: item.name, + value: item.value, + disabled: !item.enabled, + type: 'default' + }; + }); + }; + + const generateBody = (body) => { + switch (body.mode) { + case 'formUrlEncoded': + return { + mode: 'urlencoded', + urlencoded: map(body.formUrlEncoded, (bodyItem) => { + return { + key: bodyItem.name, + value: bodyItem.value, + disabled: !bodyItem.enabled, + type: 'default' + }; + }) + }; + case 'multipartForm': + return { + mode: 'formdata', + formdata: map(body.multipartForm, (bodyItem) => { + return { + key: bodyItem.name, + value: bodyItem.value, + disabled: !bodyItem.enabled, + type: 'default' + }; + }) + }; + case 'json': + return { + mode: 'raw', + raw: body.json, + options: { + raw: { + language: 'json' + } + } + }; + case 'xml': + return { + mode: 'raw', + raw: body.xml, + options: { + raw: { + language: 'xml' + } + } + }; + case 'text': + return { + mode: 'raw', + raw: body.text, + options: { + raw: { + language: 'text' + } + } + }; + } + }; + + const generateRequestSection = (itemRequest) => { + const requestObject = { + method: itemRequest.method, + header: generateHeaders(itemRequest.headers), + url: { + raw: itemRequest.url, + protocol: itemRequest.url.split('://')[0] + } + // host: TODO + // path: TODO + }; + + if (itemRequest.body.mode != 'none') { + requestObject.body = generateBody(itemRequest.body); + } + return requestObject; + }; + + const generateItemSection = (itemsArray) => { + return map(itemsArray, (item) => { + if (item.type === 'folder') { + return { + name: item.name, + item: item.items.length ? generateItemSection(item.items) : [] + }; + } else { + return { + name: item.name, + event: generateEventSection(item), + request: generateRequestSection(item.request) + }; + } + }); + }; + const collectionToExport = {}; + collectionToExport.info = generateInfoSection(); + collectionToExport.item = generateItemSection(collection.items); + console.log(collectionToExport); +}; + +export default exportCollection;