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 { useDispatch, useSelector } from 'react-redux';
|
||||||
import { collectionImported } from 'providers/ReduxStore/slices/collections';
|
import { collectionImported } from 'providers/ReduxStore/slices/collections';
|
||||||
import importBrunoCollection from 'utils/importers/bruno-collection';
|
import importBrunoCollection from 'utils/importers/bruno-collection';
|
||||||
|
import importPostmanCollection from 'utils/importers/postman-collection';
|
||||||
import { addCollectionToWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
|
import { addCollectionToWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
|
||||||
import { toastError } from 'utils/common/error';
|
import { toastError } from 'utils/common/error';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
@ -22,6 +23,17 @@ const ImportCollection = ({ onClose }) => {
|
|||||||
.catch((err) => toastError(err, 'Import collection failed'));
|
.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 (
|
return (
|
||||||
<Modal size="sm" title="Import Collection" hideFooter={true} handleConfirm={onClose} handleCancel={onClose}>
|
<Modal size="sm" title="Import Collection" hideFooter={true} handleConfirm={onClose} handleCancel={onClose}>
|
||||||
<div>
|
<div>
|
||||||
@ -31,7 +43,12 @@ const ImportCollection = ({ onClose }) => {
|
|||||||
>
|
>
|
||||||
Bruno Collection
|
Bruno Collection
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import each from 'lodash/each';
|
|
||||||
import get from 'lodash/get';
|
|
||||||
import fileDialog from 'file-dialog';
|
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 { saveCollectionToIdb } from 'utils/idb';
|
||||||
import { BrunoError } from 'utils/common/error';
|
import { BrunoError } from 'utils/common/error';
|
||||||
|
import { validateSchema, updateUidsInCollection } from './common';
|
||||||
import sampleCollection from './samples/sample-collection.json';
|
import sampleCollection from './samples/sample-collection.json';
|
||||||
|
|
||||||
const readFile = (files) => {
|
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 = () => {
|
const importCollection = () => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fileDialog({ accept: 'application/json' })
|
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