diff --git a/packages/bruno-app/src/components/RequestTabPanel/index.js b/packages/bruno-app/src/components/RequestTabPanel/index.js index aebaa444..645ba9f1 100644 --- a/packages/bruno-app/src/components/RequestTabPanel/index.js +++ b/packages/bruno-app/src/components/RequestTabPanel/index.js @@ -122,7 +122,7 @@ const RequestTabPanel = () => { className="px-4" style={{width: `${leftPaneWidth}px`, height: 'calc(100% - 5px)'}} > - {item.type === 'graphql' ? ( + {item.type === 'graphql-request' ? ( { /> ) : null} - {item.type === 'http' ? ( + {item.type === 'http-request' ? ( { - if(!['http', 'graphql'].includes(item.type)) { + if(!['http-request', 'graphql-request'].includes(item.type)) { return null; } diff --git a/packages/bruno-app/src/components/Sidebar/NewRequest/index.js b/packages/bruno-app/src/components/Sidebar/NewRequest/index.js index 692a3787..4961f299 100644 --- a/packages/bruno-app/src/components/Sidebar/NewRequest/index.js +++ b/packages/bruno-app/src/components/Sidebar/NewRequest/index.js @@ -17,9 +17,9 @@ const NewRequest = ({collection, item, isEphermal, onClose}) => { enableReinitialize: true, initialValues: { requestName: '', - requestType: 'http', + requestType: 'http-request', requestUrl: '', - requestMethod: 'get' + requestMethod: 'GET' }, validationSchema: Yup.object({ requestName: Yup.string() @@ -44,19 +44,13 @@ const NewRequest = ({collection, item, isEphermal, onClose}) => { })); } else { dispatch(newHttpRequest({ - requestName: values.requestName, - requestType: values.requestType, - requestUrl: values.requestUrl, - requestMethod: values.requestMethod, - collectionUid: collection.uid, - itemUid: item ? item.uid : null - })) - .then((action) => { - dispatch(addTab({ - uid: action.payload.item.uid, - collectionUid: collection.uid - })); - }); + requestName: values.requestName, + requestType: values.requestType, + requestUrl: values.requestUrl, + requestMethod: values.requestMethod, + collectionUid: collection.uid, + itemUid: item ? item.uid : null + })); } onClose(); } @@ -90,7 +84,7 @@ const NewRequest = ({collection, item, isEphermal, onClose}) => { type="radio" name="requestType" onChange={formik.handleChange} value="http" - checked={formik.values.requestType === 'http'} + checked={formik.values.requestType === 'http-request'} /> @@ -99,11 +93,11 @@ const NewRequest = ({collection, item, isEphermal, onClose}) => { className="ml-4 cursor-pointer" type="radio" name="requestType" onChange={(event) => { - formik.setFieldValue('requestMethod', 'post') + formik.setFieldValue('requestMethod', 'POST') formik.handleChange(event); }} value="graphql" - checked={formik.values.requestType === 'graphql'} + checked={formik.values.requestType === 'graphql-request'} /> diff --git a/packages/bruno-app/src/providers/App/useIdb.js b/packages/bruno-app/src/providers/App/useIdb.js index dc91d279..70bf7474 100644 --- a/packages/bruno-app/src/providers/App/useIdb.js +++ b/packages/bruno-app/src/providers/App/useIdb.js @@ -10,13 +10,11 @@ const useIdb = () => { useEffect(() => { let dbName = `bruno`; - let connection = openDB(dbName, 2, { + let connection = openDB(dbName, 1, { upgrade(db, oldVersion, newVersion, transaction) { switch(oldVersion) { case 0: const collectionStore = db.createObjectStore('collection', { keyPath: 'uid' }); - collectionStore.createIndex('transactionIdIndex', 'transaction_id'); - case 1: const workspaceStore = db.createObjectStore('workspace', { keyPath: 'uid' }); } } diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js index 28230fa9..6408c53a 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -10,6 +10,7 @@ import { findParentItemInCollection, isItemAFolder } from 'utils/collections'; +import { collectionSchema } from '@usebruno/schema'; import { waitForNextTick } from 'utils/common'; import cancelTokens, { saveCancelToken, deleteCancelToken } from 'utils/network/cancelTokens'; import { saveCollectionToIdb, deleteCollectionInIdb } from 'utils/idb'; @@ -36,18 +37,18 @@ export const createCollection = (collectionName) => (dispatch, getState) => { const newCollection = { uid: uuid(), name: collectionName, - items: [], - environments: [], + items: [] }; const requestItem = { uid: uuid(), - type: 'http', + type: 'http-request', name: 'Untitled', request: { method: 'GET', url: '', headers: [], + params: [], body: { mode: 'none', json: null, @@ -65,7 +66,9 @@ export const createCollection = (collectionName) => (dispatch, getState) => { const { activeWorkspaceUid } = state.workspaces; return new Promise((resolve, reject) => { - saveCollectionToIdb(window.__idb, newCollection) + collectionSchema + .validate(newCollection) + .then(() => saveCollectionToIdb(window.__idb, newCollection)) .then(() => dispatch(_createCollection(newCollection))) .then(waitForNextTick) .then(() => dispatch(addCollectionToWorkspace(activeWorkspaceUid, newCollection.uid))) @@ -90,7 +93,9 @@ export const renameCollection = (newName, collectionUid) => (dispatch, getState) ignoreDraft: true }); - saveCollectionToIdb(window.__idb, collectionToSave) + collectionSchema + .validate(collectionToSave) + .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) .then(() => { dispatch(_renameCollection({ newName: newName, @@ -135,7 +140,9 @@ export const saveRequest = (itemUid, collectionUid) => (dispatch, getState) => { const collectionCopy = cloneDeep(collection); const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - saveCollectionToIdb(window.__idb, collectionToSave) + collectionSchema + .validate(collectionToSave) + .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) .then(() => { dispatch(_saveRequest({ itemUid: itemUid, @@ -208,7 +215,9 @@ export const newFolder = (folderName, collectionUid, itemUid) => (dispatch, getS } const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - saveCollectionToIdb(window.__idb, collectionToSave) + collectionSchema + .validate(collectionToSave) + .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) .then(() => { dispatch(_newItem({ item: item, @@ -239,7 +248,9 @@ export const renameItem = (newName, itemUid, collectionUid) => (dispatch, getSta ignoreDraft: true }); - saveCollectionToIdb(window.__idb, collectionToSave) + collectionSchema + .validate(collectionToSave) + .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) .then(() => { dispatch(_renameItem({ newName: newName, @@ -286,7 +297,9 @@ export const cloneItem = (newName, itemUid, collectionUid) => (dispatch, getStat const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - saveCollectionToIdb(window.__idb, collectionToSave) + collectionSchema + .validate(collectionToSave) + .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) .then(() => { dispatch(_cloneItem({ parentItemUid: parentItem ? parentItem.uid : null, @@ -309,7 +322,9 @@ export const deleteItem = (itemUid, collectionUid) => (dispatch, getState) => { deleteItemInCollection(itemUid, collectionCopy); const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - saveCollectionToIdb(window.__idb, collectionToSave) + collectionSchema + .validate(collectionToSave) + .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) .then(() => { dispatch(_deleteItem({ itemUid: itemUid, @@ -369,7 +384,9 @@ export const newHttpRequest = (params) => (dispatch, getState) => { } const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - saveCollectionToIdb(window.__idb, collectionToSave) + collectionSchema + .validate(collectionToSave) + .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) .then(() => { dispatch(_newItem({ item: item, @@ -377,6 +394,13 @@ export const newHttpRequest = (params) => (dispatch, getState) => { collectionUid: collectionUid })); }) + .then(waitForNextTick) + .then(() => { + dispatch(addTab({ + uid: item.uid, + collectionUid: collection.uid + })); + }) .then(() => resolve()) .catch(reject); }); diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js index 47ffa133..cf079b06 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js @@ -17,7 +17,8 @@ const seedWorkpace = () => { const uid = uuid(); const workspace = { uid: uid, - name: 'My workspace' + name: 'My workspace', + collectionUids: [] }; return new Promise((resolve, reject) => { @@ -50,7 +51,8 @@ export const loadWorkspacesFromIdb = () => (dispatch) => { export const addWorkspace = (workspaceName) => (dispatch) => { const newWorkspace = { uid: uuid(), - name: workspaceName + name: workspaceName, + collectionUids: [] }; return new Promise((resolve, reject) => { diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/index.js index ad6befcc..4d15d2d9 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/index.js @@ -4,7 +4,6 @@ import filter from 'lodash/filter'; const initialState = { workspaces: [], - collectionUids: [], activeWorkspaceUid: null }; diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js index 60732692..9e74df43 100644 --- a/packages/bruno-app/src/utils/collections/index.js +++ b/packages/bruno-app/src/utils/collections/index.js @@ -218,9 +218,6 @@ export const transformCollectionToSaveToIdb = (collection, options = {}) => { const collectionToSave = {}; collectionToSave.name = collection.name; collectionToSave.uid = collection.uid; - collectionToSave.userId = collection.userId; - collectionToSave.orgId = collection.orgId; - collectionToSave.environments = cloneDeep(collection.environments); collectionToSave.items = []; copyItems(collection.items, collectionToSave.items); @@ -243,7 +240,7 @@ export const deleteItemInCollection = (itemUid, collection) => { export const isItemARequest = (item) => { return item.hasOwnProperty('request') - && ['http', 'graphql'].includes(item.type) + && ['http-request', 'graphql-request'].includes(item.type) && !item.items; }; diff --git a/packages/bruno-app/src/utils/network/index.js b/packages/bruno-app/src/utils/network/index.js index 532aa81a..92279e9f 100644 --- a/packages/bruno-app/src/utils/network/index.js +++ b/packages/bruno-app/src/utils/network/index.js @@ -6,7 +6,7 @@ import { sendHttpRequestInBrowser } from './browser'; const sendNetworkRequest = async (item, options) => { return new Promise((resolve, reject) => { - if(item.type === 'http') { + if(item.type === 'http-request') { const timeStart = Date.now(); sendHttpRequest(item.draft ? item.draft.request : item.request, options) .then((response) => { diff --git a/packages/bruno-app/src/utils/tabs/index.js b/packages/bruno-app/src/utils/tabs/index.js index f6135ff5..a6fa29dd 100644 --- a/packages/bruno-app/src/utils/tabs/index.js +++ b/packages/bruno-app/src/utils/tabs/index.js @@ -1,7 +1,7 @@ import find from 'lodash/find'; export const isItemARequest = (item) => { - return item.hasOwnProperty('request') && ['http', 'graphql'].includes(item.type); + return item.hasOwnProperty('request') && ['http-request', 'graphql-request'].includes(item.type); }; export const isItemAFolder = (item) => { diff --git a/packages/bruno-schema/readme.md b/packages/bruno-schema/readme.md index edcb2e2a..d91eaa72 100644 --- a/packages/bruno-schema/readme.md +++ b/packages/bruno-schema/readme.md @@ -12,9 +12,9 @@ uid Unique id name collection name items Items (folders and requests) |-uid A unique id - |-name Request name + |-name Item name + |-type Item type (folder, http-request, graphql-request) |-request Request object - |-type Request type (http, graphql) |-url Request url |-method Request method |-headers Request headers (array of key-val) diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index 962628c4..4f85702e 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -9,24 +9,22 @@ const keyValueSchema = Yup.object({ enabled: Yup.boolean().defined() }).noUnknown(true).strict(); -const requestTypeSchema = Yup.string().oneOf(['http', 'graphql']).required('type is required'); const requestUrlSchema = Yup.string().min(0).max(2048, 'name must be 2048 characters or less').defined(); const requestMethodSchema = Yup.string().oneOf(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD']).required('method is required'); const requestBodySchema = Yup.object({ mode: Yup.string().oneOf(['none', 'json', 'text', 'xml', 'formUrlEncoded', 'multipartForm']).required('mode is required'), - json: Yup.string().max(10240, 'json must be 10240 characters or less'), - text: Yup.string().max(10240, 'text must be 10240 characters or less'), - xml: Yup.string().max(10240, 'xml must be 10240 characters or less'), - formUrlEncoded: keyValueSchema, - multipartForm: keyValueSchema, + json: Yup.string().max(10240, 'json must be 10240 characters or less').nullable(), + text: Yup.string().max(10240, 'text must be 10240 characters or less').nullable(), + xml: Yup.string().max(10240, 'xml must be 10240 characters or less').nullable(), + formUrlEncoded: Yup.array().of(keyValueSchema).nullable(), + multipartForm: Yup.array().of(keyValueSchema).nullable(), }).noUnknown(true).strict(); // Right now, the request schema is very tightly coupled with http request // As we introduce more request types in the future, we will improve the definition to support // schema structure based on other request type const requestSchema = Yup.object({ - type: requestTypeSchema, url: requestUrlSchema, method: requestMethodSchema, headers: Yup.array().of(keyValueSchema).required('headers are required'), @@ -36,13 +34,13 @@ const requestSchema = Yup.object({ const itemSchema = Yup.object({ uid: uidSchema, - type: Yup.string().oneOf(['request', 'folder']).required('type is required'), + type: Yup.string().oneOf(['http-request', 'graphql-request', 'folder']).required('type is required'), name: Yup.string() .min(1, 'name must be atleast 1 characters') .max(50, 'name must be 100 characters or less') .required('name is required'), request: requestSchema.when('type', { - is: 'request', + is: (type) => ['http-request', 'graphql-request'].includes(type), then: (schema) => schema.required('request is required when item-type is request') }), items: Yup.lazy(() => Yup.array().of(itemSchema)) diff --git a/packages/bruno-schema/src/collections/index.spec.js b/packages/bruno-schema/src/collections/index.spec.js index eacf06fe..5e5acda9 100644 --- a/packages/bruno-schema/src/collections/index.spec.js +++ b/packages/bruno-schema/src/collections/index.spec.js @@ -46,9 +46,8 @@ describe('Collection Schema Validation', () => { items: [{ uid: uuid(), name: 'Get Countries', - type: 'request', + type: 'http-request', request: { - type: 'http', url: 'https://restcountries.com/v2/alpha/in', method: 'GET', headers: [], @@ -95,9 +94,8 @@ describe('Collection Schema Validation', () => { items: [{ uid: uuid(), name: 'Get Countries', - type: 'request', + type: 'http-request', request: { - type: 'http', url: 'https://restcountries.com/v2/alpha/in', method: 'GET', headers: [], diff --git a/packages/bruno-schema/src/collections/itemSchema.spec.js b/packages/bruno-schema/src/collections/itemSchema.spec.js index ea41b314..950766c2 100644 --- a/packages/bruno-schema/src/collections/itemSchema.spec.js +++ b/packages/bruno-schema/src/collections/itemSchema.spec.js @@ -41,11 +41,25 @@ describe('Item Schema Validation', () => { ]); }); - it('item schema must throw an error if request is not present when item-type is request', async () => { + it('item schema must throw an error if request is not present when item-type is http-request', async () => { const item = { uid: uuid(), name: 'Get Users', - type: 'request' + type: 'http-request' + }; + + return Promise.all([ + expect(itemSchema.validate(item)).rejects.toEqual( + validationErrorWithMessages('request is required when item-type is request') + ) + ]); + }); + + it('item schema must throw an error if request is not present when item-type is graphql-request', async () => { + const item = { + uid: uuid(), + name: 'Get Users', + type: 'graphql-request' }; return Promise.all([ diff --git a/packages/bruno-schema/src/collections/requestSchema.spec.js b/packages/bruno-schema/src/collections/requestSchema.spec.js index e15a91fa..b9bcda21 100644 --- a/packages/bruno-schema/src/collections/requestSchema.spec.js +++ b/packages/bruno-schema/src/collections/requestSchema.spec.js @@ -5,7 +5,6 @@ const { requestSchema } = require("./index"); describe('Request Schema Validation', () => { it('request schema must validate successfully - simple request', async () => { const request = { - type: 'http', url: 'https://restcountries.com/v2/alpha/in', method: 'GET', headers: [], @@ -19,28 +18,8 @@ describe('Request Schema Validation', () => { expect(isValid).toBeTruthy(); }); - it('request schema must throw an error of type is invalid', async () => { - const request = { - type: 'http-junk', - url: 'https://restcountries.com/v2/alpha/in', - method: 'GET', - headers: [], - params: [], - body: { - mode: 'none' - } - }; - - return Promise.all([ - expect(requestSchema.validate(request)).rejects.toEqual( - validationErrorWithMessages('type must be one of the following values: http, graphql') - ) - ]); - }); - it('request schema must throw an error of method is invalid', async () => { const request = { - type: 'http', url: 'https://restcountries.com/v2/alpha/in', method: 'GET-junk', headers: [], @@ -59,7 +38,6 @@ describe('Request Schema Validation', () => { it('request schema must throw an error of header name is missing', async () => { const request = { - type: 'http', url: 'https://restcountries.com/v2/alpha/in', method: 'GET', headers: [{ @@ -83,7 +61,6 @@ describe('Request Schema Validation', () => { it('request schema must throw an error of param value is missing', async () => { const request = { - type: 'http', url: 'https://restcountries.com/v2/alpha/in', method: 'GET', headers: [], diff --git a/packages/bruno-schema/src/index.js b/packages/bruno-schema/src/index.js index a0d11a26..2ac506b4 100644 --- a/packages/bruno-schema/src/index.js +++ b/packages/bruno-schema/src/index.js @@ -1,5 +1,7 @@ -const { workspaceSchema} = require("./workspaces"); +const { workspaceSchema } = require("./workspaces"); +const { collectionSchema } = require("./collections"); module.exports = { + collectionSchema, workspaceSchema }; \ No newline at end of file