diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js index a90e2bd2..6fd86342 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js @@ -306,28 +306,26 @@ const CollectionItem = ({ item, collection, searchText }) => { > Rename +
{ + dropdownTippyRef.current.hide(); + setCloneItemModalOpen(true); + }} + > + Clone +
{!isFolder && ( - <> -
{ - dropdownTippyRef.current.hide(); - setCloneItemModalOpen(true); - }} - > - Clone -
-
{ - dropdownTippyRef.current.hide(); - handleClick(null); - handleRun(); - }} - > - Run -
- +
{ + dropdownTippyRef.current.hide(); + handleClick(null); + handleRun(); + }} + > + Run +
)} {!isFolder && item.type === 'http-request' && (
(dispatch, getStat } if (isItemAFolder(item)) { - throw new Error('Cloning folders is not supported yet'); + const parentFolder = findParentItemInCollection(collection, item.uid) || collection; + + const folderWithSameNameExists = find( + parentFolder.items, + (i) => i.type === 'folder' && trim(i.name) === trim(newName) + ); + + if (folderWithSameNameExists) { + return reject(new Error('Duplicate folder names under same parent folder are not allowed')); + } + + const collectionPath = `${parentFolder.pathname}${PATH_SEPARATOR}${newName}`; + ipcRenderer.invoke('renderer:clone-folder', item, collectionPath).then(resolve).catch(reject); + return; } const parentItem = findParentItemInCollection(collectionCopy, itemUid); diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js index be6afbea..fc1e1444 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -391,6 +391,40 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection } }); + ipcMain.handle('renderer:clone-folder', async (event, itemFolder, collectionPath) => { + try { + if (fs.existsSync(collectionPath)) { + throw new Error(`folder: ${collectionPath} already exists`); + } + + // Recursive function to parse the folder and create files/folders + const parseCollectionItems = (items = [], currentPath) => { + items.forEach((item) => { + if (['http-request', 'graphql-request'].includes(item.type)) { + const content = jsonToBru(item); + const filePath = path.join(currentPath, `${item.name}.bru`); + fs.writeFileSync(filePath, content); + } + if (item.type === 'folder') { + const folderPath = path.join(currentPath, item.name); + fs.mkdirSync(folderPath); + + if (item.items && item.items.length) { + parseCollectionItems(item.items, folderPath); + } + } + }); + }; + + await createDirectory(collectionPath); + + // create folder and files based on another folder + await parseCollectionItems(itemFolder.items, collectionPath); + } catch (error) { + return Promise.reject(error); + } + }); + ipcMain.handle('renderer:resequence-items', async (event, itemsToResequence) => { try { for (let item of itemsToResequence) {