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
};