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 folderWithSameNameExists = find( + collection.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 = `${collection.pathname}${PATH_SEPARATOR}${newName}`; + ipcRenderer.invoke('renderer:clone-folder', newName, 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..f3eb7845 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -12,7 +12,8 @@ const { browseDirectory, createDirectory, searchForBruFiles, - sanitizeDirectoryName + sanitizeDirectoryName, + parseCollectionItems } = require('../utils/filesystem'); const { stringifyJson } = require('../utils/common'); const { openCollectionDialog } = require('../app/collections'); @@ -335,25 +336,6 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection throw new Error(`collection: ${collectionPath} already exists`); } - // Recursive function to parse the collection items 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); - } - } - }); - }; - const parseEnvironments = (environments = [], collectionPath) => { const envDirPath = path.join(collectionPath, 'environments'); if (!fs.existsSync(envDirPath)) { @@ -391,6 +373,21 @@ 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`); + } + + 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) { diff --git a/packages/bruno-electron/src/utils/filesystem.js b/packages/bruno-electron/src/utils/filesystem.js index 4f3ea980..ab3a8d88 100644 --- a/packages/bruno-electron/src/utils/filesystem.js +++ b/packages/bruno-electron/src/utils/filesystem.js @@ -134,6 +134,25 @@ const sanitizeDirectoryName = (name) => { return name.replace(/[<>:"/\\|?*\x00-\x1F]+/g, '-'); }; +// 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); + } + } + }); +}; + module.exports = { isValidPathname, exists, @@ -150,5 +169,6 @@ module.exports = { chooseFileToSave, searchForFiles, searchForBruFiles, - sanitizeDirectoryName + sanitizeDirectoryName, + parseCollectionItems };