Merge pull request #544 from kapami/feature/export-to-postman-collection

Feature/export to postman collection
This commit is contained in:
Anoop M D 2023-10-13 06:49:59 +05:30 committed by GitHub
commit 671fcecb38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 262 additions and 6 deletions

View File

@ -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 (
<Modal size="sm" title="Export Collection" hideFooter={true} handleConfirm={onClose} handleCancel={onClose}>
<div>
<div className="text-link hover:underline cursor-pointer" onClick={handleExportBrunoCollection}>
Bruno Collection
</div>
<div className="text-link hover:underline cursor-pointer mt-2" onClick={handleExportPostmanCollection}>
Postman Collection
</div>
</div>
</Modal>
);
};
export default ExportCollection;

View File

@ -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);
@ -129,6 +131,9 @@ const Collection = ({ collection, searchText }) => {
{showRemoveCollectionModal && (
<RemoveCollection collection={collection} onClose={() => setShowRemoveCollectionModal(false)} />
)}
{showExportCollectionModal && (
<ExportCollection collection={collection} onClose={() => setShowExportCollectionModal(false)} />
)}
{collectionPropertiesModal && (
<CollectionProperties collection={collection} onClose={() => setCollectionPropertiesModal(false)} />
)}
@ -186,7 +191,7 @@ const Collection = ({ collection, searchText }) => {
className="dropdown-item"
onClick={(e) => {
menuDropdownTippyRef.current.hide();
handleExportClick(true);
setShowExportCollectionModal(true);
}}
>
Export

View File

@ -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);

View File

@ -0,0 +1,214 @@
import map from 'lodash/map';
import * as FileSaver from 'file-saver';
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 generateCollectionVars = (collection) => {
const pattern = /{{[^{}]+}}/g;
let listOfVars = [];
const findOccurrences = (obj, results) => {
if (typeof obj === 'object') {
if (Array.isArray(obj)) {
obj.forEach((item) => findOccurrences(item, results));
} else {
for (const key in obj) {
findOccurrences(obj[key], results);
}
}
} else if (typeof obj === 'string') {
obj.replace(pattern, (match) => {
results.push(match.replace(/{{|}}/g, ''));
});
}
};
findOccurrences(collection, listOfVars);
const finalArrayOfVars = [...new Set(listOfVars)];
return finalArrayOfVars.map((variable) => ({
key: variable,
value: '',
type: 'default'
}));
};
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 generateAuth = (itemAuth) => {
switch (itemAuth) {
case 'bearer':
return {
type: 'bearer',
bearer: {
key: 'token',
value: itemAuth.bearer.token,
type: 'string'
}
};
case 'basic': {
return {
type: 'basic',
basic: [
{
key: 'password',
value: itemAuth.basic.password,
type: 'string'
},
{
key: 'username',
value: itemAuth.basic.username,
type: 'string'
}
]
};
}
}
};
const generateRequestSection = (itemRequest) => {
const requestObject = {
method: itemRequest.method,
header: generateHeaders(itemRequest.headers),
url: itemRequest.url,
auth: generateAuth(itemRequest.auth)
};
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);
collectionToExport.variable = generateCollectionVars(collection);
const fileName = `${collection.name}.json`;
const fileBlob = new Blob([JSON.stringify(collection, null, 2)], { type: 'application/json' });
FileSaver.saveAs(fileBlob, fileName);
};
export default exportCollection;