diff --git a/packages/bruno-app/src/components/RequestPane/RequestBody/index.js b/packages/bruno-app/src/components/RequestPane/RequestBody/index.js index b49f0d4bb..bb3033369 100644 --- a/packages/bruno-app/src/components/RequestPane/RequestBody/index.js +++ b/packages/bruno-app/src/components/RequestPane/RequestBody/index.js @@ -4,7 +4,8 @@ import CodeEditor from 'components/CodeEditor'; import FormUrlEncodedParams from 'components/RequestPane/FormUrlEncodedParams'; import MultipartFormParams from 'components/RequestPane/MultipartFormParams'; import { useDispatch } from 'react-redux'; -import { updateRequestBody, sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections'; +import { updateRequestBody } from 'providers/ReduxStore/slices/collections'; +import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; const RequestBody = ({item, collection}) => { diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/CloneCollectionItem/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/CloneCollectionItem/index.js index d71ed3e22..40cce1a83 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/CloneCollectionItem/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/CloneCollectionItem/index.js @@ -4,7 +4,7 @@ import * as Yup from 'yup'; import Modal from 'components/Modal'; import { useDispatch } from 'react-redux'; import { isItemAFolder } from 'utils/tabs'; -import { cloneItem } from 'providers/ReduxStore/slices/collections'; +import { cloneItem } from 'providers/ReduxStore/slices/collections/actions'; const CloneCollectionItem = ({collection, item, onClose}) => { const dispatch = useDispatch(); diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/DeleteCollectionItem/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/DeleteCollectionItem/index.js index d7fcaf93a..a84beb499 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/DeleteCollectionItem/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/DeleteCollectionItem/index.js @@ -3,7 +3,7 @@ import Modal from 'components/Modal'; import { isItemAFolder } from 'utils/tabs'; import { useDispatch } from 'react-redux'; import { closeTabs } from 'providers/ReduxStore/slices/tabs'; -import { deleteItem } from 'providers/ReduxStore/slices/collections'; +import { deleteItem } from 'providers/ReduxStore/slices/collections/actions'; import { recursivelyGetAllItemUids } from 'utils/collections'; import StyledWrapper from './StyledWrapper'; diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/RenameCollectionItem/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/RenameCollectionItem/index.js index dc5223db7..c6d610cfc 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/RenameCollectionItem/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/RenameCollectionItem/index.js @@ -4,7 +4,7 @@ import * as Yup from 'yup'; import Modal from 'components/Modal'; import { useDispatch } from 'react-redux'; import { isItemAFolder } from 'utils/tabs'; -import { renameItem } from 'providers/ReduxStore/slices/collections'; +import { renameItem } from 'providers/ReduxStore/slices/collections/actions'; const RenameCollectionItem = ({collection, item, onClose}) => { const dispatch = useDispatch(); diff --git a/packages/bruno-app/src/components/Sidebar/NewFolder/index.js b/packages/bruno-app/src/components/Sidebar/NewFolder/index.js index 65ea0ccb6..4f3688830 100644 --- a/packages/bruno-app/src/components/Sidebar/NewFolder/index.js +++ b/packages/bruno-app/src/components/Sidebar/NewFolder/index.js @@ -3,7 +3,7 @@ import {useFormik} from 'formik'; import * as Yup from 'yup'; import Modal from 'components/Modal'; import { useDispatch } from 'react-redux'; -import { newFolder } from 'providers/ReduxStore/slices/collections'; +import { newFolder } from 'providers/ReduxStore/slices/collections/actions'; const NewFolder = ({collection, item, onClose}) => { const dispatch = useDispatch(); diff --git a/packages/bruno-app/src/components/Sidebar/NewRequest/index.js b/packages/bruno-app/src/components/Sidebar/NewRequest/index.js index 12eef0af4..692a37871 100644 --- a/packages/bruno-app/src/components/Sidebar/NewRequest/index.js +++ b/packages/bruno-app/src/components/Sidebar/NewRequest/index.js @@ -4,7 +4,8 @@ import * as Yup from 'yup'; import { uuid } from 'utils/common';; import Modal from 'components/Modal'; import { useDispatch } from 'react-redux'; -import { newHttpRequest, newEphermalHttpRequest } from 'providers/ReduxStore/slices/collections'; +import { newEphermalHttpRequest } from 'providers/ReduxStore/slices/collections'; +import { newHttpRequest } from 'providers/ReduxStore/slices/collections/actions'; import { addTab } from 'providers/ReduxStore/slices/tabs'; import HttpMethodSelector from 'components/RequestPane/QueryUrl/HttpMethodSelector'; import StyledWrapper from './StyledWrapper'; diff --git a/packages/bruno-app/src/providers/Hotkeys/index.js b/packages/bruno-app/src/providers/Hotkeys/index.js index adf5e988c..a867cf5f4 100644 --- a/packages/bruno-app/src/providers/Hotkeys/index.js +++ b/packages/bruno-app/src/providers/Hotkeys/index.js @@ -3,8 +3,7 @@ import find from 'lodash/find'; import Mousetrap from 'mousetrap'; import { useSelector, useDispatch } from 'react-redux'; import SaveRequest from 'components/RequestPane/SaveRequest'; -import { saveRequest } from 'providers/ReduxStore/slices/collections'; -import { sendRequest } from 'providers/ReduxStore/slices/collections/actions'; +import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import { findCollectionByUid, findItemInCollection } from 'utils/collections'; export const HotkeysContext = React.createContext(); 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 feef0235f..28230fa9b 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -2,9 +2,13 @@ import axios from 'axios'; import { uuid } from 'utils/common'; import cloneDeep from 'lodash/cloneDeep'; import { + findItemInCollection, findCollectionByUid, recursivelyGetAllItemUids, - transformCollectionToSaveToIdb + transformCollectionToSaveToIdb, + deleteItemInCollection, + findParentItemInCollection, + isItemAFolder } from 'utils/collections'; import { waitForNextTick } from 'utils/common'; import cancelTokens, { saveCancelToken, deleteCancelToken } from 'utils/network/cancelTokens'; @@ -15,6 +19,11 @@ import { requestSent, requestCancelled, responseReceived, + newItem as _newItem, + renameItem as _renameItem, + cloneItem as _cloneItem, + deleteItem as _deleteItem, + saveRequest as _saveRequest, createCollection as _createCollection, renameCollection as _renameCollection, deleteCollection as _deleteCollection, @@ -115,6 +124,29 @@ export const deleteCollection = (collectionUid) => (dispatch, getState) => { }); }; +export const saveRequest = (itemUid, collectionUid) => (dispatch, getState) => { + const state = getState(); + const collection = findCollectionByUid(state.collections.collections, collectionUid); + + return new Promise((resolve, reject) => { + if(!collection) { + return reject(new Error('Collection not found')); + } + const collectionCopy = cloneDeep(collection); + const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); + + saveCollectionToIdb(window.__idb, collectionToSave) + .then(() => { + dispatch(_saveRequest({ + itemUid: itemUid, + collectionUid: collectionUid + })); + }) + .then(() => resolve()) + .catch((error) => reject(error)); + }); +}; + export const sendRequest = (item, collectionUid) => (dispatch) => { const axiosRequest = axios.CancelToken.source(); const cancelTokenUid = uuid(); @@ -148,4 +180,204 @@ export const cancelRequest = (cancelTokenUid, item, collection) => (dispatch) => collectionUid: collection.uid })) } +}; + +export const newFolder = (folderName, collectionUid, itemUid) => (dispatch, getState) => { + const state = getState(); + const collection = findCollectionByUid(state.collections.collections, collectionUid); + + return new Promise((resolve, reject) => { + if(!collection) { + return reject(new Error('Collection not found')); + } + const collectionCopy = cloneDeep(collection); + const item = { + uid: uuid(), + name: folderName, + type: 'folder', + items: [] + }; + if(!itemUid) { + collectionCopy.items.push(item); + } else { + const currentItem = findItemInCollection(collectionCopy, itemUid); + if(currentItem && currentItem.type === 'folder') { + currentItem.items = currentItem.items || []; + currentItem.items.push(item); + } + } + const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); + + saveCollectionToIdb(window.__idb, collectionToSave) + .then(() => { + dispatch(_newItem({ + item: item, + currentItemUid: itemUid, + collectionUid: collectionUid + })); + }) + .then(() => resolve()) + .catch((error) => reject(error)); + }); +}; + +export const renameItem = (newName, itemUid, collectionUid) => (dispatch, getState) => { + const state = getState(); + const collection = findCollectionByUid(state.collections.collections, collectionUid); + + return new Promise((resolve, reject) => { + if(!collection) { + return reject(new Error('Collection not found')); + } + + const collectionCopy = cloneDeep(collection); + const item = findItemInCollection(collectionCopy, itemUid); + if(item) { + item.name = newName; + } + const collectionToSave = transformCollectionToSaveToIdb(collectionCopy, { + ignoreDraft: true + }); + + saveCollectionToIdb(window.__idb, collectionToSave) + .then(() => { + dispatch(_renameItem({ + newName: newName, + itemUid: itemUid, + collectionUid: collectionUid + })); + }) + .then(() => resolve()) + .catch((error) => reject(error)); + }); +}; + +export const cloneItem = (newName, itemUid, collectionUid) => (dispatch, getState) => { + const state = getState(); + const collection = findCollectionByUid(state.collections.collections, collectionUid); + + return new Promise((resolve, reject) => { + if(!collection) { + return reject(new Error('Collection not found')); + } + const collectionCopy = cloneDeep(collection); + const item = findItemInCollection(collectionCopy, itemUid); + if(!item) { + return; + } + + if(isItemAFolder(item)) { + throw new Error('Cloning folders is not supported yet'); + } + + // todo: clone query params + const clonedItem = cloneDeep(item); + clonedItem.name = newName; + clonedItem.uid = uuid(); + each(clonedItem.headers, h => h.uid = uuid()); + + const parentItem = findParentItemInCollection(collectionCopy, itemUid); + + if(!parentItem) { + collectionCopy.items.push(clonedItem); + } else { + parentItem.items.push(clonedItem); + } + + const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); + + saveCollectionToIdb(window.__idb, collectionToSave) + .then(() => { + dispatch(_cloneItem({ + parentItemUid: parentItem ? parentItem.uid : null, + clonedItem: clonedItem, + collectionUid: collectionUid + })); + }) + .then(() => resolve()) + .catch((error) => reject(error)); + }); +}; + +export const deleteItem = (itemUid, collectionUid) => (dispatch, getState) => { + const state = getState(); + const collection = findCollectionByUid(state.collections.collections, collectionUid); + + return new Promise((resolve, reject) => { + if(collection) { + const collectionCopy = cloneDeep(collection); + deleteItemInCollection(itemUid, collectionCopy); + const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); + + saveCollectionToIdb(window.__idb, collectionToSave) + .then(() => { + dispatch(_deleteItem({ + itemUid: itemUid, + collectionUid: collectionUid + })); + }) + .then(() => resolve()) + .catch((error) => reject(error)); + } + }); +}; + +export const newHttpRequest = (params) => (dispatch, getState) => { + const { + requestName, + requestType, + requestUrl, + requestMethod, + collectionUid, + itemUid + } = params; + + return new Promise((resolve, reject) => { + const state = getState(); + const collection = findCollectionByUid(state.collections.collections, collectionUid); + if(!collection) { + return reject(new Error('Collection not found')); + } + + const collectionCopy = cloneDeep(collection); + const item = { + uid: uuid(), + type: requestType, + name: requestName, + request: { + method: requestMethod, + url: requestUrl, + headers: [], + body: { + mode: 'none', + json: null, + text: null, + xml: null, + multipartForm: null, + formUrlEncoded: null + } + } + }; + if(!itemUid) { + collectionCopy.items.push(item); + } else { + const currentItem = findItemInCollection(collectionCopy, itemUid); + if(currentItem && currentItem.type === 'folder') { + currentItem.items = currentItem.items || []; + currentItem.items.push(item); + } + } + const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); + + saveCollectionToIdb(window.__idb, collectionToSave) + .then(() => { + dispatch(_newItem({ + item: item, + currentItemUid: itemUid, + collectionUid: collectionUid + })); + }) + .then(() => resolve()) + .catch(reject); + }); }; \ No newline at end of file diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index 8ccfedd4a..304fa8464 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -9,16 +9,13 @@ import splitOnFirst from 'split-on-first'; import { findCollectionByUid, findItemInCollection, - findParentItemInCollection, - transformCollectionToSaveToIdb, addDepth, collapseCollection, deleteItemInCollection, - isItemARequest, - isItemAFolder + isItemARequest } from 'utils/collections'; import { parseQueryParams, stringifyQueryParams } from 'utils/url'; -import { getCollectionsFromIdb, saveCollectionToIdb } from 'utils/idb'; +import { getCollectionsFromIdb } from 'utils/idb'; // todo: errors should be tracked in each slice and displayed as toasts @@ -30,7 +27,7 @@ export const collectionsSlice = createSlice({ name: 'collections', initialState, reducers: { - _loadCollections: (state, action) => { + loadCollections: (state, action) => { each(action.payload.collections, (c) => collapseCollection(c)); each(action.payload.collections, (c) => addDepth(c.items)); state.collections = action.payload.collections; @@ -48,7 +45,7 @@ export const collectionsSlice = createSlice({ deleteCollection: (state, action) => { state.collections = filter(state.collections, c => c.uid !== action.payload.collectionUid); }, - _newItem: (state, action) => { + newItem: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); if(collection) { @@ -65,14 +62,14 @@ export const collectionsSlice = createSlice({ addDepth(collection.items); } }, - _deleteItem: (state, action) => { + deleteItem: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); if(collection) { deleteItemInCollection(action.payload.itemUid, collection); } }, - _renameItem: (state, action) => { + renameItem: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); if(collection) { @@ -83,7 +80,7 @@ export const collectionsSlice = createSlice({ } } }, - _cloneItem: (state, action) => { + cloneItem: (state, action) => { const collectionUid = action.payload.collectionUid; const clonedItem = action.payload.clonedItem; const parentItemUid = action.payload.parentItemUid; @@ -134,7 +131,7 @@ export const collectionsSlice = createSlice({ } } }, - _saveRequest: (state, action) => { + saveRequest: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); if(collection) { @@ -544,15 +541,15 @@ export const { createCollection, renameCollection, deleteCollection, - _loadCollections, - _newItem, - _deleteItem, - _renameItem, - _cloneItem, + loadCollections, + newItem, + deleteItem, + renameItem, + cloneItem, requestSent, requestCancelled, responseReceived, - _saveRequest, + saveRequest, newEphermalHttpRequest, collectionClicked, collectionFolderClicked, @@ -576,219 +573,10 @@ export const { export const loadCollectionsFromIdb = () => (dispatch) => { getCollectionsFromIdb(window.__idb) - .then((collections) => dispatch(_loadCollections({ + .then((collections) => dispatch(loadCollections({ collections: collections }))) .catch((err) => console.log(err)); }; -export const saveRequest = (itemUid, collectionUid) => (dispatch, getState) => { - const state = getState(); - const collection = findCollectionByUid(state.collections.collections, collectionUid); - - - return new Promise((resolve, reject) => { - if(collection) { - const collectionCopy = cloneDeep(collection); - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - - saveCollectionToIdb(window.__idb, collectionToSave) - .then(() => { - dispatch(_saveRequest({ - itemUid: itemUid, - collectionUid: collectionUid - })); - }) - .then(() => resolve()) - .catch((error) => reject(error)); - } - }); -}; - -export const newFolder = (folderName, collectionUid, itemUid) => (dispatch, getState) => { - const state = getState(); - const collection = findCollectionByUid(state.collections.collections, collectionUid); - - if(collection) { - const collectionCopy = cloneDeep(collection); - const item = { - uid: uuid(), - name: folderName, - type: 'folder', - items: [] - }; - if(!itemUid) { - collectionCopy.items.push(item); - } else { - const currentItem = findItemInCollection(collectionCopy, itemUid); - if(currentItem && currentItem.type === 'folder') { - currentItem.items = currentItem.items || []; - currentItem.items.push(item); - } - } - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - - saveCollectionToIdb(window.__idb, collectionToSave) - .then(() => { - dispatch(_newItem({ - item: item, - currentItemUid: itemUid, - collectionUid: collectionUid - })); - }) - .catch((err) => console.log(err)); - } -}; - -export const newHttpRequest = (params) => (dispatch, getState) => { - const { - requestName, - requestType, - requestUrl, - requestMethod, - collectionUid, - itemUid - } = params; - return new Promise((resolve, reject) => { - const state = getState(); - const collection = findCollectionByUid(state.collections.collections, collectionUid); - - if(collection) { - const collectionCopy = cloneDeep(collection); - const item = { - uid: uuid(), - type: requestType, - name: requestName, - request: { - method: requestMethod, - url: requestUrl, - headers: [], - body: { - mode: 'none', - json: null, - text: null, - xml: null, - multipartForm: null, - formUrlEncoded: null - } - } - }; - if(!itemUid) { - collectionCopy.items.push(item); - } else { - const currentItem = findItemInCollection(collectionCopy, itemUid); - if(currentItem && currentItem.type === 'folder') { - currentItem.items = currentItem.items || []; - currentItem.items.push(item); - } - } - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - - saveCollectionToIdb(window.__idb, collectionToSave) - .then(() => { - Promise.resolve(dispatch(_newItem({ - item: item, - currentItemUid: itemUid, - collectionUid: collectionUid - }))) - .then((val) => resolve(val)) - .catch((err) => reject(err)); - }) - .catch(reject); - } - }); -}; - -export const deleteItem = (itemUid, collectionUid) => (dispatch, getState) => { - const state = getState(); - const collection = findCollectionByUid(state.collections.collections, collectionUid); - - return new Promise((resolve, reject) => { - if(collection) { - const collectionCopy = cloneDeep(collection); - deleteItemInCollection(itemUid, collectionCopy); - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - - saveCollectionToIdb(window.__idb, collectionToSave) - .then(() => { - dispatch(_deleteItem({ - itemUid: itemUid, - collectionUid: collectionUid - })); - }) - .then(() => resolve()) - .catch((error) => reject(error)); - } - }); -}; - -export const renameItem = (newName, itemUid, collectionUid) => (dispatch, getState) => { - const state = getState(); - const collection = findCollectionByUid(state.collections.collections, collectionUid); - - if(collection) { - const collectionCopy = cloneDeep(collection); - const item = findItemInCollection(collectionCopy, itemUid); - if(item) { - item.name = newName; - } - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy, { - ignoreDraft: true - }); - - saveCollectionToIdb(window.__idb, collectionToSave) - .then(() => { - dispatch(_renameItem({ - newName: newName, - itemUid: itemUid, - collectionUid: collectionUid - })); - }) - .catch((err) => console.log(err)); - } -}; - -export const cloneItem = (newName, itemUid, collectionUid) => (dispatch, getState) => { - const state = getState(); - const collection = findCollectionByUid(state.collections.collections, collectionUid); - - if(collection) { - const collectionCopy = cloneDeep(collection); - const item = findItemInCollection(collectionCopy, itemUid); - if(!item) { - return; - } - - if(isItemAFolder(item)) { - throw new Error('Cloning folders is not supported yet'); - } - - // todo: clone query params - const clonedItem = cloneDeep(item); - clonedItem.name = newName; - clonedItem.uid = uuid(); - each(clonedItem.headers, h => h.uid = uuid()); - - const parentItem = findParentItemInCollection(collectionCopy, itemUid); - - if(!parentItem) { - collectionCopy.items.push(clonedItem); - } else { - parentItem.items.push(clonedItem); - } - - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - - saveCollectionToIdb(window.__idb, collectionToSave) - .then(() => { - dispatch(_cloneItem({ - parentItemUid: parentItem ? parentItem.uid : null, - clonedItem: clonedItem, - collectionUid: collectionUid - })); - }) - .catch((err) => console.log(err)); - } -}; - export default collectionsSlice.reducer;