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) {