From 5291bbaef7aa724b415af3269f8f07feeae0ecd5 Mon Sep 17 00:00:00 2001 From: Pragadesh-45 <54320162+Pragadesh-45@users.noreply.github.com> Date: Mon, 10 Feb 2025 11:37:50 +0530 Subject: [PATCH 01/36] Fix: Import failing for collections with special characters in Windows (#3969) * fix: correct variable used in collection name update * fix: sanitize collection names by removing invalid filesystem characters * refactor: refactor collection name sanitization to use `sanitizeDirectoryName` --- packages/bruno-electron/src/ipc/collection.js | 7 ++----- packages/bruno-electron/src/utils/filesystem.js | 5 ----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js index 07f15926f..89138f090 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -20,7 +20,6 @@ const { normalizeWslPath, normalizeAndResolvePath, safeToRename, - sanitizeCollectionName, isWindowsOS, isValidFilename, hasSubDirectories, @@ -76,7 +75,6 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection async (event, collectionName, collectionFolderName, collectionLocation) => { try { collectionFolderName = sanitizeDirectoryName(collectionFolderName); - collectionName = sanitizeCollectionName(collectionName); const dirPath = path.join(collectionLocation, collectionFolderName); if (fs.existsSync(dirPath)) { const files = fs.readdirSync(dirPath); @@ -118,7 +116,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection ipcMain.handle( 'renderer:clone-collection', async (event, collectionName, collectionFolderName, collectionLocation, previousPath) => { - collectionFolderName = sanitizeCollectionName(collectionFolderName); + collectionFolderName = sanitizeDirectoryName(collectionFolderName); const dirPath = path.join(collectionLocation, collectionFolderName); if (fs.existsSync(dirPath)) { throw new Error(`collection: ${dirPath} already exists`); @@ -168,7 +166,6 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection // rename collection ipcMain.handle('renderer:rename-collection', async (event, newName, collectionPathname) => { try { - newName = sanitizeCollectionName(newName); const brunoJsonFilePath = path.join(collectionPathname, 'bruno.json'); const content = fs.readFileSync(brunoJsonFilePath, 'utf8'); const json = JSON.parse(content); @@ -521,7 +518,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection ipcMain.handle('renderer:import-collection', async (event, collection, collectionLocation) => { try { - let collectionName = sanitizeCollectionName(collection.name); + let collectionName = sanitizeDirectoryName(collection.name); let collectionPath = path.join(collectionLocation, collectionName); if (fs.existsSync(collectionPath)) { diff --git a/packages/bruno-electron/src/utils/filesystem.js b/packages/bruno-electron/src/utils/filesystem.js index 0a849f055..a9c8597e7 100644 --- a/packages/bruno-electron/src/utils/filesystem.js +++ b/packages/bruno-electron/src/utils/filesystem.js @@ -154,10 +154,6 @@ const searchForBruFiles = (dir) => { return searchForFiles(dir, '.bru'); }; -const sanitizeCollectionName = (name) => { - return name.trim(); -} - const sanitizeDirectoryName = (name) => { return name.replace(/[<>:"/\\|?*\x00-\x1F]+/g, '-').trim(); }; @@ -267,7 +263,6 @@ module.exports = { searchForFiles, searchForBruFiles, sanitizeDirectoryName, - sanitizeCollectionName, isWindowsOS, safeToRename, isValidFilename, From ced6ddfab5b218d6e75326e81b4e16d7352074cb Mon Sep 17 00:00:00 2001 From: Pooja Belaramani Date: Fri, 7 Feb 2025 18:07:56 +0530 Subject: [PATCH 02/36] add: translation for skipRequest and stopExecution --- .../src/utils/importers/translators/postman_translation.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/bruno-app/src/utils/importers/translators/postman_translation.js b/packages/bruno-app/src/utils/importers/translators/postman_translation.js index b386d719e..f75433fe2 100644 --- a/packages/bruno-app/src/utils/importers/translators/postman_translation.js +++ b/packages/bruno-app/src/utils/importers/translators/postman_translation.js @@ -24,6 +24,10 @@ const replacements = { 'postman\\.setEnvironmentVariable\\(': 'bru.setEnvVar(', 'postman\\.getEnvironmentVariable\\(': 'bru.getEnvVar(', 'postman\\.clearEnvironmentVariable\\(': 'bru.deleteEnvVar(', + 'pm\\.execution\\.skipRequest\\(\\)': 'bru.runner.skipRequest()', + 'pm\\.execution\\.skipRequest': 'bru.runner.skipRequest', + 'pm\\.execution\\.setNextRequest\\(null\\)': 'bru.runner.stopExecution()', + 'pm\\.execution\\.setNextRequest\\(\'null\'\\)': 'bru.runnere.stopExecution()', }; const extendedReplacements = Object.keys(replacements).reduce((acc, key) => { From 288628003f2d11d44b66e3f08798e5a8d8cc9497 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Jayarajan Date: Mon, 10 Feb 2025 14:41:05 +0530 Subject: [PATCH 03/36] Fixing typo in pm translation of util functions --- .../src/utils/importers/translators/postman_translation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bruno-app/src/utils/importers/translators/postman_translation.js b/packages/bruno-app/src/utils/importers/translators/postman_translation.js index f75433fe2..4b1f557dc 100644 --- a/packages/bruno-app/src/utils/importers/translators/postman_translation.js +++ b/packages/bruno-app/src/utils/importers/translators/postman_translation.js @@ -27,7 +27,7 @@ const replacements = { 'pm\\.execution\\.skipRequest\\(\\)': 'bru.runner.skipRequest()', 'pm\\.execution\\.skipRequest': 'bru.runner.skipRequest', 'pm\\.execution\\.setNextRequest\\(null\\)': 'bru.runner.stopExecution()', - 'pm\\.execution\\.setNextRequest\\(\'null\'\\)': 'bru.runnere.stopExecution()', + 'pm\\.execution\\.setNextRequest\\(\'null\'\\)': 'bru.runner.stopExecution()', }; const extendedReplacements = Object.keys(replacements).reduce((acc, key) => { From 4d063b2d0ba929107e677eb84b4e6210f96d27ce Mon Sep 17 00:00:00 2001 From: Sreelakshmi Jayarajan Date: Mon, 10 Feb 2025 14:43:51 +0530 Subject: [PATCH 04/36] Revert "Fixing typo in pm translation of util functions" This reverts commit fceff56872a5bb91a52b541c8dd3d460df6a8a14. --- .../src/utils/importers/translators/postman_translation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bruno-app/src/utils/importers/translators/postman_translation.js b/packages/bruno-app/src/utils/importers/translators/postman_translation.js index 4b1f557dc..f75433fe2 100644 --- a/packages/bruno-app/src/utils/importers/translators/postman_translation.js +++ b/packages/bruno-app/src/utils/importers/translators/postman_translation.js @@ -27,7 +27,7 @@ const replacements = { 'pm\\.execution\\.skipRequest\\(\\)': 'bru.runner.skipRequest()', 'pm\\.execution\\.skipRequest': 'bru.runner.skipRequest', 'pm\\.execution\\.setNextRequest\\(null\\)': 'bru.runner.stopExecution()', - 'pm\\.execution\\.setNextRequest\\(\'null\'\\)': 'bru.runner.stopExecution()', + 'pm\\.execution\\.setNextRequest\\(\'null\'\\)': 'bru.runnere.stopExecution()', }; const extendedReplacements = Object.keys(replacements).reduce((acc, key) => { From 835158999482aa0ea74148d344eafdc13e69eff0 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Jayarajan Date: Mon, 10 Feb 2025 14:46:17 +0530 Subject: [PATCH 05/36] Fixing typo in pm translation of util function --- .../src/utils/importers/translators/postman_translation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bruno-app/src/utils/importers/translators/postman_translation.js b/packages/bruno-app/src/utils/importers/translators/postman_translation.js index f75433fe2..4b1f557dc 100644 --- a/packages/bruno-app/src/utils/importers/translators/postman_translation.js +++ b/packages/bruno-app/src/utils/importers/translators/postman_translation.js @@ -27,7 +27,7 @@ const replacements = { 'pm\\.execution\\.skipRequest\\(\\)': 'bru.runner.skipRequest()', 'pm\\.execution\\.skipRequest': 'bru.runner.skipRequest', 'pm\\.execution\\.setNextRequest\\(null\\)': 'bru.runner.stopExecution()', - 'pm\\.execution\\.setNextRequest\\(\'null\'\\)': 'bru.runnere.stopExecution()', + 'pm\\.execution\\.setNextRequest\\(\'null\'\\)': 'bru.runner.stopExecution()', }; const extendedReplacements = Object.keys(replacements).reduce((acc, key) => { From 4c1765e9f907faff497d5cf226d5a1d69ef6a9b0 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Mon, 10 Feb 2025 14:50:38 +0530 Subject: [PATCH 06/36] feat(#2896): add support for cheerio and xml2json as inbuilt library --- package-lock.json | 411 +++++++++++++++++- packages/bruno-js/package.json | 4 +- .../bruno-js/src/runtime/script-runtime.js | 4 + packages/bruno-js/src/runtime/test-runtime.js | 4 + .../collection/ping-another-one.bru | 15 - .../inbuilt modules/cheerio/cheerio.bru | 42 ++ .../inbuilt modules/xml2js/xml2js.bru | 41 ++ 7 files changed, 487 insertions(+), 34 deletions(-) delete mode 100644 packages/bruno-tests/collection/ping-another-one.bru create mode 100644 packages/bruno-tests/collection/scripting/inbuilt modules/cheerio/cheerio.bru create mode 100644 packages/bruno-tests/collection/scripting/inbuilt modules/xml2js/xml2js.bru diff --git a/package-lock.json b/package-lock.json index f53c786a9..a3af1292f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -787,7 +786,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", - "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -818,7 +816,6 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -836,7 +833,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/@babel/generator": { @@ -1116,7 +1112,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.25.9", @@ -7083,7 +7078,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", - "dev": true, "license": "MIT" }, "node_modules/@types/lodash": { @@ -7096,7 +7090,6 @@ "version": "12.2.3", "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/linkify-it": "*", @@ -7107,7 +7100,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", - "dev": true, "license": "MIT" }, "node_modules/@types/ms": { @@ -8586,7 +8578,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true, "license": "ISC" }, "node_modules/boolean": { @@ -9417,6 +9408,229 @@ "node": "*" } }, + "node_modules/cheerio": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", + "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "encoding-sniffer": "^0.2.0", + "htmlparser2": "^9.1.0", + "parse5": "^7.1.2", + "parse5-htmlparser2-tree-adapter": "^7.0.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^6.19.5", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=18.17" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cheerio-select/node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cheerio-select/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/cheerio-select/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/cheerio-select/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/cheerio-select/node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/cheerio-select/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/cheerio/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/cheerio/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/cheerio/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/cheerio/node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/cheerio/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/cheerio/node_modules/htmlparser2": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" + } + }, + "node_modules/cheerio/node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "license": "MIT", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -10115,7 +10329,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -10583,7 +10796,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">= 6" @@ -11718,13 +11930,25 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { "iconv-lite": "^0.6.2" } }, + "node_modules/encoding-sniffer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz", + "integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==", + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -12739,7 +12963,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -17377,7 +17600,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" @@ -17782,6 +18004,106 @@ "dev": true, "license": "MIT" }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "license": "MIT", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parse5-parser-stream/node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "license": "MIT", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -21170,7 +21492,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "dev": true, "license": "ISC" }, "node_modules/scheduler": { @@ -23213,7 +23534,7 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -23229,6 +23550,15 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "license": "MIT" }, + "node_modules/undici": { + "version": "6.21.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz", + "integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, "node_modules/undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", @@ -23757,6 +24087,27 @@ "node": ">=10.13.0" } }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -23898,6 +24249,28 @@ "node": ">= 16" } }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xml2js/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, "node_modules/xmlbuilder": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", @@ -24043,7 +24416,7 @@ "graphiql": "3.7.1", "graphql": "^16.6.0", "graphql-request": "^3.7.0", - "httpsnippet": "^3.0.6", + "httpsnippet": "^3.0.9", "i18next": "24.1.2", "idb": "^7.0.0", "immer": "^9.0.15", @@ -24365,6 +24738,7 @@ "btoa": "^1.2.1", "chai": "^4.3.7", "chai-string": "^1.5.0", + "cheerio": "^1.0.0", "crypto-js": "^4.1.1", "json-query": "^2.2.2", "lodash": "^4.17.21", @@ -24374,7 +24748,8 @@ "node-vault": "^0.10.2", "path": "^0.12.7", "quickjs-emscripten": "^0.29.2", - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "xml2js": "^0.6.2" }, "devDependencies": { "@rollup/plugin-commonjs": "^23.0.2", diff --git a/packages/bruno-js/package.json b/packages/bruno-js/package.json index ad400ab58..1f1cee55a 100644 --- a/packages/bruno-js/package.json +++ b/packages/bruno-js/package.json @@ -25,6 +25,7 @@ "btoa": "^1.2.1", "chai": "^4.3.7", "chai-string": "^1.5.0", + "cheerio": "^1.0.0", "crypto-js": "^4.1.1", "json-query": "^2.2.2", "lodash": "^4.17.21", @@ -34,7 +35,8 @@ "node-vault": "^0.10.2", "path": "^0.12.7", "quickjs-emscripten": "^0.29.2", - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "xml2js": "^0.6.2" }, "devDependencies": { "@rollup/plugin-commonjs": "^23.0.2", diff --git a/packages/bruno-js/src/runtime/script-runtime.js b/packages/bruno-js/src/runtime/script-runtime.js index dcde3f27c..758b574e8 100644 --- a/packages/bruno-js/src/runtime/script-runtime.js +++ b/packages/bruno-js/src/runtime/script-runtime.js @@ -28,6 +28,8 @@ const fetch = require('node-fetch'); const chai = require('chai'); const CryptoJS = require('crypto-js'); const NodeVault = require('node-vault'); +const xml2js = require('xml2js'); +const cheerio = require('cheerio'); const { executeQuickJsVmAsync } = require('../sandbox/quickjs'); class ScriptRuntime { @@ -145,6 +147,8 @@ class ScriptRuntime { chai, 'node-fetch': fetch, 'crypto-js': CryptoJS, + 'xml2js': xml2js, + cheerio, ...whitelistedModules, fs: allowScriptFilesystemAccess ? fs : undefined, 'node-vault': NodeVault diff --git a/packages/bruno-js/src/runtime/test-runtime.js b/packages/bruno-js/src/runtime/test-runtime.js index 71db9d83e..e2d1f4865 100644 --- a/packages/bruno-js/src/runtime/test-runtime.js +++ b/packages/bruno-js/src/runtime/test-runtime.js @@ -30,6 +30,8 @@ const axios = require('axios'); const fetch = require('node-fetch'); const CryptoJS = require('crypto-js'); const NodeVault = require('node-vault'); +const xml2js = require('xml2js'); +const cheerio = require('cheerio'); const { executeQuickJsVmAsync } = require('../sandbox/quickjs'); const getResultsSummary = (results) => { @@ -205,6 +207,8 @@ class TestRuntime { chai, 'node-fetch': fetch, 'crypto-js': CryptoJS, + 'xml2js': xml2js, + cheerio, ...whitelistedModules, fs: allowScriptFilesystemAccess ? fs : undefined, 'node-vault': NodeVault diff --git a/packages/bruno-tests/collection/ping-another-one.bru b/packages/bruno-tests/collection/ping-another-one.bru deleted file mode 100644 index 84c1412a8..000000000 --- a/packages/bruno-tests/collection/ping-another-one.bru +++ /dev/null @@ -1,15 +0,0 @@ -meta { - name: ping-another-one - type: http - seq: 2 -} - -get { - url: {{host}}/ping - body: none - auth: none -} - -script:pre-request { - throw new Error('this should not execute in a collection run'); -} diff --git a/packages/bruno-tests/collection/scripting/inbuilt modules/cheerio/cheerio.bru b/packages/bruno-tests/collection/scripting/inbuilt modules/cheerio/cheerio.bru new file mode 100644 index 000000000..07aad76b2 --- /dev/null +++ b/packages/bruno-tests/collection/scripting/inbuilt modules/cheerio/cheerio.bru @@ -0,0 +1,42 @@ +meta { + name: cheerio + type: http + seq: 1 +} + +post { + url: https://echo.usebruno.com + body: text + auth: none +} + +body:text { +

Hello Bruno!

+} + +script:pre-request { + const cheerio = require('cheerio'); + + const $ = cheerio.load('

Hello world

'); + + $('h2.title').text('Hello there!'); + $('h2').addClass('welcome'); + + bru.setVar("cheerio-test-html", $.html()); +} + +tests { + const cheerio = require('cheerio'); + + test("cheerio html - from scripts", function() { + const expected = '

Hello there!

'; + const html = bru.getVar('cheerio-test-html'); + expect(html).to.eql(expected); + }); + + test("cheerio html - from tests", function() { + const expected = '

Hello Bruno!

'; + const $ = cheerio.load(res.body); + expect($.html()).to.eql(expected); + }); +} diff --git a/packages/bruno-tests/collection/scripting/inbuilt modules/xml2js/xml2js.bru b/packages/bruno-tests/collection/scripting/inbuilt modules/xml2js/xml2js.bru new file mode 100644 index 000000000..db8748ec3 --- /dev/null +++ b/packages/bruno-tests/collection/scripting/inbuilt modules/xml2js/xml2js.bru @@ -0,0 +1,41 @@ +meta { + name: xml2js + type: http + seq: 1 +} + +get { + url: {{host}}/ping + body: none + auth: none +} + +script:pre-request { + var parseString = require('xml2js').parseString; + var xml = "Hello xml2js!" + parseString(xml, function (err, result) { + bru.setVar("xml2js-test-result", result); + }); +} + +tests { + var parseString = require('xml2js').parseString; + + test("xml2js parseString in scripts", function() { + const expected = { + root: 'Hello xml2js!' + }; + const result = bru.getVar('xml2js-test-result'); + expect(result).to.eql(expected); + }); + + test("xml2js parseString in tests", async function() { + var xml = "Hello inside test!" + const expected = { + root: 'Hello inside test!' + }; + parseString(xml, function (err, result) { + expect(result).to.eql(expected); + }); + }); +} From 89a4cd62bc621c61ff2d2779749c229881ad2597 Mon Sep 17 00:00:00 2001 From: Sanjai Kumar <161328623+sanjaikumar-bruno@users.noreply.github.com> Date: Mon, 10 Feb 2025 20:46:42 +0530 Subject: [PATCH 07/36] Feat: Move-Collection with Drag-and-Drop (#3755) --------- Co-authored-by: sanjai0py Co-authored-by: ramki-bruno --- .../Collection/CollectionItem/index.js | 22 +++++---- .../Collections/Collection/StyledWrapper.js | 11 +++++ .../Sidebar/Collections/Collection/index.js | 48 +++++++++++++++---- .../components/Sidebar/Collections/index.js | 8 +--- packages/bruno-app/src/index.js | 6 ++- .../ReduxStore/slices/collections/actions.js | 17 +++++++ .../ReduxStore/slices/collections/index.js | 11 ++++- .../bruno-app/src/utils/collections/index.js | 11 +---- packages/bruno-electron/src/ipc/collection.js | 4 ++ .../src/store/last-opened-collections.js | 18 +++---- 10 files changed, 110 insertions(+), 46 deletions(-) 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 3e426eb7f..a08fac3b7 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 @@ -32,6 +32,7 @@ const CollectionItem = ({ item, collection, searchText }) => { const activeTabUid = useSelector((state) => state.tabs.activeTabUid); const isSidebarDragging = useSelector((state) => state.app.isDragging); const dispatch = useDispatch(); + const collectionItemRef = useRef(null); const [renameItemModalOpen, setRenameItemModalOpen] = useState(false); const [cloneItemModalOpen, setCloneItemModalOpen] = useState(false); @@ -45,28 +46,31 @@ const CollectionItem = ({ item, collection, searchText }) => { const itemIsCollapsed = hasSearchText ? false : item.collapsed; const [{ isDragging }, drag] = useDrag({ - type: `COLLECTION_ITEM_${collection.uid}`, + type: `collection-item-${collection.uid}`, item: item, collect: (monitor) => ({ isDragging: monitor.isDragging() - }) + }), + options: { + dropEffect: "move" + } }); const [{ isOver }, drop] = useDrop({ - accept: `COLLECTION_ITEM_${collection.uid}`, + accept: `collection-item-${collection.uid}`, drop: (draggedItem) => { - if (draggedItem.uid !== item.uid) { - dispatch(moveItem(collection.uid, draggedItem.uid, item.uid)); - } + dispatch(moveItem(collection.uid, draggedItem.uid, item.uid)); }, canDrop: (draggedItem) => { return draggedItem.uid !== item.uid; }, collect: (monitor) => ({ - isOver: monitor.isOver() - }) + isOver: monitor.isOver(), + }), }); + drag(drop(collectionItemRef)); + const dropdownTippyRef = useRef(); const MenuIcon = forwardRef((props, ref) => { return ( @@ -255,7 +259,7 @@ const CollectionItem = ({ item, collection, searchText }) => { {generateCodeItemModalOpen && ( setGenerateCodeItemModalOpen(false)} /> )} -
drag(drop(node))}> +
{indents && indents.length ? indents.map((i) => { diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/StyledWrapper.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/StyledWrapper.js index b8e0d21fd..5c06cc42a 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/StyledWrapper.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/StyledWrapper.js @@ -12,6 +12,17 @@ const Wrapper = styled.div` transform: rotateZ(90deg); } + &.item-hovered { + background: ${(props) => props.theme.sidebar.collection.item.hoverBg}; + .collection-actions { + .dropdown { + div[aria-expanded='false'] { + visibility: visible; + } + } + } + } + .collection-actions { .dropdown { div[aria-expanded='true'] { diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js index 3fe00c686..a18547406 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js @@ -2,11 +2,11 @@ import React, { useState, forwardRef, useRef, useEffect } from 'react'; import classnames from 'classnames'; import { uuid } from 'utils/common'; import filter from 'lodash/filter'; -import { useDrop } from 'react-dnd'; +import { useDrop, useDrag } from 'react-dnd'; import { IconChevronRight, IconDots, IconLoader2 } from '@tabler/icons'; import Dropdown from 'components/Dropdown'; import { collapseCollection } from 'providers/ReduxStore/slices/collections'; -import { mountCollection, moveItemToRootOfCollection } from 'providers/ReduxStore/slices/collections/actions'; +import { mountCollection, moveItemToRootOfCollection, moveCollectionAndPersist } from 'providers/ReduxStore/slices/collections/actions'; import { useDispatch, useSelector } from 'react-redux'; import { addTab, makeTabPermanent } from 'providers/ReduxStore/slices/tabs'; import NewRequest from 'components/Sidebar/NewRequest'; @@ -33,6 +33,7 @@ const Collection = ({ collection, searchText }) => { const tabs = useSelector((state) => state.tabs.tabs); const dispatch = useDispatch(); const isLoading = areItemsLoading(collection); + const collectionRef = useRef(null); const menuDropdownTippyRef = useRef(); const onMenuDropdownCreate = (ref) => (menuDropdownTippyRef.current = ref); @@ -124,26 +125,51 @@ const Collection = ({ collection, searchText }) => { ); }; + const isCollectionItem = (itemType) => { + return itemType.startsWith('collection-item'); + }; + + const [{ isDragging }, drag] = useDrag({ + type: "collection", + item: collection, + collect: (monitor) => ({ + isDragging: monitor.isDragging(), + }), + options: { + dropEffect: "move" + } + }); + const [{ isOver }, drop] = useDrop({ - accept: `COLLECTION_ITEM_${collection.uid}`, - drop: (draggedItem) => { - dispatch(moveItemToRootOfCollection(collection.uid, draggedItem.uid)); + accept: ["collection", `collection-item-${collection.uid}`], + drop: (draggedItem, monitor) => { + const itemType = monitor.getItemType(); + if (isCollectionItem(itemType)) { + dispatch(moveItemToRootOfCollection(collection.uid, draggedItem.uid)) + } else { + dispatch(moveCollectionAndPersist({draggedItem, targetItem: collection})); + } }, canDrop: (draggedItem) => { - // todo need to make sure that draggedItem belongs to the collection - return true; + return draggedItem.uid !== collection.uid; }, collect: (monitor) => ({ - isOver: monitor.isOver() - }) + isOver: monitor.isOver(), + }), }); + drag(drop(collectionRef)); + if (searchText && searchText.length) { if (!doesCollectionHaveItemsMatchingSearchText(collection, searchText)) { return null; } } + const collectionRowClassName = classnames('flex py-1 collection-name items-center', { + 'item-hovered': isOver + }); + // we need to sort request items by seq property const sortRequestItems = (items = []) => { return items.sort((a, b) => a.seq - b.seq); @@ -173,7 +199,9 @@ const Collection = ({ collection, searchText }) => { {showCloneCollectionModalOpen && ( setShowCloneCollectionModalOpen(false)} /> )} -
+
{ {collections && collections.length ? collections.map((c) => { return ( - - - + ); }) : null} diff --git a/packages/bruno-app/src/index.js b/packages/bruno-app/src/index.js index 0e5187ebe..36b1d0bc6 100644 --- a/packages/bruno-app/src/index.js +++ b/packages/bruno-app/src/index.js @@ -1,6 +1,8 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './pages/index'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; const rootElement = document.getElementById('root'); @@ -8,7 +10,9 @@ if (rootElement) { const root = ReactDOM.createRoot(rootElement); root.render( - + + + ); } 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 7de849eea..c2532b3fd 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -32,6 +32,7 @@ import { selectEnvironment as _selectEnvironment, sortCollections as _sortCollections, updateCollectionMountStatus, + moveCollection, requestCancelled, resetRunResults, responseReceived, @@ -1151,6 +1152,22 @@ export const importCollection = (collection, collectionLocation) => (dispatch, g }); }; +export const moveCollectionAndPersist = ({ draggedItem, targetItem }) => (dispatch, getState) => { + dispatch(moveCollection({ draggedItem, targetItem })); + + return new Promise((resolve, reject) => { + const { ipcRenderer } = window; + const state = getState(); + + const collectionPaths = state.collections.collections.map((collection) => collection.pathname); + + ipcRenderer + .invoke('renderer:update-collection-paths', collectionPaths) + .then(resolve) + .catch(reject); + }); +}; + export const saveCollectionSecurityConfig = (collectionUid, securityConfig) => (dispatch, getState) => { return new Promise((resolve, reject) => { const { ipcRenderer } = window; 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 3ae0fa4e5..3fe805aed 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -1,5 +1,5 @@ import { uuid } from 'utils/common'; -import { find, map, forOwn, concat, filter, each, cloneDeep, get, set } from 'lodash'; +import { find, map, forOwn, concat, filter, each, cloneDeep, get, set, findIndex } from 'lodash'; import { createSlice } from '@reduxjs/toolkit'; import { addDepth, @@ -100,6 +100,12 @@ export const collectionsSlice = createSlice({ break; } }, + moveCollection: (state, action) => { + const { draggedItem, targetItem } = action.payload; + state.collections = state.collections.filter((i) => i.uid !== draggedItem.uid); // Remove dragged item + const targetItemIndex = state.collections.findIndex((i) => i.uid === targetItem.uid); // Find target item + state.collections.splice(targetItemIndex, 0, draggedItem); // Insert dragged-item above target-item + }, updateLastAction: (state, action) => { const { collectionUid, lastAction } = action.payload; const collection = findCollectionByUid(state.collections, collectionUid); @@ -2082,7 +2088,8 @@ export const { runFolderEvent, resetCollectionRunner, updateRequestDocs, - updateFolderDocs + updateFolderDocs, + moveCollection } = collectionsSlice.actions; export default collectionsSlice.reducer; diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js index eb53cfb48..e119553e4 100644 --- a/packages/bruno-app/src/utils/collections/index.js +++ b/packages/bruno-app/src/utils/collections/index.js @@ -1,13 +1,4 @@ -import get from 'lodash/get'; -import each from 'lodash/each'; -import find from 'lodash/find'; -import findIndex from 'lodash/findIndex'; -import isString from 'lodash/isString'; -import map from 'lodash/map'; -import filter from 'lodash/filter'; -import sortBy from 'lodash/sortBy'; -import isEqual from 'lodash/isEqual'; -import cloneDeep from 'lodash/cloneDeep'; +import {cloneDeep, isEqual, sortBy, filter, map, isString, findIndex, find, each, get } from 'lodash'; import { uuid } from 'utils/common'; import path from 'path'; import slash from 'utils/common/slash'; diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js index 89138f090..27a34d861 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -516,6 +516,10 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection } }); + ipcMain.handle('renderer:update-collection-paths', async (_, collectionPaths) => { + lastOpenedCollections.update(collectionPaths); + }) + ipcMain.handle('renderer:import-collection', async (event, collection, collectionLocation) => { try { let collectionName = sanitizeDirectoryName(collection.name); diff --git a/packages/bruno-electron/src/store/last-opened-collections.js b/packages/bruno-electron/src/store/last-opened-collections.js index 546b73b57..72452eef3 100644 --- a/packages/bruno-electron/src/store/last-opened-collections.js +++ b/packages/bruno-electron/src/store/last-opened-collections.js @@ -16,18 +16,20 @@ class LastOpenedCollections { } add(collectionPath) { - const collections = this.store.get('lastOpenedCollections') || []; + const collections = this.getAll(); - if (isDirectory(collectionPath)) { - if (!collections.includes(collectionPath)) { - collections.push(collectionPath); - this.store.set('lastOpenedCollections', collections); - } + if (isDirectory(collectionPath) && !collections.includes(collectionPath)) { + collections.push(collectionPath); + this.store.set('lastOpenedCollections', collections); } } + update(collectionPaths) { + this.store.set('lastOpenedCollections', collectionPaths); + } + remove(collectionPath) { - let collections = this.store.get('lastOpenedCollections') || []; + let collections = this.getAll(); if (collections.includes(collectionPath)) { collections = _.filter(collections, (c) => c !== collectionPath); @@ -36,7 +38,7 @@ class LastOpenedCollections { } removeAll() { - return this.store.set('lastOpenedCollections', []); + this.store.set('lastOpenedCollections', []); } } From 8810b9e2918ed569da16fc6b84f7433e832b815a Mon Sep 17 00:00:00 2001 From: lohxt1 Date: Mon, 10 Feb 2025 21:03:51 +0530 Subject: [PATCH 08/36] fix graphql variables editor and tests editor height --- package-lock.json | 13 +++++++++- .../RequestPane/GraphQLRequestPane/index.js | 2 +- .../RequestPane/GraphQLVariables/index.js | 4 +-- .../RequestPane/Tests/StyledWrapper.js | 10 -------- .../src/components/RequestPane/Tests/index.js | 25 ++++++++----------- 5 files changed, 26 insertions(+), 28 deletions(-) delete mode 100644 packages/bruno-app/src/components/RequestPane/Tests/StyledWrapper.js diff --git a/package-lock.json b/package-lock.json index a3af1292f..42cf6a343 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,6 +50,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -786,6 +787,7 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -816,6 +818,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -833,6 +836,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, "node_modules/@babel/generator": { @@ -1112,6 +1116,7 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.25.9", @@ -7078,6 +7083,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, "license": "MIT" }, "node_modules/@types/lodash": { @@ -7090,6 +7096,7 @@ "version": "12.2.3", "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dev": true, "license": "MIT", "dependencies": { "@types/linkify-it": "*", @@ -7100,6 +7107,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, "license": "MIT" }, "node_modules/@types/ms": { @@ -10329,6 +10337,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -11930,6 +11939,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -12963,6 +12973,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -23534,7 +23545,7 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/index.js b/packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/index.js index 187a91a68..07dcf1419 100644 --- a/packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/index.js +++ b/packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/index.js @@ -154,7 +154,7 @@ const GraphQLRequestPane = ({ item, collection, leftPaneWidth, onSchemaLoad, tog
-
{getTabPanel(focusedTab.requestPaneTab)}
+
{getTabPanel(focusedTab.requestPaneTab)}
); }; diff --git a/packages/bruno-app/src/components/RequestPane/GraphQLVariables/index.js b/packages/bruno-app/src/components/RequestPane/GraphQLVariables/index.js index 91fea0134..eaac6f204 100644 --- a/packages/bruno-app/src/components/RequestPane/GraphQLVariables/index.js +++ b/packages/bruno-app/src/components/RequestPane/GraphQLVariables/index.js @@ -49,7 +49,7 @@ const GraphQLVariables = ({ variables, item, collection }) => { const onSave = () => dispatch(saveRequest(item.uid, collection.uid)); return ( - + <>
) : ( diff --git a/packages/bruno-electron/src/index.js b/packages/bruno-electron/src/index.js index 4b6494b2f..0cb75645d 100644 --- a/packages/bruno-electron/src/index.js +++ b/packages/bruno-electron/src/index.js @@ -33,6 +33,7 @@ const contentSecurityPolicy = [ "script-src * 'unsafe-inline' 'unsafe-eval'", "connect-src * 'unsafe-inline'", "font-src 'self' https:", + "frame-src data:", // this has been commented out to make oauth2 work // "form-action 'none'", // we make an exception and allow http for images so that From e0750148e673998db7638af762d415f900a33eaf Mon Sep 17 00:00:00 2001 From: sreelakshmi-bruno Date: Fri, 14 Feb 2025 02:42:14 +0530 Subject: [PATCH 20/36] Styling improvements in failed-load-request summary (#3956) Co-authored-by: Sreelakshmi Jayarajan --- .../RequestTabPanel/RequestNotLoaded/index.js | 44 ++++++++----------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/packages/bruno-app/src/components/RequestTabPanel/RequestNotLoaded/index.js b/packages/bruno-app/src/components/RequestTabPanel/RequestNotLoaded/index.js index 1a951b624..289f3c879 100644 --- a/packages/bruno-app/src/components/RequestTabPanel/RequestNotLoaded/index.js +++ b/packages/bruno-app/src/components/RequestTabPanel/RequestNotLoaded/index.js @@ -1,4 +1,4 @@ -import { IconLoader2, IconFile } from '@tabler/icons'; +import { IconLoader2, IconFile, IconAlertTriangle } from '@tabler/icons'; import { loadRequest, loadRequestViaWorker } from 'providers/ReduxStore/slices/collections/actions'; import { useDispatch } from 'react-redux'; import StyledWrapper from './StyledWrapper'; @@ -15,7 +15,7 @@ const RequestNotLoaded = ({ collection, item }) => { return
-
+
@@ -39,36 +39,30 @@ const RequestNotLoaded = ({ collection, item }) => {
{!item?.error && ( - <> -
-
- Due to its large size, this request wasn't loaded automatically. +
+
+ + The request wasn't loaded due to its large size. Please try again with the following options:
-
-
- - - May cause the app to freeze temporarily while it runs. - -
-
+
- - Runs in background. - -
+

(Runs in background)

- +
+ +

(May cause the app to freeze temporarily while it runs)

+
+
)} {item?.loading && ( From 81930f6fe63e146167d971198001ca03f92f83c4 Mon Sep 17 00:00:00 2001 From: naman-bruno Date: Mon, 3 Feb 2025 15:35:48 +0530 Subject: [PATCH 21/36] Fix: Import collection failed for postman custom method --- .../bruno-app/src/utils/importers/postman-collection.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/bruno-app/src/utils/importers/postman-collection.js b/packages/bruno-app/src/utils/importers/postman-collection.js index 89ab15c7e..e4acd9ba6 100644 --- a/packages/bruno-app/src/utils/importers/postman-collection.js +++ b/packages/bruno-app/src/utils/importers/postman-collection.js @@ -181,6 +181,7 @@ const importPostmanV2CollectionItem = (brunoParent, item, parentAuth, options) = brunoParent.items = brunoParent.items || []; const folderMap = {}; const requestMap = {}; + const requestMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS', 'TRACE'] each(item, (i) => { if (isItemAFolder(i)) { @@ -230,6 +231,11 @@ const importPostmanV2CollectionItem = (brunoParent, item, parentAuth, options) = } else { if (i.request) { + if(!requestMethods.includes(i?.request?.method.toUpperCase())){ + console.warn("Unexpected request.method") + return; + } + const baseRequestName = i.name; let requestName = baseRequestName; let count = 1; From 3b8a613914163824a2f9a78c8198130d7e5bfff3 Mon Sep 17 00:00:00 2001 From: ramki-bruno Date: Wed, 12 Feb 2025 18:58:30 +0530 Subject: [PATCH 22/36] Refactor ToolHint to use `text` prop as text instead of HTML Currently there is no usage of ToolHint where we are passing HTML content, so this should not break anything. --- packages/bruno-app/src/components/ToolHint/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bruno-app/src/components/ToolHint/index.js b/packages/bruno-app/src/components/ToolHint/index.js index b8799dd69..3d559625e 100644 --- a/packages/bruno-app/src/components/ToolHint/index.js +++ b/packages/bruno-app/src/components/ToolHint/index.js @@ -34,7 +34,7 @@ const ToolHint = ({ Date: Wed, 12 Feb 2025 20:41:56 +0530 Subject: [PATCH 23/36] Refactoring InfoTip to support just text and children instead of HTML --- .../CollectionSettings/ProxySettings/index.js | 13 +++++-------- .../CollectionSettings/Vars/VarsTable/index.js | 2 +- .../FolderSettings/Vars/VarsTable/index.js | 2 +- packages/bruno-app/src/components/InfoTip/index.js | 4 ++-- .../src/components/RequestPane/QueryParams/index.js | 7 ++----- .../components/RequestPane/Vars/VarsTable/index.js | 2 +- .../Collections/Collection/CloneCollection/index.js | 2 +- .../components/Sidebar/CreateCollection/index.js | 2 +- 8 files changed, 14 insertions(+), 20 deletions(-) diff --git a/packages/bruno-app/src/components/CollectionSettings/ProxySettings/index.js b/packages/bruno-app/src/components/CollectionSettings/ProxySettings/index.js index 105a92642..bb48cbdc0 100644 --- a/packages/bruno-app/src/components/CollectionSettings/ProxySettings/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/ProxySettings/index.js @@ -104,18 +104,15 @@ const ProxySettings = ({ proxyConfig, onUpdate }) => {