forked from extern/bruno
feat: import postman collection (#45)
This commit is contained in:
parent
bf4c26de33
commit
481486cd1c
@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { collectionImported } from 'providers/ReduxStore/slices/collections';
|
||||
import importBrunoCollection from 'utils/importers/bruno-collection';
|
||||
import importPostmanCollection from 'utils/importers/postman-collection';
|
||||
import { addCollectionToWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||
import { toastError } from 'utils/common/error';
|
||||
import toast from 'react-hot-toast';
|
||||
@ -22,6 +23,17 @@ const ImportCollection = ({ onClose }) => {
|
||||
.catch((err) => toastError(err, 'Import collection failed'));
|
||||
};
|
||||
|
||||
const handleImportPostmanCollection = () => {
|
||||
importPostmanCollection()
|
||||
.then((collection) => {
|
||||
dispatch(collectionImported({ collection: collection }));
|
||||
dispatch(addCollectionToWorkspace(activeWorkspaceUid, collection.uid));
|
||||
toast.success('Postman Collection imported successfully');
|
||||
onClose();
|
||||
})
|
||||
.catch((err) => toastError(err, 'Postman Import collection failed'));
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal size="sm" title="Import Collection" hideFooter={true} handleConfirm={onClose} handleCancel={onClose}>
|
||||
<div>
|
||||
@ -31,7 +43,12 @@ const ImportCollection = ({ onClose }) => {
|
||||
>
|
||||
Bruno Collection
|
||||
</div>
|
||||
<div className='text-link hover:underline cursor-pointer mt-2'>Postman Collection</div>
|
||||
<div
|
||||
className='text-link hover:underline cursor-pointer mt-2'
|
||||
onClick={handleImportPostmanCollection}
|
||||
>
|
||||
Postman Collection
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
@ -1,11 +1,7 @@
|
||||
import each from 'lodash/each';
|
||||
import get from 'lodash/get';
|
||||
import fileDialog from 'file-dialog';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { uuid } from 'utils/common';
|
||||
import { collectionSchema } from '@usebruno/schema';
|
||||
import { saveCollectionToIdb } from 'utils/idb';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
import { validateSchema, updateUidsInCollection } from './common';
|
||||
import sampleCollection from './samples/sample-collection.json';
|
||||
|
||||
const readFile = (files) => {
|
||||
@ -29,42 +25,6 @@ const parseJsonCollection = (str) => {
|
||||
});
|
||||
};
|
||||
|
||||
const validateSchema = (collection = {}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
collectionSchema
|
||||
.validate(collection)
|
||||
.then(() => resolve(collection))
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
reject(new BrunoError('The Collection file is corrupted'));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const updateUidsInCollection = (_collection) => {
|
||||
const collection = cloneDeep(_collection);
|
||||
|
||||
collection.uid = uuid();
|
||||
|
||||
const updateItemUids = (items = []) => {
|
||||
each(items, (item) => {
|
||||
item.uid = uuid();
|
||||
|
||||
each(get(item, 'request.headers'), (header) => (header.uid = uuid()));
|
||||
each(get(item, 'request.params'), (param) => (param.uid = uuid()));
|
||||
each(get(item, 'request.body.multipartForm'), (param) => (param.uid = uuid()));
|
||||
each(get(item, 'request.body.formUrlEncoded'), (param) => (param.uid = uuid()));
|
||||
|
||||
if (item.items && item.items.length) {
|
||||
updateItemUids(item.items);
|
||||
}
|
||||
});
|
||||
};
|
||||
updateItemUids(collection.items);
|
||||
|
||||
return collection;
|
||||
};
|
||||
|
||||
const importCollection = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fileDialog({ accept: 'application/json' })
|
||||
|
44
packages/bruno-app/src/utils/importers/common.js
Normal file
44
packages/bruno-app/src/utils/importers/common.js
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
import each from 'lodash/each';
|
||||
import get from 'lodash/get';
|
||||
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { uuid } from 'utils/common';
|
||||
import { collectionSchema } from '@usebruno/schema';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
|
||||
export const validateSchema = (collection = {}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
collectionSchema
|
||||
.validate(collection)
|
||||
.then(() => resolve(collection))
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
reject(new BrunoError('The Collection file is corrupted'));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const updateUidsInCollection = (_collection) => {
|
||||
const collection = cloneDeep(_collection);
|
||||
|
||||
collection.uid = uuid();
|
||||
|
||||
const updateItemUids = (items = []) => {
|
||||
each(items, (item) => {
|
||||
item.uid = uuid();
|
||||
|
||||
each(get(item, 'request.headers'), (header) => (header.uid = uuid()));
|
||||
each(get(item, 'request.params'), (param) => (param.uid = uuid()));
|
||||
each(get(item, 'request.body.multipartForm'), (param) => (param.uid = uuid()));
|
||||
each(get(item, 'request.body.formUrlEncoded'), (param) => (param.uid = uuid()));
|
||||
|
||||
if (item.items && item.items.length) {
|
||||
updateItemUids(item.items);
|
||||
}
|
||||
});
|
||||
};
|
||||
updateItemUids(collection.items);
|
||||
|
||||
return collection;
|
||||
};
|
187
packages/bruno-app/src/utils/importers/postman-collection.js
Normal file
187
packages/bruno-app/src/utils/importers/postman-collection.js
Normal file
@ -0,0 +1,187 @@
|
||||
import each from 'lodash/each';
|
||||
import get from 'lodash/get';
|
||||
import fileDialog from 'file-dialog';
|
||||
import { uuid } from 'utils/common';
|
||||
import { saveCollectionToIdb } from 'utils/idb';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
import { validateSchema, updateUidsInCollection } 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 isItemAFolder = (item) => {
|
||||
return !item.request;
|
||||
};
|
||||
|
||||
const importPostmanV2CollectionItem = (brunoParent, item) => {
|
||||
brunoParent.items = brunoParent.items || [];
|
||||
|
||||
each(item, (i) => {
|
||||
if(isItemAFolder(i)) {
|
||||
const brunoFolderItem = {
|
||||
uid: uuid(),
|
||||
name: i.name,
|
||||
type: 'folder',
|
||||
items: []
|
||||
};
|
||||
brunoParent.items.push(brunoFolderItem);
|
||||
if(i.item && i.item.length) {
|
||||
importPostmanV2CollectionItem(brunoFolderItem, i.item);
|
||||
}
|
||||
} else {
|
||||
if(i.request) {
|
||||
const brunoRequestItem = {
|
||||
uid: uuid(),
|
||||
name: i.name,
|
||||
type: 'http-request',
|
||||
request: {
|
||||
url: get(i, 'request.url.raw'),
|
||||
method: i.request.method,
|
||||
headers: [],
|
||||
params: [],
|
||||
body: {
|
||||
mode: 'none',
|
||||
json: null,
|
||||
text: null,
|
||||
xml: null,
|
||||
formUrlEncoded: [],
|
||||
multipartForm: []
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const bodyMode = get(i, 'request.body.mode');
|
||||
if(bodyMode) {
|
||||
if(bodyMode === 'formdata') {
|
||||
brunoRequestItem.request.body.mode = 'multipartForm';
|
||||
each(i.request.body.formdata, (param) => {
|
||||
brunoRequestItem.request.body.formUrlEncoded.push({
|
||||
uid: uuid(),
|
||||
name: param.key,
|
||||
value: param.value,
|
||||
description: param.description,
|
||||
enabled: !param.disabled
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if(bodyMode === 'urlencoded') {
|
||||
brunoRequestItem.request.body.mode = 'formUrlEncoded';
|
||||
each(i.request.body.urlencoded, (param) => {
|
||||
brunoRequestItem.request.body.formUrlEncoded.push({
|
||||
uid: uuid(),
|
||||
name: param.key,
|
||||
value: param.value,
|
||||
description: param.description,
|
||||
enabled: !param.disabled
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if(bodyMode === 'raw') {
|
||||
const language = get(i, 'request.body.options.raw.language');
|
||||
if(language === 'json') {
|
||||
brunoRequestItem.request.body.mode = 'json';
|
||||
brunoRequestItem.request.body.json = i.request.body.raw;
|
||||
} else if (language === 'xml') {
|
||||
brunoRequestItem.request.body.mode = 'xml';
|
||||
brunoRequestItem.request.body.xml = i.request.body.raw;
|
||||
} else {
|
||||
brunoRequestItem.request.body.mode = 'text';
|
||||
brunoRequestItem.request.body.text = i.request.body.raw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
each(i.request.header, (header) => {
|
||||
brunoRequestItem.request.headers.push({
|
||||
uid: uuid(),
|
||||
name: header.key,
|
||||
value: header.value,
|
||||
description: header.description,
|
||||
enabled: !header.disabled
|
||||
});
|
||||
});
|
||||
|
||||
each(get(i, 'request.url.query'), (param) => {
|
||||
brunoRequestItem.request.params.push({
|
||||
uid: uuid(),
|
||||
name: param.key,
|
||||
value: param.value,
|
||||
description: param.description,
|
||||
enabled: !param.disabled
|
||||
});
|
||||
});
|
||||
|
||||
brunoParent.items.push(brunoRequestItem);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const importPostmanV2Collection = (collection) => {
|
||||
const brunoCollection = {
|
||||
name: collection.info.name,
|
||||
uid: uuid(),
|
||||
version: "1",
|
||||
items: [],
|
||||
environments: []
|
||||
};
|
||||
|
||||
importPostmanV2CollectionItem(brunoCollection, collection.item);
|
||||
|
||||
return brunoCollection;
|
||||
};
|
||||
|
||||
|
||||
const parsePostmanCollection = (str) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
let collection = JSON.parse(str);
|
||||
let schema = get(collection, 'info.schema');
|
||||
|
||||
let v2Schemas = [
|
||||
'https://schema.getpostman.com/json/collection/v2.0.0/collection.json',
|
||||
'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
|
||||
];
|
||||
|
||||
if(v2Schemas.includes(schema)) {
|
||||
return resolve(importPostmanV2Collection(collection));
|
||||
}
|
||||
|
||||
throw new BrunoError('Unknown postman schema');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
if(err instanceof BrunoError) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return reject(new BrunoError('Unable to parse the postman collection json file'));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const importCollection = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fileDialog({ accept: 'application/json' })
|
||||
.then(readFile)
|
||||
.then(parsePostmanCollection)
|
||||
.then(validateSchema)
|
||||
.then(updateUidsInCollection)
|
||||
.then(validateSchema)
|
||||
.then((collection) => saveCollectionToIdb(window.__idb, collection))
|
||||
.then((collection) => resolve(collection))
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
reject(new BrunoError('Import collection failed'));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export default importCollection;
|
Loading…
Reference in New Issue
Block a user