From 4258e031c66ee6591c0cfacadada0a2fd6c33199 Mon Sep 17 00:00:00 2001 From: Max Wittig Date: Mon, 16 Oct 2023 14:05:44 +0200 Subject: [PATCH 01/21] docs(readme): add simple installation instructions Many people just want to know how to get it directly from the Github readme --- readme.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/readme.md b/readme.md index 8021a5b7a..006191f5b 100644 --- a/readme.md +++ b/readme.md @@ -22,6 +22,14 @@ Bruno is offline-only. There are no plans to add cloud-sync to Bruno, ever. We v ![bruno](assets/images/landing-2.png)

+### Installation + +Bruno is available as binary download [on our website](https://www.usebruno.com/downloads) or via homebrew + +```sh +brew install bruno +``` + ### Run across multiple platforms 🖥️ ![bruno](assets/images/run-anywhere.png)

From e4b2b651f54cbe74bb564a649198dca2733b2930 Mon Sep 17 00:00:00 2001 From: Makar Date: Thu, 26 Oct 2023 13:23:43 -0500 Subject: [PATCH 02/21] Auth support for postman collection imports --- .../src/utils/importers/postman-collection.js | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/packages/bruno-app/src/utils/importers/postman-collection.js b/packages/bruno-app/src/utils/importers/postman-collection.js index bc7f475e6..25116446c 100644 --- a/packages/bruno-app/src/utils/importers/postman-collection.js +++ b/packages/bruno-app/src/utils/importers/postman-collection.js @@ -18,7 +18,14 @@ const isItemAFolder = (item) => { return !item.request; }; -const importPostmanV2CollectionItem = (brunoParent, item) => { +const convertV21Auth = (array) => { + return array.reduce((accumulator, currentValue) => { + accumulator[currentValue.key] = currentValue.value; + return accumulator; + }, {}); +}; + +const importPostmanV2CollectionItem = (brunoParent, item, parentAuth) => { brunoParent.items = brunoParent.items || []; each(item, (i) => { @@ -31,7 +38,7 @@ const importPostmanV2CollectionItem = (brunoParent, item) => { }; brunoParent.items.push(brunoFolderItem); if (i.item && i.item.length) { - importPostmanV2CollectionItem(brunoFolderItem, i.item); + importPostmanV2CollectionItem(brunoFolderItem, i.item, i.auth ?? parentAuth); } } else { if (i.request) { @@ -49,6 +56,12 @@ const importPostmanV2CollectionItem = (brunoParent, item) => { request: { url: url, method: i.request.method, + auth: { + mode: 'none', + basic: null, + bearer: null, + awsv4: null + }, headers: [], params: [], body: { @@ -143,6 +156,36 @@ const importPostmanV2CollectionItem = (brunoParent, item) => { }); }); + const auth = i.request.auth ?? parentAuth; + if (auth?.[auth.type] && auth.type !== 'noauth') { + let authValues = auth[auth.type]; + if (Array.isArray(authValues)) { + authValues = convertV21Auth(authValues); + } + if (auth.type === 'basic') { + brunoRequestItem.request.auth.mode = 'basic'; + brunoRequestItem.request.auth.basic = { + username: authValues.username, + password: authValues.password + }; + } else if (auth.type === 'bearer') { + brunoRequestItem.request.auth.mode = 'bearer'; + brunoRequestItem.request.auth.bearer = { + token: authValues.token + }; + } else if (auth.type === 'awsv4') { + brunoRequestItem.request.auth.mode = 'awsv4'; + brunoRequestItem.request.auth.awsv4 = { + accessKeyId: authValues.accessKey, + secretAccessKey: authValues.secretKey, + sessionToken: authValues.sessionToken, + service: authValues.service, + region: authValues.region, + profileName: '' + }; + } + } + each(get(i, 'request.url.query'), (param) => { brunoRequestItem.request.params.push({ uid: uuid(), @@ -183,7 +226,7 @@ const importPostmanV2Collection = (collection) => { environments: [] }; - importPostmanV2CollectionItem(brunoCollection, collection.item); + importPostmanV2CollectionItem(brunoCollection, collection.item, collection.auth); return brunoCollection; }; From 5df9981e20f5df0a6a3497a963365181d77ce201 Mon Sep 17 00:00:00 2001 From: Vaugen Wakeling Date: Fri, 27 Oct 2023 00:34:16 +0100 Subject: [PATCH 03/21] feat: Adding ability to import postman graphql collections Fixes: #790 --- .../src/utils/importers/postman-collection.js | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/packages/bruno-app/src/utils/importers/postman-collection.js b/packages/bruno-app/src/utils/importers/postman-collection.js index bc7f475e6..d70aac9e8 100644 --- a/packages/bruno-app/src/utils/importers/postman-collection.js +++ b/packages/bruno-app/src/utils/importers/postman-collection.js @@ -14,6 +14,56 @@ const readFile = (files) => { }); }; +/** + * + * @param {string} query + * @returns {string} + */ +const parseGraphQLQuery = (query) => { + return query + .replace(/\s+/g, ' ') + .replace(/{ /g, '{') + .replace(/ {/g, '{') + .replace(/ }/g, '}') + .replace(/, /g, ',') + .replace(/ : /g, ': ') + .replace(/\n/g, ''); +}; + +const parseGraphQLVariables = (string) => { + const cleanedString = string.replace(/[\n\t]/g, '').replace(/\\"/g, '"'); + const variables = JSON.stringify(JSON.parse(cleanedString)); + return typeof variables === 'string' ? variables : ''; +}; + +const parseGraphQLRequest = (graphqlSource) => { + try { + let queryResultObject = { + query: '', + variables: '' + }; + + if (typeof graphqlSource === 'string') { + graphqlSource = JSON.parse(text); + } + + if (graphqlSource.hasOwnProperty('variables') && graphqlSource.variables !== '') { + queryResultObject.variables = parseGraphQLVariables(graphqlSource.variables); + } + + if (graphqlSource.hasOwnProperty('query') && graphqlSource.query !== '') { + queryResultObject.query = parseGraphQLQuery(graphqlSource.query); + } + + return queryResultObject; + } catch (e) { + return { + query: '', + variables: '' + }; + } +}; + const isItemAFolder = (item) => { return !item.request; }; @@ -133,6 +183,12 @@ const importPostmanV2CollectionItem = (brunoParent, item) => { } } + if (bodyMode === 'graphql') { + brunoRequestItem.type = 'graphql-request'; + brunoRequestItem.request.body.mode = 'graphql'; + brunoRequestItem.request.body.graphql = parseGraphQLRequest(i.request.body.graphql); + } + each(i.request.header, (header) => { brunoRequestItem.request.headers.push({ uid: uuid(), From 7ac39bcf5c924c9235132e223268969e8cb90297 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Fri, 27 Oct 2023 16:18:49 +0530 Subject: [PATCH 04/21] fix(#777): fixing snap issue --- .github/workflows/release-snap.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release-snap.yml b/.github/workflows/release-snap.yml index b71e88486..16a8d2e86 100644 --- a/.github/workflows/release-snap.yml +++ b/.github/workflows/release-snap.yml @@ -30,6 +30,7 @@ jobs: run: | npm run build:bruno-query npm run build:graphql-docs + npm run build:web npm run build:electron:snap - name: Install Snapcraft From a0fe80604ec52c77d311cac438528dccee339443 Mon Sep 17 00:00:00 2001 From: Max Heidinger Date: Fri, 27 Oct 2023 14:59:09 +0200 Subject: [PATCH 05/21] fix: fix graphql schema interpolation --- packages/bruno-electron/src/ipc/network/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 7c37256e9..dfb94f3f3 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -582,6 +582,7 @@ const registerNetworkIpc = (mainWindow) => { scriptingConfig ); + interpolateVars(preparedRequest, envVars, collection.collectionVariables, processEnvVars); const axiosInstance = await configureRequest( collection.uid, preparedRequest, From 99b25fc5b2e93078351b090c4f50adf2bba1cb48 Mon Sep 17 00:00:00 2001 From: Vaugen Wakeling Date: Fri, 27 Oct 2023 17:21:16 +0100 Subject: [PATCH 06/21] feat: Remove unneeded formatting --- .../src/utils/importers/postman-collection.js | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/packages/bruno-app/src/utils/importers/postman-collection.js b/packages/bruno-app/src/utils/importers/postman-collection.js index d70aac9e8..eceafac20 100644 --- a/packages/bruno-app/src/utils/importers/postman-collection.js +++ b/packages/bruno-app/src/utils/importers/postman-collection.js @@ -14,28 +14,6 @@ const readFile = (files) => { }); }; -/** - * - * @param {string} query - * @returns {string} - */ -const parseGraphQLQuery = (query) => { - return query - .replace(/\s+/g, ' ') - .replace(/{ /g, '{') - .replace(/ {/g, '{') - .replace(/ }/g, '}') - .replace(/, /g, ',') - .replace(/ : /g, ': ') - .replace(/\n/g, ''); -}; - -const parseGraphQLVariables = (string) => { - const cleanedString = string.replace(/[\n\t]/g, '').replace(/\\"/g, '"'); - const variables = JSON.stringify(JSON.parse(cleanedString)); - return typeof variables === 'string' ? variables : ''; -}; - const parseGraphQLRequest = (graphqlSource) => { try { let queryResultObject = { @@ -48,11 +26,11 @@ const parseGraphQLRequest = (graphqlSource) => { } if (graphqlSource.hasOwnProperty('variables') && graphqlSource.variables !== '') { - queryResultObject.variables = parseGraphQLVariables(graphqlSource.variables); + queryResultObject.variables = graphqlSource.variables; } if (graphqlSource.hasOwnProperty('query') && graphqlSource.query !== '') { - queryResultObject.query = parseGraphQLQuery(graphqlSource.query); + queryResultObject.query = graphqlSource.query; } return queryResultObject; From 3f6f4ccd124b0617a233c589c08075665c26ee11 Mon Sep 17 00:00:00 2001 From: DaPutzy <9727551+DaPutzy@users.noreply.github.com> Date: Sun, 29 Oct 2023 13:04:11 +0000 Subject: [PATCH 07/21] chore: fix links and images in translated readme's --- docs/readme/readme_de.md | 10 +++++----- docs/readme/readme_fr.md | 10 +++++----- docs/readme/readme_ru.md | 8 ++++---- docs/readme/readme_tr.md | 8 ++++---- docs/readme/readme_ua.md | 8 ++++---- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/readme/readme_de.md b/docs/readme/readme_de.md index a0ef031d7..863624d1f 100644 --- a/docs/readme/readme_de.md +++ b/docs/readme/readme_de.md @@ -18,17 +18,17 @@ Du kannst Git oder eine andere Versionskontrolle deiner Wahl verwenden, um an de Bruno ist ein reines Offline-Tool. Es gibt keine Pläne, Bruno eine Cloud-Synchronisation hinzuzufügen. Wir schätzen den Schutz Deiner Daten und glauben, dass sie auf Deinem Gerät bleiben sollten. Lies unsere Langzeit-Vision [hier](https://github.com/usebruno/bruno/discussions/269). -![bruno](assets/images/landing-2.png)

+![bruno](/assets/images/landing-2.png)

### Einsatz auf verschiedensten Plattformen 🖥️ -![bruno](assets/images/run-anywhere.png)

+![bruno](/assets/images/run-anywhere.png)

### Zusammenarbeiten mit Git 👩‍💻🧑‍💻 oder eine Versionskontrolle Deiner Wahl -![bruno](assets/images/version-control.png)

+![bruno](/assets/images/version-control.png)

### Wichtige Links 📌 @@ -55,7 +55,7 @@ Wenn Bruno Dir bei Deiner Arbeit und in Deinen Teams geholfen hat, vergiss bitte ### Veröffentlichung in neuen Paketmanagern -Bitte [hier](publishing.md) für mehr Informationen lesen. +Bitte [hier](/publishing.md) für mehr Informationen lesen. ### Mitmachen 👩‍💻🧑‍💻 @@ -90,4 +90,4 @@ Das Logo stammt von [OpenMoji](https://openmoji.org/library/emoji-1F436/). Lizen ### Lizenz 📄 -[MIT](license.md) +[MIT](/license.md) diff --git a/docs/readme/readme_fr.md b/docs/readme/readme_fr.md index 97b327bfa..d16cce9a7 100644 --- a/docs/readme/readme_fr.md +++ b/docs/readme/readme_fr.md @@ -18,17 +18,17 @@ Vous pouvez utiliser git ou tout autre gestionnaire de version pour travailler d Bruno ne fonctionne qu'en mode déconnecté. Il n'y a pas de d'abonnement ou de synchronisation avec le cloud Bruno, il n'y en aura jamais. Nous sommes conscients de la confidentialité de vos données et nous sommes convaincus qu'elles doivent rester sur vos appareils. Vous pouvez lire notre vision à long terme [ici (en anglais)](https://github.com/usebruno/bruno/discussions/269). -![bruno](assets/images/landing-2.png)

+![bruno](/assets/images/landing-2.png)

### Fonctionne sur de multiples platformes 🖥️ -![bruno](assets/images/run-anywhere.png)

+![bruno](/assets/images/run-anywhere.png)

### Collaborer via Git 👩‍💻🧑‍💻 Ou n'importe quel système de gestion de sources -![bruno](assets/images/version-control.png)

+![bruno](/assets/images/version-control.png)

### Liens importants 📌 @@ -55,7 +55,7 @@ Si Bruno vous a aidé dans votre travail, au sein de votre équipe, merci de pen ### Publier Bruno sur un nouveau gestionnaire de paquets -Veuillez regarder [ici](publishing.md) pour plus d'information. +Veuillez regarder [ici](/publishing.md) pour plus d'information. ### Contribuer 👩‍💻🧑‍💻 @@ -91,4 +91,4 @@ Licence: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) ### Licence 📄 -[MIT](license.md) +[MIT](/license.md) diff --git a/docs/readme/readme_ru.md b/docs/readme/readme_ru.md index 423ab33b1..f962967e4 100644 --- a/docs/readme/readme_ru.md +++ b/docs/readme/readme_ru.md @@ -18,17 +18,17 @@ Bruno хранит ваши коллекции непосредственно в Bruno работает только в автономном режиме. Добавление облачной синхронизации в Bruno не планируется. Мы ценим конфиденциальность ваших данных и считаем, что они должны оставаться на вашем устройстве. Ознакомьтесь с нашим долгосрочным видением [здесь](https://github.com/usebruno/bruno/discussions/269) -![bruno](assets/images/landing-2.png)

+![bruno](/assets/images/landing-2.png)

### Работа на нескольких платформах 🖥️ -![bruno](assets/images/run-anywhere.png)

+![bruno](/assets/images/run-anywhere.png)

### Совместная работа через Git 👩‍💻🧑‍💻 Или другая система контроля версий по вашему выбору -![bruno](assets/images/version-control.png)

+![bruno](/assets/images/version-control.png)

### Важные ссылки 📌 @@ -74,4 +74,4 @@ Bruno работает только в автономном режиме. Доб ### Лицензия 📄 -[MIT](license.md) +[MIT](/license.md) diff --git a/docs/readme/readme_tr.md b/docs/readme/readme_tr.md index 74bd8aa50..c68609ec1 100644 --- a/docs/readme/readme_tr.md +++ b/docs/readme/readme_tr.md @@ -18,17 +18,17 @@ API koleksiyonlarınız üzerinde işbirliği yapmak için git veya seçtiğiniz Bruno yalnızca çevrimdışıdır. Bruno'ya bulut senkronizasyonu eklemek gibi bir planımız yok. Veri gizliliğinize değer veriyoruz ve cihazınızda kalması gerektiğine inanıyoruz. Uzun vadeli vizyonumuzu okuyun [burada](https://github.com/usebruno/bruno/discussions/269) -![bruno](assets/images/landing-2.png)

+![bruno](/assets/images/landing-2.png)

### Birden fazla platformda çalıştırın 🖥️ -![bruno](assets/images/run-anywhere.png)

+![bruno](/assets/images/run-anywhere.png)

### Git üzerinden işbirliği yapın 👩‍💻🧑‍💻 Veya seçtiğiniz herhangi bir sürüm kontrol sistemi -![bruno](assets/images/version-control.png)

+![bruno](/assets/images/version-control.png)

### Önemli Bağlantılar 📌 @@ -75,4 +75,4 @@ Kod yoluyla katkıda bulunamasanız bile, lütfen kullanım durumunuzu çözmek ### Lisans 📄 -[MIT](license.md) +[MIT](/license.md) diff --git a/docs/readme/readme_ua.md b/docs/readme/readme_ua.md index 9b0eb7a0f..eb4a8522f 100644 --- a/docs/readme/readme_ua.md +++ b/docs/readme/readme_ua.md @@ -18,17 +18,17 @@ Bruno зберігає ваші колекції напряму у теці на Bruno є повністю автономним. Немає жодних планів додавати будь-які синхронізації через хмару, ніколи. Ми цінуємо приватність ваших даних, і вважаєм, що вони мають залишитись лише на вашому комп'ютері. Взнати більше про наше бачення у довготривалій перспективі можна [тут](https://github.com/usebruno/bruno/discussions/269) -![bruno](assets/images/landing-2.png)

+![bruno](/assets/images/landing-2.png)

### Кросплатформенність 🖥️ -![bruno](assets/images/run-anywhere.png)

+![bruno](/assets/images/run-anywhere.png)

### Спільна робота через Git 👩‍💻🧑‍💻 Або будь-яку іншу систему контролю версій на ваш вибір -![bruno](assets/images/version-control.png)

+![bruno](/assets/images/version-control.png)

### Важливі посилання 📌 @@ -75,4 +75,4 @@ Bruno є повністю автономним. Немає жодних план ### Ліцензія 📄 -[MIT](license.md) +[MIT](/license.md) From 65f688dbc20c9506a8fc9360fe03f41695ff741c Mon Sep 17 00:00:00 2001 From: DaPutzy <9727551+DaPutzy@users.noreply.github.com> Date: Sun, 29 Oct 2023 13:49:44 +0000 Subject: [PATCH 08/21] chrore: fix logo's in translated readme's --- docs/readme/readme_de.md | 2 +- docs/readme/readme_fr.md | 2 +- docs/readme/readme_ru.md | 2 +- docs/readme/readme_tr.md | 2 +- docs/readme/readme_ua.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/readme/readme_de.md b/docs/readme/readme_de.md index 863624d1f..371672b4c 100644 --- a/docs/readme/readme_de.md +++ b/docs/readme/readme_de.md @@ -1,5 +1,5 @@
- + ### Bruno - Opensource IDE zum Erkunden und Testen von APIs. diff --git a/docs/readme/readme_fr.md b/docs/readme/readme_fr.md index d16cce9a7..9c3fdd6cd 100644 --- a/docs/readme/readme_fr.md +++ b/docs/readme/readme_fr.md @@ -1,5 +1,5 @@
- + ### Bruno - IDE Opensource pour explorer et tester des APIs. diff --git a/docs/readme/readme_ru.md b/docs/readme/readme_ru.md index f962967e4..ddbe8135c 100644 --- a/docs/readme/readme_ru.md +++ b/docs/readme/readme_ru.md @@ -1,5 +1,5 @@
- + ### Bruno - IDE с открытым исходным кодом для изучения и тестирования API. diff --git a/docs/readme/readme_tr.md b/docs/readme/readme_tr.md index c68609ec1..b04738505 100644 --- a/docs/readme/readme_tr.md +++ b/docs/readme/readme_tr.md @@ -1,5 +1,5 @@
- + ### Bruno - API'leri keşfetmek ve test etmek için açık kaynaklı IDE. diff --git a/docs/readme/readme_ua.md b/docs/readme/readme_ua.md index eb4a8522f..cb0ccb9ee 100644 --- a/docs/readme/readme_ua.md +++ b/docs/readme/readme_ua.md @@ -1,5 +1,5 @@
- + ### Bruno - IDE із відкритим кодом для тестування та дослідження API From 32d9c4833e46aa93b9e027679bf4a9219039914b Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Mon, 30 Oct 2023 23:33:29 +0530 Subject: [PATCH 09/21] chore: bump version to 1.0.0 --- packages/bruno-app/src/components/Sidebar/index.js | 2 +- packages/bruno-electron/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/bruno-app/src/components/Sidebar/index.js b/packages/bruno-app/src/components/Sidebar/index.js index a6df7141c..ae15b8c07 100644 --- a/packages/bruno-app/src/components/Sidebar/index.js +++ b/packages/bruno-app/src/components/Sidebar/index.js @@ -105,7 +105,7 @@ const Sidebar = () => { Star -
v0.27.2
+
v1.0.0
diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json index 47753da5a..cb3a81c37 100644 --- a/packages/bruno-electron/package.json +++ b/packages/bruno-electron/package.json @@ -1,5 +1,5 @@ { - "version": "v0.27.2", + "version": "v1.0.0", "name": "bruno", "description": "Opensource API Client for Exploring and Testing APIs", "homepage": "https://www.usebruno.com", From aac4a33c92396934dc92fc08725490a5e70ba1a7 Mon Sep 17 00:00:00 2001 From: HardikBandhiya Date: Tue, 31 Oct 2023 01:59:43 +0530 Subject: [PATCH 10/21] Update readme.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit changed Twitter's old name to new 𝕏 --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 1486ad25d..339e72abc 100644 --- a/readme.md +++ b/readme.md @@ -75,7 +75,7 @@ Even if you are not able to make contributions via code, please don't hesitate t ### Stay in touch 🌐 -[Twitter](https://twitter.com/use_bruno)
+[𝕏 (Twitter)](https://twitter.com/use_bruno)
[Website](https://www.usebruno.com)
[Discord](https://discord.com/invite/KgcZUncpjq)
[LinkedIn](https://www.linkedin.com/company/usebruno) From 745cb85f9561f6dc04a26db57fa5fc62893698e6 Mon Sep 17 00:00:00 2001 From: Martin Sefcik Date: Mon, 30 Oct 2023 23:43:44 +0100 Subject: [PATCH 11/21] fix (#680): fixed defined non-string variables to be displayed correctly in code editor --- packages/bruno-app/src/utils/common/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bruno-app/src/utils/common/codemirror.js b/packages/bruno-app/src/utils/common/codemirror.js index 78016de6f..6074dbdcf 100644 --- a/packages/bruno-app/src/utils/common/codemirror.js +++ b/packages/bruno-app/src/utils/common/codemirror.js @@ -10,7 +10,7 @@ if (!SERVER_RENDERED) { const pathFoundInVariables = (path, obj) => { const value = get(obj, path); - return isString(value); + return value !== undefined; }; export const defineCodeMirrorBrunoVariablesMode = (variables, mode) => { From 31ecc281a8332cf845f8199ed0501ca2bf3ea02c Mon Sep 17 00:00:00 2001 From: n00o Date: Mon, 30 Oct 2023 20:10:36 -0400 Subject: [PATCH 12/21] Fix response/body cursor offset on resize Now response/body will be refresh each time it gets resized so the cursor always stays in the right place. --- packages/bruno-app/src/components/CodeEditor/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/bruno-app/src/components/CodeEditor/index.js b/packages/bruno-app/src/components/CodeEditor/index.js index b1a115c9e..5750d41e1 100644 --- a/packages/bruno-app/src/components/CodeEditor/index.js +++ b/packages/bruno-app/src/components/CodeEditor/index.js @@ -146,6 +146,9 @@ export default class CodeEditor extends React.Component { } render() { + if (this.editor) { + this.editor.refresh() + } return ( Date: Mon, 30 Oct 2023 20:59:40 -0400 Subject: [PATCH 13/21] Update index.js Pass prettier test. --- packages/bruno-app/src/components/CodeEditor/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bruno-app/src/components/CodeEditor/index.js b/packages/bruno-app/src/components/CodeEditor/index.js index 5750d41e1..0bfd6fdd3 100644 --- a/packages/bruno-app/src/components/CodeEditor/index.js +++ b/packages/bruno-app/src/components/CodeEditor/index.js @@ -147,7 +147,7 @@ export default class CodeEditor extends React.Component { render() { if (this.editor) { - this.editor.refresh() + this.editor.refresh(); } return ( Date: Tue, 31 Oct 2023 09:49:38 +0530 Subject: [PATCH 14/21] capitalize git to Git for clarity --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 1486ad25d..0429264c9 100644 --- a/readme.md +++ b/readme.md @@ -16,7 +16,7 @@ Bruno is a new and innovative API client, aimed at revolutionizing the status qu Bruno stores your collections directly in a folder on your filesystem. We use a plain text markup language, Bru, to save information about API requests. -You can use git or any version control of your choice to collaborate over your API collections. +You can use Git or any version control of your choice to collaborate over your API collections. Bruno is offline-only. There are no plans to add cloud-sync to Bruno, ever. We value your data privacy and believe it should stay on your device. Read our long-term vision [here](https://github.com/usebruno/bruno/discussions/269) From bbcab8d33860dd71813190afe396eb65e4c74e96 Mon Sep 17 00:00:00 2001 From: Dipin Jagadish Date: Tue, 31 Oct 2023 19:32:31 +0000 Subject: [PATCH 15/21] feat: add new request from curl feature --- package-lock.json | 28 +++++ packages/bruno-app/package.json | 1 + .../components/Sidebar/NewRequest/index.js | 111 +++++++++++++----- .../ReduxStore/slices/collections/actions.js | 6 +- packages/bruno-app/src/utils/curl/index.js | 65 ++++++++++ 5 files changed, 177 insertions(+), 34 deletions(-) create mode 100644 packages/bruno-app/src/utils/curl/index.js diff --git a/package-lock.json b/package-lock.json index 79f3de50f..cf7a7d95f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12178,6 +12178,14 @@ "xml2js": "^0.4.5" } }, + "node_modules/parse-curl": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/parse-curl/-/parse-curl-0.2.6.tgz", + "integrity": "sha512-ENhXeIxG4A6wFvYSU87b0o3Tp6U+Wup069GYhXCn0ZP/E7evfvomTSM/MeEOs3QTyuye+u2r7fFRj6nX0q9kQA==", + "dependencies": { + "shellwords": "^0.1.0" + } + }, "node_modules/parse-headers": { "version": "2.0.5", "dev": true, @@ -14515,6 +14523,11 @@ "node": ">=8" } }, + "node_modules/shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==" + }, "node_modules/side-channel": { "version": "1.0.4", "license": "MIT", @@ -16470,6 +16483,7 @@ "mousetrap": "^1.6.5", "nanoid": "3.3.4", "next": "12.3.3", + "parse-curl": "^0.2.6", "path": "^0.12.7", "platform": "^1.3.6", "posthog-node": "^2.1.0", @@ -20540,6 +20554,7 @@ "mousetrap": "^1.6.5", "nanoid": "3.3.4", "next": "12.3.3", + "parse-curl": "*", "path": "^0.12.7", "platform": "^1.3.6", "posthog-node": "^2.1.0", @@ -25603,6 +25618,14 @@ "xml2js": "^0.4.5" } }, + "parse-curl": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/parse-curl/-/parse-curl-0.2.6.tgz", + "integrity": "sha512-ENhXeIxG4A6wFvYSU87b0o3Tp6U+Wup069GYhXCn0ZP/E7evfvomTSM/MeEOs3QTyuye+u2r7fFRj6nX0q9kQA==", + "requires": { + "shellwords": "^0.1.0" + } + }, "parse-headers": { "version": "2.0.5", "dev": true @@ -27036,6 +27059,11 @@ "version": "3.0.0", "dev": true }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==" + }, "side-channel": { "version": "1.0.4", "requires": { diff --git a/packages/bruno-app/package.json b/packages/bruno-app/package.json index c3f82569f..77ff96b67 100644 --- a/packages/bruno-app/package.json +++ b/packages/bruno-app/package.json @@ -42,6 +42,7 @@ "mousetrap": "^1.6.5", "nanoid": "3.3.4", "next": "12.3.3", + "parse-curl": "^0.2.6", "path": "^0.12.7", "platform": "^1.3.6", "posthog-node": "^2.1.0", diff --git a/packages/bruno-app/src/components/Sidebar/NewRequest/index.js b/packages/bruno-app/src/components/Sidebar/NewRequest/index.js index 2e54b56ad..1476a7de8 100644 --- a/packages/bruno-app/src/components/Sidebar/NewRequest/index.js +++ b/packages/bruno-app/src/components/Sidebar/NewRequest/index.js @@ -11,6 +11,7 @@ import { addTab } from 'providers/ReduxStore/slices/tabs'; import HttpMethodSelector from 'components/RequestPane/QueryUrl/HttpMethodSelector'; import { getDefaultRequestPaneTab } from 'utils/collections'; import StyledWrapper from './StyledWrapper'; +import { getRequestFromCurlCommand } from 'utils/curl'; const NewRequest = ({ collection, item, isEphemeral, onClose }) => { const dispatch = useDispatch(); @@ -21,7 +22,8 @@ const NewRequest = ({ collection, item, isEphemeral, onClose }) => { requestName: '', requestType: 'http-request', requestUrl: '', - requestMethod: 'GET' + requestMethod: 'GET', + curlCommand: '' }, validationSchema: Yup.object({ requestName: Yup.string() @@ -61,6 +63,23 @@ const NewRequest = ({ collection, item, isEphemeral, onClose }) => { onClose(); }) .catch((err) => toast.error(err ? err.message : 'An error occurred while adding the request')); + } else if (values.requestType === 'from-curl') { + getRequestFromCurlCommand(values.curlCommand).then((request) => + dispatch( + newHttpRequest({ + requestName: values.requestName, + requestType: 'http-request', + requestUrl: request.url, + requestMethod: request.method, + collectionUid: collection.uid, + itemUid: item ? item.uid : null, + headers: request.headers, + body: request.body + }) + ) + .then(() => onClose()) + .catch((err) => toast.error(err ? err.message : 'An error occurred while adding the request')) + ); } else { dispatch( newHttpRequest({ @@ -124,9 +143,22 @@ const NewRequest = ({ collection, item, isEphemeral, onClose }) => { + + + + -
+ {formik.values.requestType !== 'from-curl' ? ( + <> +
+ -
- - -
-
- formik.setFieldValue('requestMethod', val)} - /> -
-
- +
+
+ formik.setFieldValue('requestMethod', val)} + /> +
+
+ +
+
+ {formik.touched.requestUrl && formik.errors.requestUrl ? ( +
{formik.errors.requestUrl}
+ ) : null}
+ + ) : ( +
+ +
- {formik.touched.requestUrl && formik.errors.requestUrl ? ( -
{formik.errors.requestUrl}
- ) : null} -
+ )} 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 20a68b80e..2ef107954 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -568,7 +568,7 @@ export const moveItemToRootOfCollection = (collectionUid, draggedItemUid) => (di }; export const newHttpRequest = (params) => (dispatch, getState) => { - const { requestName, requestType, requestUrl, requestMethod, collectionUid, itemUid } = params; + const { requestName, requestType, requestUrl, requestMethod, collectionUid, itemUid, headers, body } = params; return new Promise((resolve, reject) => { const state = getState(); @@ -591,9 +591,9 @@ export const newHttpRequest = (params) => (dispatch, getState) => { request: { method: requestMethod, url: requestUrl, - headers: [], + headers: headers ?? [], params, - body: { + body: body ?? { mode: 'none', json: null, text: null, diff --git a/packages/bruno-app/src/utils/curl/index.js b/packages/bruno-app/src/utils/curl/index.js new file mode 100644 index 000000000..37282f09c --- /dev/null +++ b/packages/bruno-app/src/utils/curl/index.js @@ -0,0 +1,65 @@ +import * as parse from 'parse-curl'; +import { BrunoError } from 'utils/common/error'; +import { parseQueryParams } from 'utils/url'; + +export const getRequestFromCurlCommand = (command) => { + const parseFormData = (parsedBody) => { + parseQueryParams(parsedBody); + }; + return new Promise((resolve, reject) => { + try { + const request = parse(command); + const parsedHeader = request?.header; + const headers = + parsedHeader && + Object.keys(parsedHeader).map((key) => ({ name: key, value: parsedHeader[key], enabled: true })); + + const contentType = headers?.find((h) => h.name.toLowerCase() === 'content-type'); + const body = { + mode: 'none', + json: null, + text: null, + xml: null, + sparql: null, + multipartForm: null, + formUrlEncoded: null + }; + const parsedBody = request?.body; + if (parsedBody && contentType) { + switch (contentType.value.toLowerCase()) { + case 'application/json': + body.mode = 'json'; + body.json = parsedBody; + break; + case 'text/xml': + body.mode = 'xml'; + body.xml = parsedBody; + break; + case 'application/x-www-form-urlencoded': + body.mode = 'formUrlEncoded'; + body.formUrlEncoded = parseFormData(parsedBody); + break; + case 'multipart/form-data': + body.mode = 'multipartForm'; + body.multipartForm = parsedBody; + break; + case 'text/plain': + default: + body.mode = 'text'; + body.text = parsedBody; + break; + } + } + debugger; + console.log(request); + return resolve({ + url: request.url, + method: request.method, + body, + headers: headers + }); + } catch (error) { + return reject(new BrunoError('Unable to parse the cURL command')); + } + }); +}; From 89e0d3ae7edaabb8139ed643920dd11d1bb95f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linhart=20Luk=C3=A1=C5=A1?= Date: Wed, 1 Nov 2023 07:05:05 +0100 Subject: [PATCH 16/21] Fix Multipart Form --- packages/bruno-electron/src/ipc/network/prepare-request.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index 6e3f123c1..d38849f69 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -1,5 +1,6 @@ -const { get, each, filter } = require('lodash'); +const { get, each, filter, forOwn, extend } = require('lodash'); const decomment = require('decomment'); +const FormData = require('form-data'); // Authentication // A request can override the collection auth with another auth From 49f29fa2afede3f917d398259cc0152aefb43f58 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Wed, 1 Nov 2023 14:36:28 +0530 Subject: [PATCH 17/21] fix(#836): Fix graphql blank screen issue --- .../components/RequestPane/GraphQLSchemaActions/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/bruno-app/src/components/RequestPane/GraphQLSchemaActions/index.js b/packages/bruno-app/src/components/RequestPane/GraphQLSchemaActions/index.js index 954efebf7..01ce6f320 100644 --- a/packages/bruno-app/src/components/RequestPane/GraphQLSchemaActions/index.js +++ b/packages/bruno-app/src/components/RequestPane/GraphQLSchemaActions/index.js @@ -1,6 +1,6 @@ import React, { useEffect, useRef, forwardRef } from 'react'; import useGraphqlSchema from './useGraphqlSchema'; -import { IconBook, IconDownload, IconLoader2, IconCheckmark } from '@tabler/icons'; +import { IconBook, IconDownload, IconLoader2, IconRefresh } from '@tabler/icons'; import get from 'lodash/get'; import { findEnvironmentInCollection } from 'utils/collections'; import Dropdown from '../../Dropdown'; @@ -30,8 +30,8 @@ const GraphQLSchemaActions = ({ item, collection, onSchemaLoad, toggleDocs }) => return (
{isSchemaLoading && } - {!isSchemaLoading && schema && } - {!isSchemaLoading && !schema && } + {!isSchemaLoading && schema && } + {!isSchemaLoading && !schema && } Schema
); From 05bf40fa82ee01f963c85410006adac51184fa9b Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Wed, 1 Nov 2023 14:38:33 +0530 Subject: [PATCH 18/21] chore: bumped version to 1.0.1 --- packages/bruno-app/src/components/Sidebar/index.js | 2 +- packages/bruno-electron/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/bruno-app/src/components/Sidebar/index.js b/packages/bruno-app/src/components/Sidebar/index.js index ae15b8c07..69be75689 100644 --- a/packages/bruno-app/src/components/Sidebar/index.js +++ b/packages/bruno-app/src/components/Sidebar/index.js @@ -105,7 +105,7 @@ const Sidebar = () => { Star
-
v1.0.0
+
v1.0.1
diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json index cb3a81c37..5f334ac87 100644 --- a/packages/bruno-electron/package.json +++ b/packages/bruno-electron/package.json @@ -1,5 +1,5 @@ { - "version": "v1.0.0", + "version": "v1.0.1", "name": "bruno", "description": "Opensource API Client for Exploring and Testing APIs", "homepage": "https://www.usebruno.com", From dbd3ab6064298e952a726b4c344250090b7ed1ff Mon Sep 17 00:00:00 2001 From: Dipin Jagadish Date: Wed, 1 Nov 2023 10:58:07 +0000 Subject: [PATCH 19/21] fix: validate curl command before submit --- .../components/Sidebar/NewRequest/index.js | 42 +++++--- packages/bruno-app/src/utils/curl/index.js | 101 +++++++++--------- 2 files changed, 74 insertions(+), 69 deletions(-) diff --git a/packages/bruno-app/src/components/Sidebar/NewRequest/index.js b/packages/bruno-app/src/components/Sidebar/NewRequest/index.js index 1476a7de8..f6bcdfeb0 100644 --- a/packages/bruno-app/src/components/Sidebar/NewRequest/index.js +++ b/packages/bruno-app/src/components/Sidebar/NewRequest/index.js @@ -37,6 +37,14 @@ const NewRequest = ({ collection, item, isEphemeral, onClose }) => { const trimmedValue = value ? value.trim().toLowerCase() : ''; return !['collection', 'folder'].includes(trimmedValue); } + }), + curlCommand: Yup.string() + .min(1, 'must be at least 1 character') + .required('curlCommand is required') + .test({ + name: 'curlCommand', + message: `Invalid cURL Command`, + test: (value) => getRequestFromCurlCommand(value) !== null }) }), onSubmit: (values) => { @@ -64,22 +72,21 @@ const NewRequest = ({ collection, item, isEphemeral, onClose }) => { }) .catch((err) => toast.error(err ? err.message : 'An error occurred while adding the request')); } else if (values.requestType === 'from-curl') { - getRequestFromCurlCommand(values.curlCommand).then((request) => - dispatch( - newHttpRequest({ - requestName: values.requestName, - requestType: 'http-request', - requestUrl: request.url, - requestMethod: request.method, - collectionUid: collection.uid, - itemUid: item ? item.uid : null, - headers: request.headers, - body: request.body - }) - ) - .then(() => onClose()) - .catch((err) => toast.error(err ? err.message : 'An error occurred while adding the request')) - ); + const request = getRequestFromCurlCommand(values.curlCommand); + dispatch( + newHttpRequest({ + requestName: values.requestName, + requestType: 'http-request', + requestUrl: request.url, + requestMethod: request.method, + collectionUid: collection.uid, + itemUid: item ? item.uid : null, + headers: request.headers, + body: request.body + }) + ) + .then(() => onClose()) + .catch((err) => toast.error(err ? err.message : 'An error occurred while adding the request')); } else { dispatch( newHttpRequest({ @@ -227,6 +234,9 @@ const NewRequest = ({ collection, item, isEphemeral, onClose }) => { value={formik.values.curlCommand} onChange={formik.handleChange} > + {formik.touched.curlCommand && formik.errors.curlCommand ? ( +
{formik.errors.curlCommand}
+ ) : null} )} diff --git a/packages/bruno-app/src/utils/curl/index.js b/packages/bruno-app/src/utils/curl/index.js index 37282f09c..30080e467 100644 --- a/packages/bruno-app/src/utils/curl/index.js +++ b/packages/bruno-app/src/utils/curl/index.js @@ -6,60 +6,55 @@ export const getRequestFromCurlCommand = (command) => { const parseFormData = (parsedBody) => { parseQueryParams(parsedBody); }; - return new Promise((resolve, reject) => { - try { - const request = parse(command); - const parsedHeader = request?.header; - const headers = - parsedHeader && - Object.keys(parsedHeader).map((key) => ({ name: key, value: parsedHeader[key], enabled: true })); + try { + const request = parse(command); + const parsedHeader = request?.header; + const headers = + parsedHeader && Object.keys(parsedHeader).map((key) => ({ name: key, value: parsedHeader[key], enabled: true })); - const contentType = headers?.find((h) => h.name.toLowerCase() === 'content-type'); - const body = { - mode: 'none', - json: null, - text: null, - xml: null, - sparql: null, - multipartForm: null, - formUrlEncoded: null - }; - const parsedBody = request?.body; - if (parsedBody && contentType) { - switch (contentType.value.toLowerCase()) { - case 'application/json': - body.mode = 'json'; - body.json = parsedBody; - break; - case 'text/xml': - body.mode = 'xml'; - body.xml = parsedBody; - break; - case 'application/x-www-form-urlencoded': - body.mode = 'formUrlEncoded'; - body.formUrlEncoded = parseFormData(parsedBody); - break; - case 'multipart/form-data': - body.mode = 'multipartForm'; - body.multipartForm = parsedBody; - break; - case 'text/plain': - default: - body.mode = 'text'; - body.text = parsedBody; - break; - } + const contentType = headers?.find((h) => h.name.toLowerCase() === 'content-type'); + const body = { + mode: 'none', + json: null, + text: null, + xml: null, + sparql: null, + multipartForm: null, + formUrlEncoded: null + }; + const parsedBody = request?.body; + if (parsedBody && contentType) { + switch (contentType.value.toLowerCase()) { + case 'application/json': + body.mode = 'json'; + body.json = parsedBody; + break; + case 'text/xml': + body.mode = 'xml'; + body.xml = parsedBody; + break; + case 'application/x-www-form-urlencoded': + body.mode = 'formUrlEncoded'; + body.formUrlEncoded = parseFormData(parsedBody); + break; + case 'multipart/form-data': + body.mode = 'multipartForm'; + body.multipartForm = parsedBody; + break; + case 'text/plain': + default: + body.mode = 'text'; + body.text = parsedBody; + break; } - debugger; - console.log(request); - return resolve({ - url: request.url, - method: request.method, - body, - headers: headers - }); - } catch (error) { - return reject(new BrunoError('Unable to parse the cURL command')); } - }); + return { + url: request.url, + method: request.method, + body, + headers: headers + }; + } catch (error) { + return null; + } }; From cd9276f4d2b5605cfa7ed7fd639bdcc01727cf76 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Wed, 1 Nov 2023 18:23:27 +0530 Subject: [PATCH 20/21] chore: added installation instructions --- readme.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 69f78b0f2..31f50ffa5 100644 --- a/readme.md +++ b/readme.md @@ -24,10 +24,28 @@ Bruno is offline-only. There are no plans to add cloud-sync to Bruno, ever. We v ### Installation -Bruno is available as binary download [on our website](https://www.usebruno.com/downloads) or via homebrew +Bruno is available as binary download [on our website](https://www.usebruno.com/downloads) for Mac, Windows and Linux. + +You can also install Bruno via package managers like Homebrew, Chocolatey, Snap and Apt. ```sh +# On Mac via Homebrew brew install bruno + +# On Windows via Chocolatey +choco install bruno + +# On Linux via Snap +snap install bruno + +# On Linux via Apt +sudo mkdir -p /etc/apt/keyrings +sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266 + +echo "deb [signed-by=/etc/apt/keyrings/bruno.gpg] http://debian.usebruno.com/ bruno stable" | sudo tee /etc/apt/sources.list.d/bruno.list + +sudo apt update +sudo apt install bruno ``` ### Run across multiple platforms 🖥️ From 9cf8a584a094c7a59012cc4ab9759a178b179d06 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Wed, 1 Nov 2023 18:25:25 +0530 Subject: [PATCH 21/21] chore: added foss 3.0 talk link --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 31f50ffa5..96a9d7c88 100644 --- a/readme.md +++ b/readme.md @@ -20,6 +20,8 @@ You can use Git or any version control of your choice to collaborate over your A Bruno is offline-only. There are no plans to add cloud-sync to Bruno, ever. We value your data privacy and believe it should stay on your device. Read our long-term vision [here](https://github.com/usebruno/bruno/discussions/269) +📢 Watch our recent talk at India FOSS 3.0 Conference [here](https://www.youtube.com/watch?v=7bSMFpbcPiY) + ![bruno](assets/images/landing-2.png)

### Installation