Compare commits

...

774 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
7fda0fc714 Remove irrelevant keyboard shortcuts - keep only Ctrl+W and Ctrl+PageUp/Down
Co-authored-by: Pragadesh44-Bruno <172116368+Pragadesh44-Bruno@users.noreply.github.com>
2025-10-27 09:10:16 +00:00
copilot-swe-agent[bot]
c4a2d52cc9 Add keyboard shortcut pass-through for tab navigation in CodeMirror editors
Co-authored-by: Pragadesh44-Bruno <172116368+Pragadesh44-Bruno@users.noreply.github.com>
2025-10-27 08:50:31 +00:00
copilot-swe-agent[bot]
4e5846f3bd Initial plan 2025-10-27 08:38:03 +00:00
Sanjai Kumar
c5325c732f feat: enhance environment variable persistence handling (#5783)
* feat: enhance environment variable persistence handling

* feat: experiment playwright with multiple workers

---------

Co-authored-by: Bijin Bruno <bijin@usebruno.com>
2025-10-25 19:02:45 +05:30
Anton
a538b27f24 Import WSDL to collection (#5015)
* Import WSDL to bruno collection

* feat(wsdl-import): remove unused code and minor refactor

---------

Co-authored-by: Bijin Bruno <bijin@usebruno.com>
2025-10-25 15:20:18 +05:30
Anoop M D
77bb8f40fe Update readme.md (#5883)
Fix broken anchors for contribute and git headers.
2025-10-24 17:56:21 +05:30
kosarinin
8f1f5e3861 Update readme.md
Fix broken anchors for contribute and git headers.
2025-10-24 15:12:40 +03:00
Bijin A B
e9251a1f3f fix: add missing jsonwebtoken in package-lock (#5882) 2025-10-24 17:25:11 +05:30
Sid
3a011b2a18 Merge pull request #5881 from usebruno/bugfix/incorrect-space-encode-internal
Fixes: Generate Code does urlencoding twice
2025-10-24 17:17:40 +05:30
Chirag Chandrashekhar
fa1498e2a8 Bugfix/incorrect space encode (#5870)
* Fix the space encoding issue

* fix: incorrect space encoding

Fixed an issue in Code Generation for requests. The original fix was
raised in [PR](https://github.com/usebruno/bruno/pull/4478). The current
PR fixes some merge conflicts and resolves some unimported dependencies
error.

* test: add URL encoding tests for code generation feature

Add Playwright tests to verify proper URL encoding behavior in Bruno's
code generation dialog for both encoded and unencoded query parameters.

* moved the test script inside request

* updated the snippet generation code to reuse code and reduce redundancy

* removed redundant code and reverted autoformat

* reverted some auto formatted changes

* reverting format during commit hook

* chore: reset formatting

* chore: reformat

---------

Co-authored-by: Vipin Sundar <86339268+vipin-sundar@users.noreply.github.com>
Co-authored-by: Chirag Chandrashekhar <chiragchan@Chirags-MacBook-Air.local>
Co-authored-by: Sid <siddharth@usebruno.com>

chore: reformat
2025-10-24 16:29:22 +05:30
Siddharth Gelera (reaper)
77681ca51e fix: inherit vars and headers from the collection (#5876)
* fix: inherit vars and headers from the collection
2025-10-24 15:08:10 +05:30
Vipin Sundar
045141efaf Fix the space encoding issue (#4478) 2025-10-23 15:27:19 +05:30
anusree-bruno
c997b91698 added jsonwebtoken as inbuilt library (#5535)
* added jsonwebtoken as inbuilt library

* removed bundling

* handle callback in quickjs

* chore: tests folder restructure

* chore: lint fix

---------

Co-authored-by: Sid <siddharth@usebruno.com>
2025-10-22 14:57:19 +05:30
anusree-bruno
986d5b0b2a moved custom search to components folder (#5750)
* moved custom search to components folder

* renamed custom search

---------

Co-authored-by: Sid <siddharth@usebruno.com>
2025-10-22 14:56:57 +05:30
ganesh
a2a521477a add fix for runtime var color (#4254)
* added new changes

* adds color to light and dark theme file

* import theme obj and use variable runtime color

* fix: operator linebreak style for eslint

* chore: remove un-needed changes

---------

Co-authored-by: Sid <siddharth@usebruno.com>
2025-10-22 14:23:12 +05:30
Siddharth Gelera (reaper)
8e70adcbf9 fix: incomplete tests (#5824)
* fix: close support modal for other tests to reuse the window properly

* Update support-links.spec.js

* chore: reformat

---------

Co-authored-by: Sid <siddharth@usebruno.com>
2025-10-22 13:39:36 +05:30
Prasanth Baskar
87296776fa add arch linux install to readme (#4569)
Signed-off-by: bupd <bupdprasanth@gmail.com>
2025-10-19 03:19:16 +05:30
Alex
9df70cd759 Merge pull request #5809 from 0x416c6578/feature/minify-json-xml
Add `bru.utils.minifyXml` and `bru.utils.minifyJson`
2025-10-19 01:29:32 +05:30
Anoop M D
8f9fb3b3c9 Merge pull request #5163 from josbiz/fix--dot-on-proxy-options-when-unused
fix: dot on unused proxy settings
2025-10-19 01:15:21 +05:30
Anoop M D
6d018f5648 Merge pull request #5164 from josbiz/fix--dot-now-showed-on-used-preset-setting
fix: show dot on used preset setting
2025-10-19 01:14:00 +05:30
Anoop M D
789d0b23c0 added option to revert changes (#4503) 2025-10-19 01:09:07 +05:30
anusree-bruno
81e1e403e4 handle options in getBody for QuickJS VM (#4614) 2025-10-19 01:02:30 +05:30
Sanjai Kumar
ad2add4026 Added tests for replacing invalid variable characters in Postman collection Env (#4634)
---------

Co-authored-by: sanjai0py <sanjailucifer666@gmail.com>
Co-authored-by: Anoop M D <anoop@usebruno.com>
2025-10-19 01:00:19 +05:30
naman-bruno
02554c3ad9 Merge pull request #4279 from naman-bruno/feat/apikey-codegen
Add: API Key auth in code generator
2025-10-19 00:53:58 +05:30
Anoop M D
62815e3429 Merge pull request #5008 from anusree-bruno/feat/add-process-env-vars-to-gql-introspection
add process.env variable support to GraphQL introspection
2025-10-18 23:15:51 +05:30
Anoop M D
9859b69559 Merge pull request #5113 from apealpha/bugfix/3019-prettify-json-with-variables
fix(request): prettify JSON with variables
2025-10-18 22:51:10 +05:30
Anoop M D
440c688bbb Merge pull request #4708 from pooja-bruno/improve/use-common-getTreePathFromCollectionToItem-function
improve: use common getTreePathFromCollectionToItem function
2025-10-18 22:44:08 +05:30
Anoop M D
416eb754b7 Merge pull request #4747 from ZieglerZhu/bugfix/update-readme-cn
docs(readme): update readme_cn.md
2025-10-18 18:00:11 +05:30
Anoop M D
b85d6efa60 Merge pull request #5303 from usebruno/dependabot/github_actions/actions/checkout-5
build(deps): bump actions/checkout from 4 to 5
2025-10-18 16:49:35 +05:30
Blake Guilloud
19dea18629 Merge pull request #5829 from BlakeGuilloud/bugfix/5823-saving-url-in-response-pane
Bugfix/5823 saving url in response pane
2025-10-18 16:39:21 +05:30
Abhishek S Lal
636901c23d fix: resolve global env variable becoming undefined on script execution (#5816)
* fix: resolve global env variable becoming undefined on script execution

Fixes an issue where global disabled environment variables were becoming undefined during request execution when the pre request script is non-empty.

The update ensures that global variables persist as expected and are correctly referenced throughout the request lifecycle.

Closes #5772.

* feat: added test for checking proper global env update through scripts

* refactor: updated comments for more readability and added a new data-testid in modal.
2025-10-17 21:50:50 +05:30
lohit
a4b1941817 fix(bru-2035): form-urlencoded logic updates (#5820) 2025-10-17 18:22:43 +05:30
Sid
7d8fde9180 fix: improve URL parsing in getParsedWsUrlObject (#5822) 2025-10-17 18:15:15 +05:30
Anoop M D
4197304bf9 Merge pull request #5679 from mheidinger/visual-gql-indicator
feat: add visual indicator for GQL requests
2025-10-17 15:00:37 +05:30
Max Heidinger
b75422a010 feat: add visual indicator for GQL requests 2025-10-17 10:25:54 +02:00
Pragadesh-45
e9f03c46c7 tests: add tests for URN parsing (#5819) 2025-10-17 10:58:26 +05:30
Pragadesh-45
73e828621f fix: enhance URL parameter parsing and interpolation logic (#5812)
* fix: enhance URL parameter parsing and interpolation logic
2025-10-16 17:58:53 +05:30
Siddharth Gelera (reaper)
2becf49542 fix: harden type checks for buildFormUrlEncodedPayload (#5811) 2025-10-16 13:31:13 +05:30
Siddharth Gelera (reaper)
4c3a9928bc fix: remove redundant ipcRenderer.invoke call (#5799) 2025-10-15 17:33:41 +05:30
sanish chirayath
b694a41c96 fix: duplicate response for grpc (#5793) 2025-10-15 16:39:37 +05:30
sanish chirayath
ff9a4d97e3 fix: newly created requests should be added within the directory context (#5784)
* fix: newly created requests should get added to directory we want them to get added

* refactor: simplify code

* fix : lint

* refactor

* refactor
2025-10-14 17:49:21 +05:30
Bijin A B
6ab6e5ed57 fix(ui): limit dropdown width to 650px and fix alignment (#5781) 2025-10-14 12:05:48 +05:30
Bijin A B
3837a7612c Merge pull request #5778 from bijin-bruno/fix/environment-names-visibility
fix: make environment name width flexible up to 35% and disable tooltip for short names
2025-10-14 11:31:29 +05:30
Anoop M D
6589dc51cd Merge pull request #5765 from usebruno/chore/better-message-for-the-future-maintainer
chore(#1693): better comment explaining why bruno sets content-type header as false
2025-10-12 15:19:37 +05:30
Anoop M D
509f4da667 chore(#1693): better comment explaining why bruno sets content-type header as false 2025-10-12 15:18:29 +05:30
Anoop M D
9d2b070ed9 Merge pull request #5754 from Pragadesh-45/fix/doc-editor
feat(Markdown): override normalizing on whitespace in markdown editor
2025-10-11 17:25:39 +05:30
Anoop M D
d0c524cd9a Merge pull request #5757 from wbw1537/enhance-error-log
bugfix/Enhance error log for OAuth2 when certificate error
2025-10-11 17:08:43 +05:30
Anoop M D
74f0f67795 Update error message for SSL/TLS certificate verification 2025-10-11 17:08:09 +05:30
Bowen Wang
45664bdb65 enhance error log 2025-10-10 21:55:53 +08:00
Pragadesh-45
98cb2df3fe feat(Markdown): enhance Markdown rendering options and use exact whitespace instead normalizing 2025-10-09 23:33:55 +05:45
lohit
d478102b30 chore(bru-1943): upgrade electron version to v37.6.1 (#5752) 2025-10-09 18:58:28 +05:30
Siddharth Gelera (reaper)
924bc2e79e Merge pull request #5713 from barelyhuman/fix/form-values-seq-5237
fix: reimplement payload serialization for `x-www-form-encoded`
2025-10-09 18:25:28 +05:30
Pooja
c2d40fe99f Fix: Cross button not resetting timeout to inherit (#5749)
* Fix: Cross button not resetting timeout to inherit
2025-10-09 14:47:18 +05:30
sanish chirayath
944674d208 feat: add transformDescription function to handle various description formats in Postman collections (#5744)
- Implemented transformDescription to standardize handling of string and object descriptions.
- Updated importPostmanV2CollectionItem to utilize transformDescription for folder, request, and parameter descriptions.
- Added comprehensive tests for transformDescription covering edge cases and different formats.
2025-10-08 20:31:39 +05:30
Pooja
0c30357b01 feat: add redirect and timeout in request settings (#5672)
* feat: add redirect and timeout in request settings
2025-10-08 20:00:37 +05:30
Sanjai Kumar
ce40949564 fix: filter out internal content-type headers for no body requests in axiosinstance (#5591)
* fix: filter out internal content-type headers for no body requests in axios instance
2025-10-08 17:25:21 +05:30
Siddharth Gelera (reaper)
c6ce40c245 fix: keepAlive's fallback adds problem while saving normal requests (#5741)
* fix: only get the values if the settings exist
* Apply suggestion from @Copilot
* refactor: move status line to the query bar

---------

Co-authored-by: Bijin A B <bijin@usebruno.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-08 17:06:24 +05:30
Anoop M D
6890bbee70 Merge pull request #5733 from Skewnart/fix/locale-usage-in-tests
fix: fixing tests using locale on numbers
2025-10-08 15:01:16 +05:30
lohit
4993c61e29 fix(bru-1928): fix debug library dependency for bruno-requests package (#5738) 2025-10-08 12:59:33 +05:30
anusree-bruno
a66e849cfb Feat/editor custom search (#5278)
* added custom search in editor

* UI improvements

* added yellow highlight for search

* added playwright tests

* memoizing matches and few other changes

* fixed issue with debounce

* refactoring and styling fixes

* lint fixes

* ensure ESC closes search bar even when focus is in editor

* move esc logic to editor

---------

Co-authored-by: Sid <siddharth@usebruno.com>
2025-10-08 11:05:17 +05:30
lohit
9f47200e7b fix(bru-1939): fix OAuth2 credentials not persisting across requests in the same collection run. (#5730) 2025-10-07 22:40:51 +05:30
lohit
10739c32c4 fix(bru-1928): bruno-cli oauth2 updates (#5729) 2025-10-07 22:38:52 +05:30
Siddharth Gelera (reaper)
c1853e613b Feat: Websocket Support (#5480)
* init

* fix: header saving in ws

* fix: retrieve auth value correctly

* feat: ws settings

* fix: text for inherited auth

* feat: pass down options/settings for ws

* fix: handle run handling on url

* fix: send initial message

* fix: fix header movement and minor cleanup

* fix: message queue

* refactor: faster flushing

* feat: ws tab specific additions

close tab should close connection
`ws` shown in the tab

* chore: remove unused icon

* feat: simplify query URL rendering

* fix: only add to settings if they were added

* chore: revert to original

* fix: restyle web ui

* feat: implement WebSocket response sorting and enhance message handling

- Added WSResponseSortOrder component for toggling message sort order.
- Updated WSMessagesList to accept and utilize sort order.
- Refactored message handling to use 'type' instead of 'direction'.
- Enhanced response state management to include sort order.

* feat: enhance WebSocket handling with redirect and upgrade events

- Added support for 'ws:redirect' and 'ws:upgrade' events in the WebSocket client.
- Updated WSResponseHeaders to format headers correctly.
- Modified WSResponsePane to display headers in the response.
- Improved message handling in the Redux slice for WebSocket events.

* fix: correct fallback for URL retrieval in bruRequestToJson

* feat: enhance WebSocket message handling and styling

- Add new styling for incoming messages in StyledWrapper.
- Update WSMessagesList to handle message sorting and focus.
- Refactor response sort order handling in WSResponseSortOrder.
- Improve WebSocket connection management in ws-client.

* fix: adjust styling for message display

* fix: imports for ws files

* fix: visually simplify the message list

* chore: pkg updates

* fix: remove unused content-type check in WebSocket request preparation

* fix: avoid duplicate messages

avoid message getting queued and sent twice

* feat: beautify the code editor in each message

* feat(websockets): add websocket tests

* tests(websockets): move it a folder up

* fix: hexdump on sent messages

* fix: make the view a lot more compact

* feat: enhance WebSocket message handling and styling

* formatting fixes - batch 1

* chore: formatting fixes batch 2

* chore: format changes batch 3

* chore: format settings batch 4

* chore: clean up

* chore: for now avoid oauth2

* chore: formatting changes batch 6

* test(websocket): add headers handling in tests

- Implemented logic to send headers in websocket messages.
- Added tests for websocket connections and message handling.
- Created locators for common elements in websocket tests.

* chore: cleanup

* test(websocket): refactor to use constant for BRU_FILE_NAME

Updated the test cases to utilize a constant for the BRU_FILE_NAME regex pattern for better maintainability and readability.

* test(websocket): update BRU_FILE_NAME to use regex

Changed BRU_FILE_NAME from a string to a regex pattern for better matching.

* fix(ws-client): rename timeout to handshakeTimeout

Updated the WebSocket connection options to use 'handshakeTimeout' instead of 'timeout' for clarity.

* chore: cleanup

* fix(ShareCollection): update non-exportable request types handling

Refactor hasGrpcRequests to hasNonExportableRequestTypes,
returning an object with a flag and types of requests that
will not be exported.

* feat: inherit timeout from app prefs

* fix: faster queue

* feat: add WSRequestBodyMode component and language detection

- Introduced a new component for selecting request body modes (JSON, XML, TEXT).
- Implemented auto-detection of language for the request body content.
- Created a styled wrapper for improved UI presentation.

* feat: enhance WebSocket message handling with decoder support

- Added decoder field to WebSocket messages in various components.
- Updated prettify functionality to handle XML and JSON formats.
- Modified Redux state to include decoder information.
- Adjusted schema validation to accommodate decoder field.

* refactor: replace decoder with type in WebSocket message handling

* fix: use `body` directly

* chore: reset formatting

* chore: reformat

* chore: reformat

* chore: reformat

* chore: reformat

* chore: base format

* chore: fix lang constructs

* chore: fix message queue flush logic

Ensure that the flushQueue method checks for the existence of the message queue before processing.

Refactor WebSocket test fixtures for better readability by correcting indentation and structure.

* fix: typo

* chore: lint fixes

* chore: lint fixes

* chore: rediff utils

* chore: rediff utils

* chore: remove from CLI

* chore: rediff utils

* chore: rediff utils

* chore: rediff utils

* chore: rediff utils

* chore: fix formatting

* tests(websocket): add websocket persistence tests

* chore: format

* feat(eslint): add TypeScript support and update test file patterns

* fix: turn off single line jsx expressions

* revert lang `ws` removal

* chore: reformat

* feat: better subprotocol support and tests

* chore: reformat

* chore: reformat

* clean up ununsed components

* refactor: locators, tests, new request design

* chore: close app for each test to start afresh

* Revert "chore: close app for each test to start afresh"

This reverts commit 5c2e3bec81.

* refactor: simplify dropdown mode selection

* chore: remove unused changes

* refactor: simplify

* chore: simplify

* fix: loading pulse animation

* refactor: update lodash import syntax

* fix: comments and sanitisation

* refactor: rename BRU_FILE_NAME to BRU_REQ_NAME for consistency

Updated variable names across websocket tests to improve clarity and maintain consistency in naming conventions.

* fix: null check for the initialisation of websocket client

* fix: add poller to check for saved state

* fix: variable message time check for tests

* fix: force wait for elements

* fix: use nth locators instead of wait (draft attempt)

* chore: reformat

* fix: update beta preferences to include websocket support

* feat: GA

* feat: rename `connectionTimeout` to `timeout` and better form

* feat: update WebSocket IPC channel names to use 'renderer' prefix

* feat: add 'oauth2' to supported authentication modes

* chore: add default `json` type in ws

* test: add tests for bruToJson and jsonToBru parsers

- Implemented smoke tests for the bruToJson parser to validate message inference and settings.

* refactor: improve timeout handling in WebSocket client

---------

Co-authored-by: Siddharth Gelera <siddharthgelera@Siddharths-MacBook-Air.local>
Co-authored-by: Sid <siddharth@usebruno.com>
2025-10-07 21:03:09 +05:30
Skewnart
c393dfe5d6 fix: fixing tests using locale on sizes 2025-10-07 16:33:20 +02:00
Pragadesh-45
cf17539a47 Refactor: Remove normalizeNewlines function and update tests to preserve newline types (#5697)
* refactor: remove `normalizeNewlines` function and update tests to preserve newline types
2025-10-07 18:43:19 +05:30
Anoop M D
608a9d1954 Merge pull request #5386 from pkolmann/bugfix-digest-auth
fix(digest-auth): fix Digest Auth when no QOP is set
2025-10-07 18:29:11 +05:30
Pragadesh-45
3a04d43ffe fix: lint 2025-10-07 18:05:46 +05:45
Pragadesh-45
5c9a391cc6 fix(digest-auth): handle multiple QOP values in Digest Auth 2025-10-07 17:39:38 +05:45
Pragadesh-45
df4b7c1337 feat(cli): ignore and skip invalid .bru file (#5711) 2025-10-07 15:20:45 +05:30
Pooja
db6a639c15 feat: add path based grouping for openapi (#5638)
* feat: add path based grouping for openapi
2025-10-07 13:32:11 +05:30
Siddharth Gelera (reaper)
85319769a5 feat: add Rosetta detection for Apple Silicon (#5717)
* feat: add Rosetta detection for Apple Silicon

* fix: update class attributes to className for React compatibility
2025-10-07 13:05:43 +05:30
Sanjai Kumar
8d2f087206 feat: enhance json environment file support in bruno-cli (#5660)
* feat: enhance json environment file support in bruno-cli

feat: add parseEnvironmentJson function to normalize environment JSON structure

lint fixes

feat: added tests for invalid JSON environment files in CLI and added missing constant defenition.

feat: improve JSON environment file handling and update tests

Trigger test

fix: update CLI command syntax for non-existent JSON environment file test

fix: correct CLI command syntax in test for non-existent JSON environment file

fix: update CLI command syntax in test for non-existent JSON environment file

fix: update test to use temporary path for non-existent JSON environment file

trying to fix the tests

fix tests

refactor: rename ERROR_INVALID_JSON to ERROR_INVALID_FILE and update related error handling in CLI commands and tests

fix: update parseEnvironmentJson to preserve secret flag

test: improved tests

* refactor: move parseEnvironmentJson function to utils/ environment.js file and update imports

* test: update tests
2025-10-07 12:49:22 +05:30
sanish chirayath
1cc3a6432a Feature: support import paths for gRPC (#5573)
* Enhance GrpcSettings component: update ui to improve user experience

Enhance GrpcSettings component: add import path management functionality

Refactor filesystem utility: remove duplicate isDirectory function and clean up code

Enhance GrpcQueryUrl component: add import path management and improve proto file selection functionality

Remove unused error message from GrpcQueryUrl component to streamline UI

Enhance GrpcSettings component: add editing functionality for proto files and import paths, improve UI for better user experience

Refactor GrpcSettings component: remove editing functionality for proto files and import paths, add replace import path feature, and update UI for improved feedback on file validity

Update GrpcQueryUrl component: change error message styling from red to yellow for improved visual feedback on invalid proto files and import paths

Refactor GrpcQueryUrl component: update styling for mode indicators and active tabs to use yellow color for improved visual consistency

Refactor ToggleSwitch component: add activeColor prop for customizable styling and update Checkbox background color logic to utilize activeColor

Update GrpcQueryUrl component: change dropdown and button styles to use yellow color for active states, enhancing visual consistency across the UI

Update GrpcSettings component: change error message styling from yellow to red for improved visibility and consistency in indicating invalid proto files and import paths

Refactor GrpcSettings component: remove hover background styles from table rows for a cleaner UI and maintain consistent button styling across actions

Refactor GrpcSettings component: remove Status column from the table and update error indication for invalid files with an alert icon for better visibility

Enhance Dropdown and GrpcQueryUrl components: add controlled visibility to Dropdown for improved interaction, and update loadGrpcMethodsFromProtoFile to accept collection for dynamic import paths, enhancing gRPC method loading functionality.

Refactor GrpcSettings component: streamline the display of proto files and import paths by consolidating empty state messages and enhancing error visibility with alert icons, while maintaining consistent table structure and button functionality.

Update GrpcQueryUrl component: simplify dependency array in useEffect and add conditional rendering for empty state messages regarding proto files and import paths, enhancing user feedback and clarity.

Refactor IconGrpc component: remove unused IconProto SVG definition to streamline the code and improve maintainability.

Refactor filesystem and network utility files: remove unnecessary blank lines to improve code readability and maintainability.

Update GrpcSettings and GrpcQueryUrl components: modify getBasename function to handle relative paths more effectively, and replace IconFile with IconFolder for improved visual consistency in the display of import paths.

Update Grpc components: enhance getBasename function to accept collection pathname for improved path resolution in GrpcSettings and GrpcQueryUrl, ensuring accurate display of proto file names.

Implement ProtobufSettings component: replace gRPC references with Protobuf, add functionality for managing proto files and import paths, and enhance UI with styled components for improved user experience.

Merge gRPC and Protobuf configurations for backward compatibility in CollectionSettings, ProtobufSettings, and GrpcQueryUrl components. Update state management and UI interactions to reflect the new structure, ensuring seamless transition from gRPC to Protobuf settings.

Add migration utility for gRPC to Protobuf configuration transition

Implement migration logic in collection-watcher to check and convert gRPC configurations to Protobuf format. Introduce a new utility for handling the migration process, ensuring backward compatibility and seamless updates to configuration files. This change enhances the application's ability to manage configuration transitions effectively.

Remove redundant migration logging and comments in collection-watcher.

Update loadGrpcMethodsFromProtoFile to use Protobuf configuration instead of gRPC. Adjust import path handling to reflect the new structure, ensuring compatibility with recent configuration transitions.

Enhance collection-watcher to send updated Protobuf configuration to the main process after migration. Remove redundant migration logic from the change function, streamlining the configuration handling process.

Add unit tests for gRPC to Protobuf migration utility

Introduce comprehensive tests for the migrateGrpcToProtobuf and needsMigration functions, covering various scenarios including config presence, merging, and handling of edge cases. This addition ensures the reliability of the migration process and validates the expected behavior of the utility functions.

Add initial tests for managing protofiles in Protobuf settings

Introduce a new test suite for managing protofiles, validating the visibility of protofiles and import paths in the Protobuf settings. The tests cover scenarios for loading methods from protofiles, handling invalid paths, and ensuring successful loading after providing necessary import paths. Additionally, a new collection configuration file is added to support the tests.

Reset gRPC methods state on loading errors in GrpcQueryUrl component. This ensures a clean state when encountering issues while loading methods from proto files, improving error handling and user feedback.

Enhance ProtobufSettings and GrpcQueryUrl components with data-test-ids for improved testing.

Refactor manage protofile tests to improve method loading verification. Update selectors for better specificity and ensure visibility of gRPC methods dropdown after selection.

Remove debug logging from getBasename function in path.js and refactor variable declaration in collection-watcher.js for improved clarity.

Refactor GrpcQueryUrl component to enhance dropdown item styling and improve method selection feedback. Update class names for better visual transitions and ensure consistent appearance across selected and hover states.

Refactor GrpcQueryUrl component by removing the GrpcurlModal implementation and its associated logic. This change streamlines the component and prepares for future enhancements.

Refactor GrpcQueryUrl component by introducing TabNavigation, ProtoFilesTab, and ImportPathsTab for improved organization and readability. This change enhances the user interface by streamlining tab management and separating concerns within the component.

Remove visibility check for loaded gRPC methods in manage protofile tests to streamline method selection process. Update selectors for improved specificity.

Refactor collection-watcher.js to remove gRPC migration logic and update configuration handling. Delete grpc-to-protobuf migration utility and associated tests to streamline codebase and eliminate redundancy.

Refactor GrpcQueryUrl component to rename gRPC-related functions and improve button click handling. Update dropdown item styling for consistency and enhance the visibility of proto files and import paths in the user interface. Add new test data for collection management and update paths in user data preferences.

Refactor path utility functions by removing getDirPath and updating exports in path.js. Adjust imports in Protobuf component to reflect these changes. Clean up filesystem.js by removing unused fs and fsPromises imports.

Refactor ProtobufSettings and GrpcQueryUrl components: improve code readability by standardizing arrow function syntax, enhancing UI feedback for proto files and import paths, and ensuring consistent styling across components.

Update manage protofile tests: change selector for collection path name to improve test specificity and ensure accurate visibility of protofiles in the Protobuf settings.

Refactor path utility functions and update component logic: modify getRelativePath and getBasename functions to accept parameters in a consistent order, enhancing path resolution across ProtobufSettings and GrpcQueryUrl components. Simplify filesystem utility functions by removing error handling for IPC calls, improving code clarity. Add comprehensive unit tests for path utilities to ensure reliability and correctness across different platforms.

fix: lint

feat: Add jsdocs to getAbsoluteFilePath utility function

refactor: Enhance GrpcQueryUrl and related components with styled wrappers for improved UI consistency

- Removed the "BETA" label from GrpcurlModal for a cleaner interface.
- Introduced StyledWrapper components for ImportPathsTab and ProtoFilesTab to encapsulate styling and improve readability.
- Updated TabNavigation to utilize StyledWrapper, enhancing the overall layout and design.
- Added new styles in the dark and light themes to support the updated UI elements, ensuring a cohesive look across components.

refactor: Enhance GrpcQueryUrl and related components with styled wrappers for improved UI consistency

- Removed the "BETA" label from GrpcurlModal for a cleaner interface.
- Introduced StyledWrapper components for ImportPathsTab and ProtoFilesTab to encapsulate styling and improve readability.
- Updated TabNavigation to utilize StyledWrapper, enhancing the overall layout and design.
- Added new styles in the dark and light themes to support the updated UI elements, ensuring a cohesive look across components.

refactor

feat: Enhance error handling and user feedback in GrpcQueryUrl and useProtoFileManagement

feat: Refactor GrpcQueryUrl component and introduce MethodDropdown and ProtoFileDropdown for improved user experience

- Removed unused imports and state variables to streamline the GrpcQueryUrl component.
- Introduced MethodDropdown for better organization of gRPC methods, enhancing selection and display.
- Added ProtoFileDropdown to manage proto file selection and import paths, improving user interaction.
- Updated UI elements for consistency and clarity, including dropdowns and method selection feedback.
- Enhanced error handling and user feedback mechanisms throughout the component.

refactor: rm comments

fix: linting

refactor: streamline proto file and import path management in useProtoFileManagement and useReflectionManagement hooks

refactor: use hook for protofile management within collection settings

fix: lint

fix: e2e tests

refactor: use getByTestId within playwright tests

refactor: enhance path utilities for cross-platform compatibility

* fix: lint

* test: add cleanup step to manage protofile tests for improved isolation
2025-10-07 12:47:16 +05:30
Pooja
28907a203f fix: Show active global environment in config modal (#5698)
* fix: Show active global environment in config modal
* add: delayShow prop in tooltip
2025-10-07 12:30:53 +05:30
Philipp Kolmann
6204e90e9c fix(digest-auth): fix Digest Auth when no QOP is set
(working on usebruno/bruno#5378)
2025-10-07 11:32:38 +05:45
sanish chirayath
1d0ba135ff Enable gRPC (Beta to GA) (#5687)
* refactor: remove gRPC feature toggle from CollectionSettings and Presets components

* fix: lint error

---------

Co-authored-by: Bijin A B <bijin@usebruno.com>
2025-10-06 23:16:19 +05:30
Siddharth Gelera (reaper)
3c72975314 fix: removeMenu on about window (#5712) 2025-10-06 15:30:14 +05:30
Andrii Oriekhov
3fa9fea6a4 use request directory as the destination for saving response (#5699)
* use request directory as the destination for saving response
* use request directory as the destination for saving response
2025-10-04 02:33:28 +05:30
Anoop M D
239f1dc9f5 Merge pull request #5690 from james-ha-bruno/feat/add-get-tags-for-requests
adding req getTags methods
2025-10-04 02:04:11 +05:30
James Ha
28e37d8f6f feat(#5689): req.getTags() api 2025-10-04 01:45:33 +05:30
Anoop M D
8b28070695 Merge pull request #5666 from usebruno/feat/tab-reordering-internal
feat: extended additions for tab reordering (#5413)
2025-10-02 08:44:28 +05:30
Bijin A B
4ae55b8f1a fix: update interpolate-request-url.spec.ts test flow (#5682) 2025-10-01 13:45:51 +05:30
Sanjai Kumar
8bad0262c6 feat: Enhance EnvironmentVariables component with read-only support for non-string values (#5616)
* feat: Enhance EnvironmentVariables component with read-only support for non-string values

* feat: minor refactor and cleanup worker app state

* fix: playwright test flow

---------

Co-authored-by: Bijin Bruno <bijin@usebruno.com>
2025-10-01 02:36:45 +05:30
Sanjai Kumar
c7029d1cda fix: improve file upload handling in prepare-request to use streaming (#5637)
* fix: improve file upload handling in prepare-request to use streaming
* feat: add unit tests

---------

Co-authored-by: Bijin Bruno <bijin@usebruno.com>
2025-09-30 22:47:09 +05:30
Sid
bb44d9e193 feat: add draggable tabs component (#5669) 2025-09-30 14:27:25 +05:30
Jayakrishnan C N
14966f6e6c feat: import multiple collections from a parent folder (#5431)
* feat: import multiple collections from a parent folder
* feat: open collections in parallel, revert plural labels, and update playwright tests

---------

Co-authored-by: Bijin Bruno <bijin@usebruno.com>
2025-09-30 13:27:20 +05:30
Siddharth Gelera (reaper)
56f0741121 chore: extract ts support for aslant from feat/websocket-engine (#5664)
* chore: extract ts support
2025-09-30 11:23:47 +05:30
Roland Schaer
b1840d189d feat: make tabs reorderable (#5413) 2025-09-30 08:59:25 +05:30
naman-bruno
aacb1e0b8e Merge pull request #5635 from naman-bruno/feat/performance-monitor
add: system monitor
2025-09-29 19:37:56 +05:30
Anoop M D
fa0f3b3b7b Merge pull request #5661 from barelyhuman/fix/eslint-comma-arrow
fix: update stylistic rules in ESLint configuration
2025-09-29 15:46:27 +05:30
Siddharth Gelera
2a00add966 fix: update stylistic rules in ESLint configuration
- Added 'comma-dangle' rule to disallow trailing commas.
- Changed 'arrow-parens' rule to require parentheses for arrow functions.
2025-09-29 14:54:56 +05:30
Mauricio Sanabria
41e0615f77 Feature: Add collapse full collection feature (#4492)
* Add collapse collection feature
---------
Co-authored-by: Anoop M D <anoop@usebruno.com>
2025-09-29 13:07:10 +05:30
Rudra Patel
191a997b05 feat: Add button to copy environment variable from popover (#5416)
* feat: Add copy button to environment variable hover

* feat: Add success state

* feat: Clean up code

* feat: Add DOM test for popover and copy button functionality

* feat: Add more robust tests

* chore: reformat

---------

Co-authored-by: Siddharth Gelera <ahoy@barelyhuman.dev>
2025-09-29 13:00:42 +05:30
Pragadesh-45
123fe7d542 Merge pull request #5557 from Pragadesh-45/feat/default-location
feat: default location for collections
2025-09-25 22:53:08 +05:30
Pooja
187f5ca011 feat: add support for file body mode in bruno-cli (#5427)
* feat: add support for `file` body mode in `bruno-cli` Fixes #4336
* fix: Correct await/async on file reading.
* fix: update test and fix lint errors

---------

Co-authored-by: William Floyd <william.floyd@modopayments.com>
Co-authored-by: Bijin Bruno <bijin@usebruno.com>
2025-09-25 17:03:48 +05:30
Pooja
e1b4043ca5 fix: openapi request import (#5586)
* fix: openapi request import
* fix: js sandbox mode selector doesn't show up while opening new collections in playwright tests

---------

Co-authored-by: Bijin Bruno <bijin@usebruno.com>
2025-09-25 13:06:02 +05:30
sanish chirayath
9c9cfdf0b2 fix: update preferences saving method in preferences utility (#5617)
* fix: update preferences saving method in preferences utility

* fix: make markAsLaunched asynchronous and improve error handling in onboarding process

* fix: lint errors

---------

Co-authored-by: Bijin Bruno <bijin@usebruno.com>
2025-09-24 19:28:30 +05:30
Anoop M D
daf6a6d5d6 Merge pull request #5629 from barelyhuman/ci/eslint-run-on-main
ci: fallback to `main` as base ref for ESLint
2025-09-24 18:11:14 +05:30
Siddharth Gelera
95a2ca9558 ci: fallback to main 2025-09-24 17:28:31 +05:30
Anoop M D
f359303927 Merge pull request #5615 from usebruno/fix/odata-style-pathparams
Support for Odata style path params
2025-09-24 15:23:07 +05:30
Pragadesh-45
65f52961c5 Merge pull request #5613 from Pragadesh-45/main 2025-09-24 13:59:45 +05:30
Pooja
2a3db96c9b fix: Add null safety checks in GlobalSearchModal (#5625)
* fix: Add null safety checks in GlobalSearchModal
2025-09-24 13:57:58 +05:30
Bijin A B
a1a7c9a136 remove the custom test timeout as default would be enough 2025-09-24 13:56:41 +05:30
Siddharth Gelera (reaper)
c15d47c0dc chore: base format (#5624) 2025-09-24 13:00:54 +05:30
Pragadesh-45
e4f8945e89 fix: add Linux support for xdg-portal version in Electron app (#5618) 2025-09-24 01:53:41 +05:30
John Vester
e6c136d2bb Merge pull request #5582 from johnjvester/5579_correct_spelling
5579 - correct spelling error and introduce constant to avoid duplication
2025-09-24 00:40:58 +05:30
sid-bruno
6f8c543ee3 tests: additional tests for path params and odata (#5610)
* Support for Odata style path params (#5048)

* Support for Odata style path params

* Remove test statement

* Update packages/bruno-app/src/utils/url/index.spec.js

Add more testcases

Co-authored-by: sid-bruno <siddharth@usebruno.com>

* Performance improvements

* Add testcases for odata style url params

---------

Co-authored-by: sid-bruno <siddharth@usebruno.com>

* tests: additional tests for odata and path params

tests(electron): add in odata smoke for interpolation

chore: code format

chore: ESLint atomic diff based formatting (#5592)

* chore: atomic diff based formatting

chore(format): fix formatting

tests(playwright): interpolation tests

Support for Odata style path params (#5048)

* Support for Odata style path params

* Remove test statement

* Update packages/bruno-app/src/utils/url/index.spec.js

Add more testcases

Co-authored-by: sid-bruno <siddharth@usebruno.com>

* Performance improvements

* Add testcases for odata style url params

---------

Co-authored-by: sid-bruno <siddharth@usebruno.com>

---------

Co-authored-by: Anton <anton@trugen.net>
Co-authored-by: Siddharth Gelera <ahoy@barelyhuman.dev>
2025-09-23 15:55:04 +05:30
Anton
40b44de294 Support for Odata style path params (#5048)
* Support for Odata style path params

* Remove test statement

* Update packages/bruno-app/src/utils/url/index.spec.js

Add more testcases

Co-authored-by: sid-bruno <siddharth@usebruno.com>

* Performance improvements

* Add testcases for odata style url params

---------

Co-authored-by: sid-bruno <siddharth@usebruno.com>
2025-09-23 13:50:51 +05:30
Siddharth Gelera (reaper)
f24e1e78fe chore: ESLint atomic diff based formatting (#5592)
* chore: atomic diff based formatting
2025-09-23 13:36:34 +05:30
Pooja
87d8c5ccb7 fix: env name overflow (#5598) 2025-09-19 19:36:37 +05:30
Pragadesh-45
17d5629627 refactor: Replace SingleLineEditor with MultiLineEditor in EnvironmentVariables components and add masking functionality (#5576)
* refactor: Replace SingleLineEditor with MultiLineEditor in EnvironmentVariables components and add masking functionality
- Adjusted related components to support the new editor and its features, including toggling visibility for secret values.

---------

Co-authored-by: lohit-bruno <lohit@usebruno.com>
2025-09-18 22:31:09 +05:30
Sanjai Kumar
4321846dbd feat: Add end-to-end tests for collection run reports (#5562)
* feat: Add end-to-end tests for collection run reports
2025-09-18 15:20:28 +05:30
Pooja
f3d4ac84d8 fix: environment list scroll (#5585) 2025-09-18 11:23:49 +05:30
Sanjai Kumar
de52ceea48 refactor: moved sample collection JSON to resources folder inside bruno-electron and updated electron-builder-config (#5581) 2025-09-17 20:45:33 +05:30
Pooja
65e69e77b3 revamp: collection and global env selector dropdown (#5542)
* revamp: collection and global env selector dropdown

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Pragadesh-45 <54320162+Pragadesh-45@users.noreply.github.com>
Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
Co-authored-by: sanish-bruno <sanish@usebruno.com>
Co-authored-by: bernborgess <bernborgesse@outlook.com>
Co-authored-by: lohit <lohit@usebruno.com>
Co-authored-by: Its-Treason <39559178+Its-treason@users.noreply.github.com>
Co-authored-by: jayakrishnancn <jayakrishnancn@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-17 19:35:00 +05:30
Sanjai Kumar
fb2ca8937e feat: add environment variable DISABLE_SAMPLE_COLLECTION_IMPORT to control sample collection import behavior (#5567)
* feat: add environment variable DISABLE_SAMPLE_COLLECTION_IMPORT to control sample collection import behavior
2025-09-17 13:57:10 +05:30
Anoop M D
e2da072e8b Merge pull request #5566 from lohit-bruno/crypto_safe_mode_support
fix crypto-js in safe mode
2025-09-16 16:11:05 +05:30
lohit-bruno
90492d6e79 fix crypto-js in safe mode 2025-09-16 15:39:06 +05:30
Sanjai Kumar
5393e3b496 feat: Add default sample collection on first app launch (#5536)
* feat: Add Default Sample Collection On First Launch
* feat(initial-load): add  attribute for app readiness

---------

Co-authored-by: Bijin Bruno <bijin@usebruno.com>
2025-09-15 15:00:39 +05:30
lohit
9fc885839f ca certs function updates (#5555) 2025-09-12 21:49:49 +05:30
Pragadesh-45
dbfbde43cf refactor: Replace MultiLineEditor with SingleLineEditor in EnvironmentVariables components (#5554) 2025-09-12 21:49:33 +05:30
lohit
1aa4e27ab5 use node:tls library for ca certs (#5552) 2025-09-12 20:29:28 +05:30
Siddharth Gelera (reaper)
2b6da56c3c fix(electron): avoid double encoding urls params. Fixes #5380. (#5507)
* fix(common): avoid double encoding urls params
2025-09-12 19:08:53 +05:30
lohit
c08827b0c0 ca certs updates and fixes (#5549) 2025-09-12 16:03:27 +05:30
Anoop M D
841d977725 Merge pull request #5547 from lohit-bruno/ca_certs_fixes_system_ca
use system-ca library for ca certs
2025-09-12 01:11:25 +05:30
Anoop M D
56629663dc Remove flaky header size test from getSize
Removed test for header size from getSize tests.
2025-09-12 01:05:24 +05:30
lohit-bruno
27cbb194bf use system-ca library for ca certs 2025-09-12 00:33:22 +05:30
Anoop M D
cfec4a9e1b Merge pull request #5531 from helloanoop/chore/update-digest-tests
Update digest authentication test cases with new URLs and credentials
2025-09-08 22:58:57 +05:30
Anoop M D
a7f6d669af Update digest authentication test cases with new URLs and credentials 2025-09-08 22:50:11 +05:30
dependabot[bot]
e57162b79a build(deps): bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 17:10:22 +00:00
Anoop M D
03abbc585f Remove body size test from getSize tests 2025-09-08 22:36:22 +05:30
Anoop M D
be730a8c4f Merge pull request #5529 from usebruno/dependabot/github_actions/actions/setup-node-5
chore(deps): bump actions/setup-node from 4 to 5
2025-09-08 22:29:25 +05:30
dependabot[bot]
194d904284 chore(deps): bump actions/setup-node from 4 to 5
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 5.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 16:21:53 +00:00
Anoop M D
86b3c65dcd Merge pull request #5525 from sanish-bruno/feat/moving-requests-cross-collection
Feature: moving requests cross collection
2025-09-08 20:05:04 +05:30
sanish chirayath
c9fe9813db Merge pull request #5526 from sanish-bruno/fix/tags-removed-while-moving-request
Fix: tags removed while moving request
2025-09-08 20:03:36 +05:30
sanish-bruno
70d65d87c5 move: test cases to new folder 2025-09-08 16:32:13 +05:30
jayakrishnancn
0bce203851 feat: Move requests between collections #3320
test: update e2e test case for moving request from one collection to another

test: updated the tests

test: added more test cases

test: e2e test updated

test: fixed test case

test: fixed test cause for folder

fix: add grpc-request to clone-folder

fix: removed handleCrossCollectionItemMove method

test: updated e2e test cases

fix: removed cross-collection gurard statement

format: revert format

fix: UX changes for collection drag and drop
2025-09-08 16:29:46 +05:30
lohit
5b716cbe60 node vm fixes (#5519) 2025-09-08 06:39:18 +05:30
lohit
a6b0b6c117 node vm support (#5518)
Co-authored-by: Its-Treason <39559178+Its-treason@users.noreply.github.com>
2025-09-08 06:09:25 +05:30
lohit
3c656270b3 ca certs fixes and tests (#5429)
Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
2025-09-07 23:06:44 +05:30
Anoop M D
1bc7a1f655 Modify body size test to check for > 1MB 2025-09-07 21:49:11 +05:30
Anoop M D
5a10322608 Merge pull request #5490 from bernborgess/bugfix/global-shortcut-unfocused
Bugfix/global shortcut unfocused
2025-09-07 21:24:29 +05:30
Anoop M D
2864ddaa72 Merge pull request #5262 from sanish-bruno/add/playwright-testing-guide
Add Playwright testing guide for Bruno application
2025-09-07 04:59:23 +05:30
Anoop M D
c2f3d8e7da Merge pull request #5238 from helloanoop/feat/loc-count-script
feat: script to calculate locs of repo
2025-09-07 04:48:52 +05:30
Anoop M D
1fd61f0601 Merge pull request #5517 from helloanoop/refactor-tests
Refactor tests
2025-09-07 03:23:01 +05:30
Anoop M D
033c5cc0f7 Refactor tests 2025-09-07 03:05:11 +05:30
Pragadesh-45
db35e7059c Merge pull request #5438 from Pragadesh-45/feat/multiline-values-for-env-vars
Feat/ Add Multiline Support for Enviroment Variables
2025-09-06 17:17:51 +05:30
bernborgess
cd80332de9 fix: Make globalShortcut only active when app is focused 2025-09-03 14:02:01 -03:00
Anoop M D
1902329226 Merge pull request #5491 from naman-bruno/add/vscode-image
add: vscode image
2025-09-03 22:09:25 +05:30
naman-bruno
b25569d29a add: vscode image 2025-09-03 22:08:24 +05:30
Pooja
de4674dcc4 add: playwright test for import collection modal (#5487)
* add: playwright test for import collection modal
2025-09-03 19:14:08 +05:30
naman-bruno
457a2f83e7 fix: Bruno GUI hangs on 308 redirect (#5445)
* fix: 308 redirect
2025-09-03 17:52:12 +05:30
Pragadesh-45
ae3d5a5515 fix(apt): ensure Bruno repo key is world-readable on Debian 12+ (#5474)
- Added `chmod 644 /etc/apt/keyrings/bruno.gpg` so `_apt` user can read the key
- Keeps key in binary format with `gpg --dearmor`
- Prevents NO_PUBKEY errors and repository being ignored on Debian 12+
2025-09-03 17:43:58 +05:30
Bijin A B
3b74e0da86 fix(curl-parser): curl commands with url without protocol (#5453) 2025-09-03 16:05:19 +05:30
Pooja
985b5ed20c add: global search modal (#5400)
* add: global search modal
2025-09-03 15:32:18 +05:30
Anoop M D
188a2e63e3 Add HttpMethodSelector component tests (#5481) 2025-09-03 10:33:54 +05:30
Anoop M D
01839c8e5f Merge pull request #5435 from notKvS/theme-fix
fix: graphQL documentation theme
2025-09-03 01:18:11 +05:30
Sanjai Kumar
648581ded5 feat: custom HTTP method (#4841) 2025-09-02 23:09:48 +05:30
sreelakshmi-bruno
bf38cc0f51 adding metadata to report (#5360) 2025-09-02 15:11:23 +05:30
sanish chirayath
abddc98767 feat: add WSSE authentication support to gRPC requests (#5455)
* feat: add WSSE authentication support to gRPC requests

- Introduced WSSE authentication mode in GrpcAuth component.
- Updated supported authentication modes to include WSSE.
- Refactored gRPC event handlers to streamline authentication header setting.
- Added notes regarding limitations of complex auth modes in gRPC.

* fix: update authentication header retrieval in setAuthHeaders function

- Refactored the setAuthHeaders function to correctly retrieve WSSE and OAuth2 refresh token URLs from the request object instead of the collectionAuth object.
- Added comprehensive tests for various authentication modes, ensuring proper inheritance and request-level overrides for AWS v4, basic, bearer, digest, NTLM, WSSE, API key, and OAuth2 authentication methods.

* chore: remove outdated comments on gRPC authentication limitations
2025-09-01 19:19:14 +05:30
Pooja
3fa05d32cb fix: openapi auth import in bruno (#5354)
* fix: openapi auth import in bruno
2025-09-01 15:15:30 +05:30
Pragadesh-45
eb0accdf21 Update Bruno's Age 🎉 (#5328)
* feat: Update Bruno's age calculation in tests and specs to use a dynamic function instead of a static value.
2025-09-01 12:13:27 +05:30
Anoop M D
6f57633572 Merge pull request #5466 from helloanoop/footer-playwright-tests 2025-09-01 10:47:14 +05:30
Anoop M D
e7c33f7eef Add playwright tests for Notifications Modal and Sidebar Toggle functionality 2025-08-30 20:24:52 +05:30
ganesh
1620c24557 update the grpc tagline (#5449)
* updated grpc tagline

* add share feeback hyperlink
2025-08-30 13:05:30 +05:30
Bijin A B
bd9d2eabe1 fix: upgrade @faker-js/faker from 8.4.0 to 8.4.1 (#5347)
Snyk has created this PR to upgrade @faker-js/faker from 8.4.0 to 8.4.1.

See this package in npm:
@faker-js/faker

See this project in Snyk:
https://app.snyk.io/org/bruno-8a2f42NP3GxXppW5covrLX/project/dfa3b6f8-996e-40e0-85d9-2df8ec62bdbd?utm_source=github&utm_medium=referral&page=upgrade-pr

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2025-08-30 10:16:23 +05:30
Anoop M D
990bbdb813 Merge pull request #5458 from Pragadesh-45/fix/keybinding-issues-with-global-shortcut
Refactor: Remove use of `globalShortcut` for minimize/hide to avoid hijacking system shortcuts
2025-08-30 02:42:36 +05:30
Anoop M D
00636a5a31 Merge pull request #5459 from josbiz/fix/suggestion-box-behind-modal
Add z-index to CodeMirror hint box
2025-08-30 02:27:46 +05:30
Jose Bolivar Ibz
c526eacd6b Add z-index to CodeMirror hint box 2025-08-29 20:32:14 +00:00
Anoop M D
9a2836129f Merge pull request #3178 from pietrygamat/bugfix/571
fix: unable to set request bodies with colon characters in their names
2025-08-30 01:57:54 +05:30
Anoop M D
b8d67d9232 Merge branch 'main' into bugfix/571 2025-08-30 01:52:46 +05:30
Anoop M D
bcf4673a64 chore: Update Bruno grammar and tests to support keys with spaces, braces, and nested escaped quotes in headers and query parameters 2025-08-30 01:44:33 +05:30
Pragadesh-45
6c52c07494 refactor: remove use of globalShortcut for minimize/hide to avoid hijacking system shortcuts 2025-08-30 00:42:32 +05:45
Jose Bolivar Ibz
1de9203dd5 Merge branch 'main' into fix--dot-on-proxy-options-when-unused 2025-08-29 08:45:44 -07:00
Pooja
de48c93e8d fix: store redirect cookies under initial request domain (#5387) 2025-08-29 21:05:18 +05:30
Pragadesh-45
ba56e87375 Feat: Collapsable Sidebar (#5302) 2025-08-29 21:03:46 +05:30
sanish chirayath
cb7f61ee4b Implement legacy Postman global API transformations (#5403) 2025-08-29 21:01:06 +05:30
Pragadesh-45
6bcb850b6e fix: resolve URL and method handling in digest auth interceptor (#5317) 2025-08-29 21:00:17 +05:30
ganesh
dc56c00309 changed example to cjs syntax (#4526)
* changed example to cjs syntax
2025-08-29 14:46:25 +05:30
Bijin A B
1220a5f159 Merge pull request #5253 from jokj624/bugfix/running-test-filtering
fix: incorrectly counts running/in-progress requests
2025-08-29 14:34:26 +05:30
Bijin A B
3046327fa7 Merge pull request #5139 from ganesh-bruno/fix/rename-path-value
rename query table value from path to value
2025-08-29 14:17:30 +05:30
Anoop M D
c1c617bfeb Merge pull request #5436 from ganesh-bruno/fix/bruno-readme
change landing page of Bruno
2025-08-28 18:14:47 +05:30
lohit
6632407a34 include oauth2 additional parameters in bruno collection exports (#5422) 2025-08-28 18:10:08 +05:30
Sanjai Kumar
447b3046b3 fix: environment persistence and UI (#5404) 2025-08-28 18:09:37 +05:30
Anoop M D
2666e7fee0 Merge pull request #5412 from jbraconig/fix/debian-trixie-install
Update: readme.md installation instructions via Apt (#5411)
2025-08-28 17:57:27 +05:30
ganesh-bruno
f9ca0e2f5a change landing page of Bruno 2025-08-28 14:59:39 +05:30
notKvS
5dd90e1386 fix: graphQL documentation theme 2025-08-27 20:47:16 +05:30
Bijin A B
5e9cec38f0 Merge pull request #5385 from naman-bruno/bugfix/large-response
fix: Large response crash bruno
2025-08-26 20:10:34 +05:30
lohit
ed1a072ba1 chore: eslint updates and fixes (#5402) 2025-08-26 18:49:50 +05:30
Pooja
5f938d77b4 feat: new import modal (#5050) 2025-08-26 18:32:02 +05:30
lohit
f5b4dbd1a1 electron builder updates (#5425) 2025-08-26 15:13:56 +05:30
Bijin A B
8c72a6094b Update contributing.md (#5407) 2025-08-26 14:44:50 +05:30
Coel Aspey
325d03b92f feat: Persist response body scroll position across tabs (#3902) 2025-08-25 17:21:34 +05:30
tlaloc911
54c41c861e Show request body in devtools (#5337) 2025-08-25 16:46:26 +05:30
sanish chirayath
22a77b90f9 Enhance gRPC request handling in collection transformation functions by conditionally including methodType and protoPath, and removing params for gRPC requests. (#5399) 2025-08-25 15:17:15 +05:30
Martin Braconi
af894b5bbb Update: readme.md installation instructions via Apt (#5411) 2025-08-23 14:12:50 -05:00
sreelakshmi-bruno
48934ef74a Add type field to env when not present (#5401) 2025-08-22 18:27:33 +05:30
Pooja
9c16ebcda3 add: global env var in codegen url interpolation (#5397) 2025-08-22 14:15:52 +05:30
sreelakshmi-bruno
2ed51bb984 Fix global env issue on bulk import (#5396) 2025-08-22 14:05:41 +05:30
naman-bruno
aec9ee6265 fix: bru import command fix (#5393) 2025-08-22 13:07:34 +05:30
Pooja
04d1e50f98 Merge pull request #5384 from pooja-bruno/move/common-cookie-file-in-buno-request-package 2025-08-21 21:15:35 +05:30
naman-bruno
e74c78ea8b fix: large response 2025-08-21 01:59:39 +05:30
lohit
e71ee3eff5 Merge pull request #4447 from usebruno/oauth2_additional_params 2025-08-20 21:31:16 +05:30
lohit-bruno
e0b3b1ad4b Merge remote-tracking branch 'origin/main' into oauth2_additional_params 2025-08-20 20:00:58 +05:30
lohit
f9d29f821c Merge pull request #5377 from naman-bruno/bugfix/oauth2-cli 2025-08-20 17:34:03 +05:30
naman-bruno
4454f4f7b8 oauth2 cli fixes 2025-08-20 17:10:56 +05:30
lohit
c4cacf284b Merge pull request #5376 from lohit-bruno/oauth2_additional_parameters
Oauth2 additional parameters updates
2025-08-20 17:07:16 +05:30
lohit-bruno
311a232968 updates 2025-08-20 16:57:07 +05:30
Pooja
97aff84157 fix(cookie-store): defer encryption setup to prevent early macOS ‘Chr… (#5373) 2025-08-20 16:49:31 +05:30
lohit-bruno
ef12401d2e fetch/refresh token - collection/request variables usage fix 2025-08-20 16:34:03 +05:30
lohit-bruno
8dde2701f4 ui updates 2025-08-20 16:32:52 +05:30
lohit-bruno
cd00c21781 dsl updates 2025-08-20 16:30:08 +05:30
sanish chirayath
efb2e83ad9 Add gRPC support (#5148) 2025-08-20 16:24:49 +05:30
Sanjai Kumar
e5a608f962 feat: add persistent environment variable handling in IPC events and Bru class (#5172) 2025-08-19 23:05:22 +05:30
Pooja
3e3e2e0563 feat: persist cookies in app (#5318) 2025-08-19 22:10:22 +05:30
lohit-bruno
8d1f292b83 updates 2025-08-19 17:46:05 +05:30
lohit-bruno
953024dae7 Merge remote-tracking branch 'origin/main' into oauth2_additional_params 2025-08-19 17:39:02 +05:30
lohit
146c8462ea option to parse large bru files using a regex based approach (#5324) 2025-08-19 15:24:23 +05:30
naman-bruno
77c96c4821 fix: consider delay when running again (#5349) 2025-08-19 15:24:05 +05:30
naman-bruno
060c613aa1 fix: client id placement issue (#5348) 2025-08-19 14:21:00 +05:30
naman-bruno
b804ff6dfd oauth2 fixes (#5259) 2025-08-19 11:17:39 +05:30
Pragadesh-45
ce0fc08500 Feat/ Add Global Shortcuts for Zoom, Minimize, and Close on Windows (fixes: #4108) (#4110)
Co-authored-by: sanjai0py <sanjailucifer666@gmail.com>
2025-08-14 20:48:15 +05:30
sanish chirayath
fc53dd88e2 fix: update authentication mode to inherit in OpenAPI to Bruno (#5300) 2025-08-14 20:47:17 +05:30
Bijin A B
c2063ce71b fix(security): patch CVE-2025-7783 by forcing form-data@4.0.4 (#5329) 2025-08-14 15:58:31 +05:30
Pooja
acc8e9deba Merge pull request #5327 from pooja-bruno/fix/cli-test-for-cookie
fix: cli test for cookie
2025-08-14 15:31:29 +05:30
lohit
bf145a71f5 Merge pull request #5330 from lohit-bruno/oauth2_additional_parameters
oauth2 additional params fixes
2025-08-14 15:06:23 +05:30
lohit-bruno
7de3e6e3ff review update fixes 2025-08-14 15:04:45 +05:30
lohit
c33bf9f88e Merge pull request #5323 from lohit-bruno/oauth2_additional_parameters
oauth2 additional params updates
2025-08-13 21:43:26 +05:30
lohit-bruno
ceab0b4dc1 additional params updates 2025-08-13 21:42:04 +05:30
lohit-bruno
7ccbea7ced Merge remote-tracking branch 'origin/main' into oauth2_additional_params 2025-08-13 21:16:16 +05:30
lohit
51163a7282 chore: upgrade electron version (#5305)
* chore: upgrade electron version to v37.2.6

* fixed rollup version
2025-08-13 15:44:38 +05:30
lohit-bruno
1f0b1cb5a7 fixed rollup version 2025-08-12 20:40:26 +05:30
lohit-bruno
ec151ac2e5 chore: upgrade electron version to v37.2.6 2025-08-12 20:30:44 +05:30
maintainer-bruno
c4356411c9 Update CODEOWNERS 2025-08-11 14:39:29 +05:30
Pooja
84cca6f92b add: bulk edit for collection and folder header (#5279) 2025-08-08 19:44:47 +05:30
sreelakshmi-bruno
f1f1c1fe5b Handle decryption for secret env vars (#5285) 2025-08-08 17:28:49 +05:30
Andrew Borg
20ffae86e4 Add missing stringifyRequest import for bruno-cli (#5282) 2025-08-08 17:11:31 +05:30
Pooja
d031687ee9 fix: url interpolation in code gen (#5187) 2025-08-07 20:25:28 +05:30
Pooja
86901c1e89 fix: test only flag in cli to inclue pre and post test (#5216) 2025-08-07 15:50:03 +05:30
naman-bruno
7cb80abdfc fix: scrollbar visible in tables (#5270) 2025-08-06 16:22:30 +05:30
sanish-bruno
da2f2519ec feat: add Playwright testing guide for Bruno application 2025-08-05 17:17:38 +05:30
naman-bruno
99c8fd5240 fix: request order reset on select all (#5261) 2025-08-05 17:11:49 +05:30
jokj624
8bd2216bf0 fix: check running status in runner results 2025-08-04 19:26:06 +09:00
jokj624
4cfc28cd73 fix: incorrectly counts running/in-progress requests 2025-08-04 18:44:23 +09:00
Sanjai Kumar
0e81c14b96 fix: correct password field binding in DigestAuth component (#5242)
Co-authored-by: sanjai0py <sanjailucifer666@gmail.com>
2025-08-01 21:00:19 +05:30
lohit
110d93a983 global environments fetch error handling (#5241) 2025-08-01 20:59:57 +05:30
naman-bruno
e2ecd7bfa9 fix: request tab opening unintentionally (#5240) 2025-08-01 20:59:37 +05:30
Anoop M D
7efaa427ca feat: script to calculate locs of repo 2025-08-01 13:50:13 +05:30
Sanjai Kumar
98c09db820 fix: enable sensitive field warnings for collection and folder auth (#5230)
- Fix sensitive field warnings not showing for collection-level and folder-level auth
- Use consistent object structure approach across all auth levels (collection, folder, request)
- Replace manual object property access with lodash get() for better readability and robustness
- Extract variable usage checking logic into reusable helper function
- Eliminate code duplication by using single sensitive fields definition
- Improve maintainability and performance by reducing regex pattern recreation

feat: add sensitive field warnings to collection-level auth components

refactor: streamline sensitive field checks in environment variables

refactor: remove unused imports in EnvironmentVariables component

Co-authored-by: sanjai0py <sanjailucifer666@gmail.com>
2025-07-31 22:32:37 +05:30
lohit
8938b04faf added res url api hint words, updated test (#5234) 2025-07-31 22:31:30 +05:30
naman-bruno
81b5e3c539 rm: cleanup from filestore (#5233) 2025-07-31 22:30:51 +05:30
naman-bruno
ec51ebba45 Add Select/Deselect and Reorder Capabilities to Collection Runner (#5195) 2025-07-31 00:00:23 +05:30
Pooja
31027cb2e0 feat: adding cookie apis (#5117) 2025-07-30 19:35:54 +05:30
Tim Nikischin
60a0a32743 Implement Response URL variable (#2983) 2025-07-30 19:35:17 +05:30
maintainer-bruno
aae4f03fdf fix(dev): add filestore src to dev hot reload watchers (#5223) 2025-07-30 18:45:28 +05:30
naman-bruno
5150251698 fix: params while involking renderer:remove-collection (#5218) 2025-07-30 00:27:24 +05:30
Sanjai Kumar
b571c1a1a5 Feat/add warnings for sensitive fields other auths (#5100) 2025-07-30 00:26:45 +05:30
naman-bruno
62151330f2 Fix: Loading state while collection mount (#5138) 2025-07-29 17:15:30 +05:30
naman-bruno
780beb832e fix: typescript errors (#5214) 2025-07-29 12:11:50 +05:30
naman-bruno
29e6470f7a fix: insecure requests not working (#5197) 2025-07-25 18:05:10 +05:30
Anoop M D
78b8b7f6e4 Revert "disable ssl/tls & enable system proxy (#5125)" (#5196)
This reverts commit 36e3554d5f.
2025-07-25 17:13:58 +05:30
lohit
63f5108dfd list block grammar fixes (#5180) 2025-07-25 14:07:38 +05:30
Anoop M D
6daaf90667 feat: update statusbar styling, enhance cookie button accessibility, and adjust theme colors (#5185)
Co-authored-by: Maintainer Bruno <code@usebruno.com>
2025-07-25 14:05:28 +05:30
naman-bruno
0fec0003f2 fix: always showing scrollbar (#5184) 2025-07-24 20:44:13 +05:30
naman-bruno
4badee903a Add @usebruno/filestore package (#5130) 2025-07-24 18:48:25 +05:30
lohit
b20de42598 Update authorize-user-in-window.js 2025-07-23 20:40:54 +05:30
lohit
e5d30c2920 Merge branch 'main' into oauth2_additional_params 2025-07-23 15:05:17 +05:30
Jose Bolivar Ibz
cffa37ed50 fix: show dot on used preset setting 2025-07-22 12:17:19 -07:00
Jose Bolivar Ibz
bcf61f507a Update index.js
Variable change from let to const
2025-07-22 12:10:14 -07:00
Jose Bolivar Ibz
325b573da9 fix: dot on unused proxy settings 2025-07-22 11:51:02 -07:00
naman-bruno
a36f33746d comment debug tab and error boundry (#5161) 2025-07-22 18:33:02 +05:30
sanish chirayath
9ea7659f61 fix: crash double-click handling for collection and collection item (#5151) 2025-07-22 12:51:41 +05:30
lohit
6c165eddf6 Revert "fix: add rsbuild watchFiles config for bruno-app src/providers/* …" (#5153)
This reverts commit eacbc7799f.
2025-07-22 12:12:17 +05:30
lohit
803e974dbb include draft tags while filtering requests for collection/folder run (#5142) 2025-07-18 22:30:36 +05:30
ganesh-bruno
b3a0234ec3 rename query table value from path to value 2025-07-18 13:33:29 +05:30
naman-bruno
8e7bdc2bfd fix: status bar & dev tools z-index issue (#5132) 2025-07-17 14:36:36 +05:30
lohit
d5cb051f19 enable/disable collection/folder run buttons based on the filtered requests (#5131) 2025-07-17 14:21:00 +05:30
lohit
36e3554d5f disable ssl/tls & enable system proxy (#5125) 2025-07-16 21:37:21 +05:30
Pragadesh-45
645b7e721a Merge pull request #5123 from Pragadesh-45/fix/collection-path-validator 2025-07-16 21:36:46 +05:30
naman-bruno
ba5eb53548 Merge pull request #5110 from naman-bruno/bugfix/devtools-timeline-scroll 2025-07-16 17:41:27 +05:30
apealpha
4b5c7dcca6 fix(request): prettify JSON with variables 2025-07-16 00:00:26 +09:00
lohit
2a90ec59cb Merge pull request #5111 from lohxt1/folder_sequencing_fixes_cli 2025-07-15 19:17:24 +05:30
lohxt1
5c47e1f405 updated validations 2025-07-15 19:10:19 +05:30
lohxt1
9c3314ce47 folder sequencing sort by name and then sequence 2025-07-15 18:55:34 +05:30
lohit
5512ec1c6d Merge pull request #5108 from naman-bruno/bugfix/devtools-error 2025-07-15 18:11:56 +05:30
lohit
530f0bacaf Merge pull request #5107 from sanish-bruno/fix/auth-type-missing-dupe-2
Bug/improve-handling-of -Inherit-for-folders-and-request
2025-07-15 17:07:34 +05:30
naman-bruno
15e06ba86c fix: runner height 2025-07-15 17:07:27 +05:30
naman-bruno
dca1ffa27e fixes 2025-07-15 16:44:39 +05:30
sanish-bruno
8182161ff7 Enhance auth handling in Postman converter 2025-07-15 16:21:14 +05:30
Leonard Phillips
0e054259e9 Expand postman import to handle "inherit" auth type
Allow child items to inherit "No Auth" auths from parent

Simplify processAuth checks by setting mode="inherit" in bruno request object

Allow folders to inherit "No Auth" from parent folder

Reduce inherit fix scope

Revert standard jest test config

Reduce inherit fix scope even more

Reduce inherit fix scope final

Minor format change
2025-07-15 16:10:02 +05:30
Yash
ab4dabf047 Merge pull request #5083 from stupidly-logical/fix/clear_cache_message_text 2025-07-15 14:57:38 +05:30
lohit
a7f75f6fab Merge pull request #5103 from naman-bruno/bufix/console-debug 2025-07-15 14:57:26 +05:30
naman-bruno
fe1275e7d2 fix: console design 2025-07-15 14:53:51 +05:30
lohit
1811b6b152 Merge pull request #5098 from maintainer-bruno/feat/url-encoding-settings-refactor 2025-07-15 14:51:54 +05:30
lohit
3e8f1a71ff Merge branch 'main' into feat/url-encoding-settings-refactor 2025-07-15 14:47:58 +05:30
lohit
52e44a0568 Merge pull request #5069 from usebruno/feat/collection_runner_tags 2025-07-15 14:43:21 +05:30
Wibaek Park
903c5b4363 fix: Ignore empty header on Auth API Key(Header) to prevent sending request error (#5007) 2025-07-15 14:42:46 +05:30
Pooja
85c4871701 fix: awsv4 signature error bug (#5099) 2025-07-15 14:41:56 +05:30
maintainer-bruno
16736958c1 feat(url): import url encode settings from postman and insomnia (#5102) 2025-07-15 14:40:46 +05:30
lohit-bruno
0e28c97f8f collection runner tag updates 2025-07-15 14:33:18 +05:30
Antti Sonkeri
3803576aa4 feat: Tagging requests and filtering collection runs using tags 2025-07-15 13:37:36 +05:30
Maintainer Bruno
dda1673a0f feat(url): move url encoding utils to bruno common 2025-07-15 02:19:21 +05:30
maintainer-bruno
ecc6c1604c feat(url): introduce setting to toggle encoding of URL query parameters (#5089) 2025-07-15 00:23:17 +05:30
naman-bruno
e89a240237 fix: scroll issue (#5093) 2025-07-14 23:29:18 +05:30
lohit
4e4c94d73f sort folders by name first and then sequence (#5063)
* sort folders by name first and then sequence
---------

Co-authored-by: lohit <lohit@usebruno.com>
2025-07-14 22:17:11 +05:30
lohit
31e555812c use dedicated axiosRequestConfig and fix request info logs across all OAuth2 flows, token request call refactor (#5066) 2025-07-14 22:03:37 +05:30
naman-bruno
b9da31d24e added: status bar & console (#4922)
* added: status bar & console
2025-07-14 19:05:57 +05:30
Joseph PS
48989ceea9 manage secrets modal content updated (#5034) 2025-07-11 14:05:24 +05:30
Pooja
f1dbc65383 fix: code generator headers and multipartForm bug (#5056)
* fix: code generator headers and multipartForm bug
2025-07-11 13:58:25 +05:30
naman-bruno
a68833089f Feat: OAuth2 implicit grant type (#4307)
* add: implicit grant type
2025-07-11 13:55:03 +05:30
Bacteria
668fbfb0e0 bugfix: Use SingleLineEditor in New Request form to add env variable highlighting (#4954)
* Use SingleLineEditor in New Request form to add variable highlighting
2025-07-09 19:03:12 +05:30
Pooja
ef730c2c1a fix: runner result scroll (#5062)
* fix: runner result scroll
2025-07-09 18:59:19 +05:30
lohit
eacbc7799f fix: add rsbuild watchFiles config for bruno-app src/providers/* path and forceRefreshWatcher option for collection reopening (#4766)
* add rsbuild watchFiles config for src/providers and forceRefreshWatcher option for collection reopening

* updated paths
2025-07-09 17:33:27 +05:30
Pooja
4e7a880885 fix: export for folder level auth (#5041) 2025-07-09 16:17:13 +05:30
Joseph PS
f24b28b090 content updated (#5027) 2025-07-09 16:15:49 +05:30
Pooja
fbc77fc725 feat: introduce res.getSize() helper (header/body/total) (#5018)
* feat: introduce `res.getSize()` helper (header/body/total)

* fix: unit test

* rm: request-duration from collection runner header

* change: api for getSize

* fix

* improve: getSize method

* add: todo comment

---------

Co-authored-by: lohit <lohit@usebruno.com>
2025-07-08 21:00:05 +05:30
Raino Pikkarainen
82f5f9ee88 Add dataBuffer to response to be available in test scripts (#1881)
Co-authored-by: Raino Pikkarainen <raino.pikkarainen@twoday.com>
2025-07-08 19:32:01 +05:30
Joseph PS
8ec26a9383 Warning message content updated (#5032) 2025-07-08 16:09:14 +05:30
ramki-bruno
215256b2fe Added validator to check if a given path is inside an open Collection (#4800)
* Refactor: Renamed `Watcher` class and instance to `CollectionWatcher`

The name `Watcher` sounds very generic, but in this case its tightly
coupled with watching Bruno Collection paths. So it makes sense to name
it accordingly.

* Added validator to check if a given path is inside an open Collection

And added an sample validation for _new-request_ IPC event.

* Review fixes
2025-07-08 15:28:01 +05:30
Pooja
63a8201290 add: new timeline in runner (#4927)
* add: new timeline in runner
2025-07-08 15:26:21 +05:30
Jungsub Ryoo
795b365df3 fix: restrict {{$randomInt}} output to 0–1000 as per docs (#4847) (#4938)
Previously, `{{$randomInt}}` returned values across the full JavaScript number range.
This commit updates the generator to produce integers between 0 and 1000,
matching the documented behavior.

Fixes #4847
2025-07-04 21:33:01 +05:30
Pooja
b948e4a26d fix: collection request numbers font family (#4248) 2025-07-04 19:17:22 +05:30
sanish chirayath
69e19235a5 Merge pull request #5014 from sanish-bruno/fix/folder-collapse-behaviour
Enhancement: Improve CollectionItem collapse behaviour and UX
2025-07-04 19:08:17 +05:30
lohit
9cd709828d Merge pull request #5009 from sanjaikumar-bruno/fix/openAPI-import-fail-when-the-title-is-missing
fix: handle undefined title in collection name and improve error handling
2025-07-04 18:57:26 +05:30
lohit
a9eb1c72c6 Merge pull request #5022 from pooja-bruno/fix/-reset-test-results-&-script-error-state-on-each-new-request-run
fix: reset test results state on each new request run
2025-07-04 18:54:25 +05:30
lohit
e5d194f455 Merge branch 'main' into fix/-reset-test-results-&-script-error-state-on-each-new-request-run 2025-07-04 18:53:37 +05:30
lohit
eeb0885991 Merge pull request #4984 from pooja-bruno/add/script-error-card-in-collection-runner
add: script error card in collection runner
2025-07-04 18:51:36 +05:30
pooja-bruno
68f4e8770f fix: reset test results state on each new request run 2025-07-04 15:44:25 +05:30
pooja-bruno
bf93e136b6 mv: error msg null in initRunRequestEvent 2025-07-04 15:39:29 +05:30
pooja-bruno
837a152a96 change name of Indicator component 2025-07-04 15:39:29 +05:30
pooja-bruno
b461de9aaf improve 2025-07-04 15:39:29 +05:30
pooja-bruno
b83657cbd9 improve: runFolderEvent 2025-07-04 15:39:29 +05:30
pooja-bruno
054bf1cd19 fix: error console 2025-07-04 15:39:29 +05:30
pooja-bruno
b441e1648e add: type in indicator 2025-07-04 15:39:29 +05:30
pooja-bruno
cff4f5457b fix: sending script error 2025-07-04 15:39:29 +05:30
pooja-bruno
c96042c53f fix: testResult code 2025-07-04 15:39:29 +05:30
pooja-bruno
d39ccd2195 rm: comments 2025-07-04 15:39:29 +05:30
pooja-bruno
7f7b4e1c32 improvements 2025-07-04 15:39:29 +05:30
pooja-bruno
cb880840a2 add: error indicator in test tab 2025-07-04 15:39:29 +05:30
pooja-bruno
47bedec590 add: script error console in cli 2025-07-04 15:39:29 +05:30
pooja-bruno
cab75f7543 improvements 2025-07-04 15:39:29 +05:30
pooja-bruno
587e3cfe5d add: script error card in collection runner 2025-07-04 15:39:29 +05:30
lohit
b4e1871b66 Merge pull request #5030 from stupidly-logical/fix/gen_code_auth_header
fix: Add null check for collection root in snippet generator #5029
2025-07-03 19:28:10 +05:30
lohit
42448c90ab Merge pull request #5036 from maintainer-bruno/feat/fix-params-table-scroll
fix: params table default scroll
2025-07-03 19:27:50 +05:30
Maintainer Bruno
71ccd93771 fix: params table default scroll 2025-07-03 19:11:07 +05:30
Yash
f48241f6e1 fix: Add null check for collection root in snippet generator 2025-07-03 16:20:08 +05:30
lohit
1a93eabf01 request/response pane styling fixes (#5025) 2025-07-03 13:35:05 +05:30
lohit
df1c5f9363 Merge pull request #5028 from maintainer-bruno/fix/tests-2.7.0
fix: unit tests and e2e
2025-07-03 13:34:28 +05:30
Maintainer Bruno
803d2d96c9 fix: unit tests and e2e 2025-07-03 13:31:19 +05:30
sanjai0py
895d2ddf47 fix: update test description for default collection name handling 2025-07-02 15:12:29 +05:30
sanjai0py
a6a50f42a3 fix: handle undefined title in collection name and improve error handling
test: add unit tests for collection name handling based on OpenAPI title

fix: trim whitespace from info.title and improve default collection name handling

fix: simplify collection name assignment by using optional chaining

removed two console.log and improved the error message.

refactor: standardize single quotes in OpenAPI test cases

test: add case for empty title defaulting to Untitled Collection
2025-07-02 15:10:21 +05:30
Anoop M D
99873af281 Merge pull request #5020 from lohxt1/pm_translations_requestConfig_updates
handle `requestConfig` translations for variable references in `pm.sendRequest` calls
2025-07-01 20:23:41 +05:30
lohxt1
1b63798ff3 handle requestConfig translations when passed to pm.sendRequest as a variable 2025-07-01 20:04:42 +05:30
Anoop M D
c90d607046 Merge pull request #4973 from lohxt1/send_request_default_options
fix: set default proxy value as `false` for `bru.sendRequest`' axios request config
2025-07-01 13:02:58 +05:30
anusree-bruno
d2888daa88 add process.env variable support to GraphQL introspection 2025-06-30 13:12:35 +05:30
Pooja
c6c3931446 feat: support onFail api to catch errors in pre req (#4581)
support `onFail` api to catch errors in pre req

---------

Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
Co-authored-by: lohit <lohit@usebruno.com>
2025-06-27 19:42:00 +05:30
Art051
10e872c6ab Merge pull request #4752 from Art051/bugfix/4749-generate-code-error-with-binary-file-request
Bugfix/4749 generate code error with binary file request
2025-06-27 19:35:37 +05:30
lohit
6792cc26bd Merge pull request #4999 from ganesh-bruno/feat/remove-beta-key
removed BETA keyword
2025-06-27 19:29:08 +05:30
lohit
c76d99d1b0 Merge pull request #4995 from pooja-bruno/fix/include-unsaved-changes-in-generate-code
fix: include unsaved changes in generate code
2025-06-27 19:11:28 +05:30
ganesh-bruno
b813c916b8 removed BETA keyword 2025-06-27 18:51:15 +05:30
lohit
fab9d00566 Merge pull request #3973 from betawait/bugfix/bug-remove-content-type-in-post-with-no-body
Fix: Allow empty Content-Type when no body (#1693)
2025-06-27 17:49:34 +05:30
lohit
afcd7395d9 Merge pull request #4980 from lohxt1/codemirror_autocomplete_logic_refactor
codemirror `api/variables` autocomplete refactor
2025-06-27 17:18:37 +05:30
lohit
ed9c61908d Merge branch 'main' into codemirror_autocomplete_logic_refactor 2025-06-27 17:17:15 +05:30
lohit
999e3e5b71 Merge pull request #4992 from maintainer-bruno/fix/curl-query-parsing
fix(import): handle repeated query keys and improve error handling in curl import
2025-06-27 17:10:16 +05:30
lohit
81ae8db1a9 Merge pull request #4958 from sanjaikumar-bruno/pr-706-improved
Improved feat: add bulk edit mode for request headers
2025-06-27 17:09:46 +05:30
sanjai0py
f2b5b6f783 refactor: implementation of bulk edit functionality for query parameters and request headers
refactor: integrate BulkEditCodeEditor for bulk editing of query parameters and request headers

refactor: refactor BulkEditCodeEditor component folder structure nad fix Bulk Edit button styles

refactor: now the queryparams are updated in both the ways

style: fix indentation

reverting the style changes which  fixes the alignment of the bulkedit button

refactor: add onSave prop to BulkEditCodeEditor and update value handling

feat: add onSave prop to BulkEditCodeEditor for improved header management

added onRun prop to BulkEditCodeEditor, QueryParams, and RequestHeaders

refactor: renamed BulkEditCodeEditor to BulkEditor and update the references, and updated names for bulkEdit states
2025-06-27 17:06:29 +05:30
Chris Casola
e8eab46f48 feat: add bulk edit mode for request headers
Closes #185
2025-06-27 17:05:15 +05:30
lohit
bb913d32bc Merge pull request #4987 from naman-bruno/bugfix/oauth2-scope
Remove scope parameter from token request when empty
2025-06-27 15:13:03 +05:30
lohit
2ea59dcdae Merge pull request #4994 from maintainer-bruno/fix/minor-layout-fixes
fix(layout): minor layout css fixes
2025-06-27 14:53:54 +05:30
pooja-bruno
bbdf514098 rm: optional chaining 2025-06-27 13:48:53 +05:30
pooja-bruno
a0950dc4f3 rm: condition 2025-06-27 13:32:41 +05:30
pooja-bruno
d65ae78119 rm: comment 2025-06-27 13:16:11 +05:30
pooja-bruno
e6afbc75ff fix: authHeaders 2025-06-27 13:13:09 +05:30
Maintainer Bruno
47e420dec1 fix(layout): minor layout css fixes 2025-06-27 13:00:52 +05:30
pooja-bruno
1d6566679b fix: include unsaved changes in generate code 2025-06-27 12:56:21 +05:30
Maintainer Bruno
535865fdeb fix(import): handle repeated query keys and improve error handling in curl import 2025-06-27 00:08:10 +05:30
naman-bruno
5065b2ac37 fix: oauth2 scope 2025-06-26 17:26:59 +05:30
lohit
6349e9b816 fix: oauth2 tokenHeaderPrefix can be set to an empty string value (#4928)
* ~ only prefill `Bearer` as token prefix only when the oauth2 is selected as the auth type for the first time
~ check if tokenPrefix is present before adding a space before the access_token value in the header

* review comment fixes

---------

Co-authored-by: lohit <lohit@usebruno.com>
2025-06-26 15:53:14 +05:30
lohit
eb70883127 codemirror api/variables autocomplete refactor 2025-06-26 14:38:48 +05:30
lohit
1e83b3b35c Feat: Update serialization logic for application/x-www-form-urlencoded body type (#4943)
* fix: update qs.stringify to use repeat array format for url serialization

* fix(cli): update qs.stringify to use repeat array format for url serialization

* feat(tests): add URL serialization test case for Duplicate Keys

* feat(cli): refactor formUrlEncoded handling to use buildFormUrlEncodedPayload function

* fix(cli): standardize quotes in qs.stringify for form-urlencoded data

* fix(electron): standardize quotes in qs.stringify for form-urlencoded data
2025-06-26 13:52:56 +05:30
Pragadesh-45
ef18805008 fix(electron): standardize quotes in qs.stringify for form-urlencoded data 2025-06-26 12:05:02 +05:45
Pragadesh-45
5d51a528d7 fix(cli): standardize quotes in qs.stringify for form-urlencoded data 2025-06-26 12:04:34 +05:45
Pooja
ff0ceb2879 feat: add dropdown to select language and add lib selector in code gen (#4345)
* feat: add dropdown to select language and add lib selector in code gen

* add: checkbox for interpolation

* rm: url should interpolate from url

* add: search in dropdown

* fixes

* add: autofocus for search

* add: arrow navigation in select

* fix

code improvements

fix

rm: editor wrapper

rm: font-size

improvement

rm: custom select

rm comments and add sparql mode

rm: styles

* add: tests and fixes

* fixes: file naming

* rm: comments

* fix

* fix: unit tests

* improvements

* fixes

* fix: indentation

* fix

* fixes: CodeViewToolbar

* trim: extra spaces
2025-06-25 20:26:42 +05:30
Pooja
4d7c044eba Fix: undefined auth fields in folder-level authentication (#4907) 2025-06-25 20:25:53 +05:30
ganesh
3a92cb4eda Fix: Made reporter-skip-headers option case-insensitive in bruno-cli (#4799) 2025-06-25 16:08:42 +05:30
Bacteria
6244679d5b Merge pull request #4956 from bacteriostat/feature/single-line-editor-placeholder
feat: Add placeholder for SingleLineEditor
2025-06-25 16:00:22 +05:30
lohit
59c1b6b675 set default proxy value as false for send_request axios request config 2025-06-25 12:07:41 +05:30
Anoop M D
92a0f093db Merge pull request #4970 from ganesh-bruno/fix/remeove-runtime-var-note
Removed text from runtime var section
2025-06-24 22:00:18 +05:30
lohit
39dccd4b5f Merge pull request #4969 from lohxt1/send_request_default_options
add explicit HTTP agents with keepAlive to `bru.sendRequest` axios request config
2025-06-24 19:53:58 +05:30
lohit
674820f7c9 Merge pull request #4959 from maintainer-bruno/feat/curl-parser
fix(import): curl parser library
2025-06-24 19:45:20 +05:30
ganesh-bruno
f138b126f3 removed text fron runtime var 2025-06-24 19:24:15 +05:30
lohit
efaac453ce feat: implement vertical layout for response pane and enhance drag (#4957) 2025-06-24 19:22:05 +05:30
lohit
879c124aec add explicit HTTP agents with keepAlive to bru.sendRequest axios instance 2025-06-24 17:12:17 +05:30
sanish chirayath
9fe13f1868 Fix: postman collection fails when auth object missing auth values (#4794)
* refactor: streamline authentication handling in postman-to-bruno.js by using a switch statement and introducing AUTH_TYPES constant for better readability and maintainability

* feat: enhance authentication handling in postman-to-bruno.js to manage missing auth values across collection, folder, and request levels, ensuring a default mode of 'none'

* fix: update authentication handling in postman-to-bruno.js to correctly set auth mode based on provided auth type

* fix: update authentication tests to ensure default values are set for various auth types in postman-to-bruno
2025-06-24 16:32:32 +05:30
sanish chirayath
2bbfb28090 fix: handle falsy values in Postman environment and collection variables (#4924)
* fix: handle falsy values in Postman environment and collection variables

* Updated the `postman-env-to-bruno-env` and `postman-to-bruno` converters to handle cases where variable keys or values are falsy, ensuring they default to empty strings.
* Added unit tests to verify the correct handling of falsy values in both environment and collection variables.

* fix: filter out null/undefined keys and values in Postman variable imports

* Updated the `postman-env-to-bruno-env` and `postman-to-bruno` converters to filter out variables with null keys and values during import.
* Removed redundant test cases for empty variables in the corresponding unit tests.
2025-06-24 15:58:29 +05:30
Maintainer Bruno
3c65642e92 fix(import): curl parser library 2025-06-24 02:31:49 +05:30
Pragadesh-45
cf5f52b7b9 feat(cli): refactor formUrlEncoded handling to use buildFormUrlEncodedPayload function 2025-06-23 18:49:29 +05:45
Pragadesh-45
04d0439c9d feat(tests): add URL serialization test case for Duplicate Keys 2025-06-23 18:14:01 +05:45
Anoop M D
f1116c3008 feat: implement vertical layout for response pane and enhance drag 2025-06-22 19:12:33 +05:30
Yash
bbf4ad6b98 Enable variable tootlip in json request body (#4885)
* Enable variable tootlip in json request body

* fix: enhance variable value popover and add test coverage

---------

Co-authored-by: Maintainer Bruno <code@usebruno.com>
2025-06-20 16:15:11 +05:30
Phil Jones
3fe3eec465 Add support for integer and boolean in OpenAPI to Bruno converter (#4734) 2025-06-20 12:16:41 +05:30
Johann Kaspar Lieberwirth
a93b05fd6e Update wording for clarification. Add tooltip. (#4761)
* Update wording for clarification. Add tooltip.

* Update hint to match deafult style
2025-06-20 12:12:05 +05:30
Henri Parquet
da25d46df4 feature: add randomNanoId to dynamic variables (#4932) 2025-06-20 12:11:44 +05:30
Pragadesh-45
0d13d40cd7 fix(cli): update qs.stringify to use repeat array format for url serialization 2025-06-19 20:02:25 +05:45
Pragadesh-45
4664fd60b5 fix: update qs.stringify to use repeat array format for url serialization 2025-06-19 20:01:36 +05:45
maintainer-bruno
65ba984c2f Merge pull request #1037 from Nikolai2038/docs/update-linux-installation-instructions-via-apt
docs(#1036): Update linux installation instructions via apt
2025-06-19 17:19:45 +05:30
Anoop M D
8355b67bae Merge pull request #4859 from georgegiosue/docs/update-contributing-es
Update Spanish contribution guide for clarity and accuracy
2025-06-19 14:32:55 +05:30
Nikolai Ivanov
9b3fe2fd97 Add Debian dependencies (in particular, for "libasound2") (#2356)
See https://github.com/usebruno/bruno/pull/1037#discussion_r1403537930
2025-06-18 20:27:35 +05:30
Sanjai Kumar
34614f039f Autocomplete random variables (#4695)
* Feature: adding dynamic variable support (#3609)


Co-authored-by: Raghav Sethi <109696225+rsxc@users.noreply.github.com>
Co-authored-by: sanjai0py <sanjailucifer666@gmail.com>
2025-06-18 20:06:45 +05:30
Pooja
acd42eaa1b add: pre and post in report template (#4931) 2025-06-18 17:54:15 +05:30
Anoop M D
aebc8241cc Merge pull request #4923 from maintainer-bruno/fix/e2etest-dependencies
fix(workflow): ensure E2E test collection dependencies are installed …
2025-06-17 14:46:55 +05:30
Maintainer Bruno
0eda1b761d fix(workflow): ensure E2E test collection dependencies are installed in GitHub Actions 2025-06-17 13:40:06 +05:30
lohit
a05f7cb686 Merge pull request #4918 from lohxt1/bru_send_request_fixes
bru.sendRequest translation fixes
2025-06-17 00:26:39 +05:30
lohit
745a71700c add await keyword to the translated bru.sendRequest function calls (#4906)
* add await keyword for the bru.sendRequest postman translations

---------

Co-authored-by: lohit <lohit@usebruno.com>
2025-06-16 22:50:45 +05:30
Anoop M D
ac9c190b41 Merge pull request #4914 from naman-bruno/bugfix/timeline-scroll
fix: timeline scroll
2025-06-16 22:48:44 +05:30
Pragadesh-45
1a1a230a1e Merge pull request #4901 from Pragadesh-45/feat/support-multiple-run-cli-v1
Co-authored-by: William Quintal <william95quintalwilliam@outlook.com>
Feat: Enhance run command to accept multiple inputs for requests and folders in Bruno CLI (Improves: #2956) (Fixes: #2955)
2025-06-16 22:27:34 +05:30
Anoop M D
b2e02b7762 Merge pull request #4908 from Pragadesh-45/feature/support-json-env-files
feat(cli): add support for environment file input in run command
2025-06-16 22:19:27 +05:30
naman-bruno
9cbfeccbed fix: timeline-scroll 2025-06-16 21:53:38 +05:30
Pragadesh-45
4725300c41 feat(cli): add support for environment file input in run command 2025-06-16 19:34:56 +05:45
naman-bruno
f2aedf780d Fix: showing test script errors (#4902)
* fix: catch errors in tests
2025-06-14 22:20:24 +05:30
lohit
f03047a2f9 feat: bru.sendRequest api (#4867)
* feat: bru.sendRequest api

* updated the postman-translations logic to handle `pm.sendRequest` to `bru.sendRequest` translations, and added unit tests

* ~ removed `maxRedirects` and `proxy` values for sendRequest axios-instance
~ fixed the imports for the `send-request-transformer` function
~ `sendRequest` and `runRequest` will return same response object in both safe and developer mode
~ sendRequest function optimization

* revert sendRequest to async function, added a testcase for sendRequest with url string

* sendRequest callback errors handling

* updated tests and added await for the callbacks

---------

Co-authored-by: lohit <lohit@usebruno.com>
2025-06-14 22:18:31 +05:30
lohit
a7ba23d97e Merge pull request #4886 from sanish-bruno/fix/bearer-undefined
fix: handle undefined bearer token to send an empty string instead
2025-06-14 21:50:08 +05:30
lohit
2521e980ea Merge pull request #4514 from jonman5/fix/digest-headers-split
Fix Digest auth header field key value extraction
2025-06-14 20:46:18 +05:30
lohit
1c118fa04a feat: add prompt for handling large responses (#4866)
* feat: add prompt for handling large responses

- Add `formatSize` utility function to format response size
- Add unit tests for `formatSize` utility function

* fix: update danger color in light theme
2025-06-14 20:44:08 +05:30
Anoop M D
b6fb5e02d4 Merge pull request #4893 from stupidly-logical/fix/watcher_err_handling
Fix watcher error message typo
2025-06-14 13:51:12 +05:30
Yash
5313704d84 Fix watcher error message typo 2025-06-14 13:25:21 +05:30
Anoop M D
b147f14fef Merge pull request #4758 from ShrutiShahi18/main
Added Hindi translation of Readme file
2025-06-13 22:31:06 +05:30
sanish-bruno
66fe1528df add: new Bearer Auth undefined test case and update Authorization header format 2025-06-13 14:42:57 +05:30
sanish-bruno
a598cda624 fix: handle undefined bearer token to send an empty string instead 2025-06-13 14:16:02 +05:30
ramki-bruno
69f218cc16 Merge branch 'main' into docs/update-linux-installation-instructions-via-apt 2025-06-12 18:36:45 +05:30
Pragadesh-45
e1c12ea699 fix: update danger color in light theme 2025-06-11 22:57:45 +05:45
Pragadesh-45
9801e91720 feat: add prompt for handling large responses
- Add `formatSize` utility function to format response size
- Add unit tests for `formatSize` utility function
2025-06-11 22:57:29 +05:45
Pooja
364fb45e97 add: pre and post tests in runner (#4878) 2025-06-11 22:38:58 +05:30
Pooja
5c9981aca2 Fix: AWS v4 auth empty fields displaying "undefined" after save (#4814)
* Fix: AWS v4 auth empty fields displaying "undefined" after save
2025-06-11 14:27:45 +05:30
Pooja
fc697bf81b feat: support chai in scripts (#4552)
feat: support chai in scripts
2025-06-10 22:41:11 +05:30
lohit
9bc07afc77 initRunRequestEvent function for initializing request execution related details (#4863)
added a initRunRequestEvent function resetting and initializing request run event related details
2025-06-10 21:05:39 +05:30
Pooja
e4ae857df3 Merge pull request #4693 from pooja-bruno/mv/isValidValue-in-common-file
Fixed a bug causing secrets to appear as null instead of an empty value.

rm isValidValue and directly handle it in encryptString and `decryptString` function
2025-06-09 13:50:25 +05:30
georgegiosue
9e628fa6be docs(contributing): update Spanish contribution guide for clarity and accuracy 2025-06-08 12:36:55 -05:00
Anoop M D
3d26833b8a Merge pull request #4837 from maintainer-bruno/feat/develop-hot-reload-js
feat(dev): enhance hot reload development setup
2025-06-07 13:21:13 +05:30
sreelakshmi-bruno
1089a52171 Tests for responseSize component (#4750)
---------

Co-authored-by: lohit <lohit@usebruno.com>
2025-06-06 01:54:01 +05:30
lohit
9dde2df475 Merge pull request #4661 from devendra-bruno/fix/gql-introspection-variable-interpolation
Added combined Vars for prepareGqlIntrospectionRequest for all interp…
2025-06-05 18:05:45 +05:30
Maintainer Bruno
1cc94e8ffe feat(dev): enhance hot reload development setup 2025-06-04 16:56:22 +05:30
lohit
223f79a3e2 Merge pull request #4694 from usebruno/feature/playwright
Improvements in Playwright setup and added tests for running bruno-testbench
2025-06-04 15:18:34 +05:30
lohit
5dc6f6757d Merge pull request #4765 from lohxt1/single_line_editor_onedit
fix: single line editor component onChange validations update
2025-06-04 14:48:48 +05:30
lohit
e20fe790a6 Merge pull request #4782 from ramki-bruno/fix/proxy-pass-encoding
Fix: Special URI characters in proxy username/password is giving error
2025-06-04 14:48:26 +05:30
ramki-bruno
a006fe8230 Move Playwright tests to Tests Workflow itself
Currently the test-results and annotations form jobs are getting added
to random Workflow and there is no fix for it right now
Ref: https://github.com/EnricoMi/publish-unit-test-result-action/issues/12
Also Playwright tests have the same triggers as Tests, so no need to
keep it separate.
2025-05-30 13:57:44 +05:30
ramki-bruno
577d54b432 Added Playwright test for bruno-testbench, few sanity tests and improvements
- Trace will capture snapshots now
- Added ability to add init Electron user-data, preferences and other
  app settings.
- Improved test Fixtures
  - Use tempdir for Electron user-data
  - Ability to reuse app instance for a given init user-data by placing
    them in a folder(`pageWithUserData` Fixture)
  - Ability to create tests with fresh user-data(`newPage` Fixture)
- Improved logging
- Improved the env vars to customize the Electron user-data-path
2025-05-30 13:57:44 +05:30
maintainer-bruno
afaebf6b3d Merge pull request #4796 from lohxt1/collection_auth_default_values_issue
fix: collection auth default value access fix and validations
2025-05-29 18:28:57 +05:30
lohit
6e89001825 fix: collection auth default value access fix and validations 2025-05-29 17:45:42 +05:30
ramki-bruno
cb611c6510 Fix: Special URI characters in proxy username/password is giving error
URI-encoding the _username_ and _password_ before creating the proxy URI
which then gets passed to `HttpsProxyAgent` and `HttpProxyAgent`
respectively.
2025-05-28 14:45:21 +05:30
lohit
e7dd78ea53 Merge pull request #4775 from lohxt1/axios_instance_redirect_error_fix
fix: return the actual axios error in bruno-cli' axios-instance for url-redirect related errors
2025-05-27 20:27:48 +05:30
lohit
9ad0f2d169 revert custom error messages 2025-05-27 19:40:51 +05:30
lohit
bf19645282 revert test update 2025-05-27 19:40:22 +05:30
lohit
bb01199877 updates 2025-05-27 19:17:05 +05:30
lohit
5627c5624f updates 2025-05-27 19:16:29 +05:30
lohit
8e23a7054f Merge pull request #4770 from lohxt1/error_requests_cli_tests_issue
fix: consider request execution errors as `CLI Tests` workflow failure
2025-05-27 18:49:02 +05:30
lohit
d820069371 return the actual axios error with the custom error message in bruno-cli axios-instance 2025-05-27 18:41:47 +05:30
devendra-bruno
6f9daadcfb Update index.js Removed duplicate variable 2025-05-27 15:44:07 +05:30
lohit
2de9b87c6f consider errored request as a collection run fail 2025-05-27 15:30:54 +05:30
devendra-bruno
8d5d952026 Added runtimeVars in prepareGqlIntrospectionRequest 2025-05-27 14:38:48 +05:30
lohit
178773d63a Merge pull request #4173 from Pragadesh-45/feat/custom-installation-path
Feat/ Custom installation path for GUI installer on Windows
2025-05-27 11:49:29 +05:30
lohit
7994946c85 Merge pull request #4764 from lohxt1/shortcut_key_new_request_issue
fix: new request shortcut key
2025-05-27 11:49:15 +05:30
lohit
b020255269 Merge pull request #4662 from sanjaikumar-bruno/fix/cli-not-following-redirects
feat: enhance axios instance with redirect handling and cookie management in CLI
2025-05-27 11:48:43 +05:30
devendra-bruno
afb2d3dffd Updated resolved variable assignment and testcases 2025-05-26 22:52:37 +05:30
lohit
73b0f0919d Merge pull request #4679 from anusree-bruno/bugfix/timestamp-current-time
fix: ensure timestamp and isoTimestamp return current time instead of random values
2025-05-26 22:29:53 +05:30
Pragadesh-45
8975b9eef6 fix: update Windows build configuration for icon and publisher name 2025-05-26 21:06:01 +05:45
lohit
865e813b42 revert test bru file 2025-05-26 20:45:33 +05:30
lohit
51f36b1903 Merge pull request #4038 from Chriss4123/feature/localhost-secure-context
feat: Add RFC 6761–compliant localhost loopback checks so `secure` cookies work on localhost (fixes: #1676)
2025-05-26 17:16:33 +05:30
Clay Powers
6b122d7262 Switch GraphQL variables code editor to json linting (#4756) 2025-05-26 16:55:11 +05:30
devendra-bruno
9f1aed3209 Refactored fetch-gql-schema-handler.spec.js 2025-05-26 16:42:18 +05:30
devendra-bruno
ce1110bdd4 Added interpolate for header values 2025-05-26 16:39:40 +05:30
devendra-bruno
788569a5f4 Added testcases for prepare-gql-introspection-request.spec.js 2025-05-26 16:39:07 +05:30
devendra-bruno
91397eaf57 Renamed fetchGqlSchema to fetchGqlSchemaHandler 2025-05-26 16:38:09 +05:30
devendra-bruno
c293ceefcf Refactored fetch-gql-schema-handler.spec.js 2025-05-26 16:37:28 +05:30
lohit
a8e5ce9c13 fix: new request shortcut key 2025-05-26 14:58:25 +05:30
anusree-bruno
8ac916b0ff removed unwanted tests 2025-05-26 14:49:21 +05:30
anusree-bruno
8d860a051c replace real time with mocked time in faker tests 2025-05-26 14:43:23 +05:30
lohit
256f63dd38 single line editor comp onChange validations 2025-05-26 10:20:22 +05:30
devendra-bruno
0948964677 Revert changes to common.spec.js 2025-05-26 09:47:43 +05:30
Shruti Shahi
1b52bb27f7 Added Hindi translation of Readme file 2025-05-24 01:52:54 +05:30
Anoop M D
4ac2c4ac34 Merge pull request #4706 from ved-bruno/e2e_support
Playwright: Support Element Verification
2025-05-23 21:11:27 +05:30
maintainer-bruno
7c27193983 chore: add CODEOWNERS file for repository maintenance 2025-05-23 16:57:48 +05:30
ramki-bruno
2c3d2ff6a7 Make Secure-local-cookies work in CLI as well 2025-05-23 13:49:56 +05:30
Chriss4123
a4fff01647 Support Secure cookies for localhost and loopback addresses 2025-05-23 12:35:04 +05:30
sanjai0py
2cd985faf7 Remove test file for redirects with cookies 2025-05-23 08:58:28 +05:30
ZieglerZhu
ec9d63219f docs(readme): update readme_cn.md
- Added introduction of commercial version
- Added Table of Contents
- Updated installation guide via package managers
- Updated important links
- Adjusted document structure, optimized title hierarchy
2025-05-22 23:38:33 +08:00
sanish chirayath
9a35302d4b Feature: implemented bru.interpolate (#4122)
* feat: enhance variable highlighting in CodeMirror and update interpolation method

* feat: add interpolate function to bru shim and corresponding tests

- Implemented the `interpolate` function in the bru shim to handle variable interpolation.
- Added a new test case for the `interpolate` function to verify its functionality with mock variables.

* feat: enhance interpolate function to support object interpolation

* feat: add translation support for pm.variables.replaceIn to bru.interpolate

* revert: eslint config changes

* revert: eslint config changes

* fix: update method call to use correct interpolation function in Bru class

* refactor: added jsdoc to codemirror highlighting code

* fix: higlighting for multiline editor
2025-05-22 15:37:15 +05:30
Pooja
553f7675f2 fix: request timer reset while switching tabs (#4165)
* fix" request timer reset while switching tabs

* fix

* rm: extraReducers

* improve: logic

* fix: pass startTime as prop

* fix

* fix: directly use collection in setRequestStartTime

* rm: reseting start time null
2025-05-22 15:36:26 +05:30
devendra-bruno
3e714ab9f8 Updated handler fetch-gql-schema 2025-05-21 17:54:53 +05:30
devendra-bruno
f2e9a6a502 Added folder level variable support 2025-05-21 17:39:10 +05:30
devendra-bruno
b924e15afa Added testcases for fetch-gql-schema-handler 2025-05-21 17:35:47 +05:30
devendra-bruno
b0c74909ba Updated argument request object for useGraphqlSchema hook 2025-05-21 17:35:17 +05:30
devendra-bruno
548a6b4319 Rename combinedVars to resolvedVars 2025-05-21 17:34:36 +05:30
sanjai0py
b299879b82 Refactor saveCookies function to remove disableCookies parameter and streamline cookie handling in response interceptors 2025-05-21 17:00:22 +05:30
Pooja
3696562414 fix: circular recursion for openapi import (#4729) 2025-05-21 15:10:35 +05:30
devendra-bruno
e02c6c274b Fix/svg render respone panel (#4655)
* Refactor getContentType in utils

* Add testcases for getContentType

* Refactor getContent

* Refactor getContent

* Refactor getContent

* Added testcase of case insensitivity

* Added content-type case in sensitive

* Refactor testcase spec

* Added testcases for empty content-type
2025-05-21 13:45:06 +05:30
devendra-bruno
9c9afaf78f Extracted fetchGqlSchema handler seperate from ipc handler 2025-05-21 06:42:19 +05:30
devendra-bruno
6cde453032 Added test for prepareGqlIntrospectionRequest 2025-05-21 06:41:18 +05:30
devendra-bruno
8f06889996 Remove mergeEnvironmnetVariable method from spec file 2025-05-21 06:40:21 +05:30
devendra-bruno
52662f0766 Updated testcases in prepare-gql-introspection spec 2025-05-19 17:39:39 +05:30
sanjai0py
ab0a4b8140 Add disableCookies option to axios instance and saveCookies function 2025-05-19 15:08:12 +05:30
sanjai0py
1b268ae9db Merge branch 'main' into fix/cli-not-following-redirects 2025-05-19 14:36:54 +05:30
ved-bruno
8debb9fd11 made suggested changes for support element verification 2025-05-19 14:02:34 +05:30
pooja-bruno
9173ffbdee improve: use common getTreePathFromCollectionToItem function 2025-05-19 12:42:10 +05:30
naman-bruno
7c07488e16 Merge pull request #4697 from lohxt1/req_get_name_test
fix: bruno converters test for reg.getName()
2025-05-16 21:52:30 +05:30
lohit
6073a9e2c3 fix bruno converters test for reg.getName() 2025-05-16 21:27:00 +05:30
lohit
9c652f86c9 Merge pull request #4696 from naman-bruno/bugfix/noproxy-option
add: noproxy flag in options
2025-05-16 21:06:29 +05:30
naman-bruno
3c0090d86f fix: runSingleRequest function 2025-05-16 21:02:24 +05:30
naman-bruno
9132755d49 add: noproxy in options 2025-05-16 20:52:15 +05:30
lohit
2a44691cb3 Merge pull request #4590 from poojabela/feat/add-getName-api-for-script
feat: add `req.getName` & `bru.getCollectionName` api
2025-05-16 20:21:35 +05:30
lohit
0d8a696498 Merge pull request #4609 from pooja-bruno/feat/extend-support-for-more-auth-for-folder-level
feat: extend support for more auth in folder level
2025-05-16 20:20:33 +05:30
lohit
bfa2706598 Merge pull request #4366 from Pragadesh-45/fix/import-curl
Feat: Enhance curl parsing for multipart form data
2025-05-16 20:20:18 +05:30
ved-bruno
5fdb52388a support element verification 2025-05-16 19:34:39 +05:30
Pooja
799dc9a1ca feat: add function in bruno converters package (#4669)
* feat: add  function in bruno converters package

* add: example for openapi yaml to bruno conversion

* add: converting json to yaml in converters

* fix
2025-05-16 17:26:40 +05:30
naman-bruno
2bb56e8a4b Fix: properly handling redirects with status code (#4561)
* Fix: properly handling redirects with status code

* fix: updated redirect logic for method change
2025-05-16 17:14:37 +05:30
Pragadesh-45
084d2bf692 test: add unit tests for basic functionality, headers, auth, and form data handling in parseCurlCommand 2025-05-16 14:32:30 +05:45
Pragadesh-45
10640c7561 feat: enhance curl parsing for multipart form data
- Updated `parseCurlCommand` to handle `-F` and `--form` flags, allowing for multiple form fields with file uploads.
- Adjusted `curlToJson` to set `Content-Type` for multipart data and handle binary data correctly.
2025-05-16 14:32:05 +05:45
naman-bruno
9f044c48fe Added proxy flag for cli (#3963)
* system level proxy depends on proxy flag

* added proxy flag

* fix: proxy flag behaviour

* fix: noproxy flag logic
2025-05-16 14:02:11 +05:30
devendra-bruno
5567e1b7f2 Fixed typo in prepareGqlIntrospectionRequest 2025-05-16 00:47:49 +05:30
devendra-bruno
3cd18d1e16 Added testcases for prepare-gql-introspection-request 2025-05-16 00:43:58 +05:30
devendra-bruno
9d3e42b5d4 Update prepareGqlIntrospectionRequest change assignment sequence 2025-05-16 00:43:27 +05:30
devendra-bruno
0f318c26c2 Updated precedence in combinedVars object 2025-05-16 00:42:27 +05:30
lohit
c2271945c4 Merge pull request #4685 from lohxt1/pr_4447
chore: merge main to oauth2_additional_params feat branch
2025-05-15 23:36:12 +05:30
lohit
0e6c36f62c fix: save disabled additional params rows 2025-05-15 23:19:50 +05:30
lohit
6d38f2b38c Merge branch 'main' into lint_gh_workflow_step 2025-05-15 23:09:57 +05:30
Anoop M D
79f4e69a05 Merge pull request #4160 from usebruno/feature/custom-user-data-path-for-dev 2025-05-15 16:18:28 +05:30
ramki-bruno
f13148af3d Added option to customize userData path on dev mode
If `ELECTRON_APP_NAME` env-variable is present and its development mode,
then the `appName` and `userData` path is modified accordingly.

e.g.
```sh
ELECTRON_APP_NAME=bruno-dev npm run dev:electron
```

Note: This doesn't change the name of the window or the names in lot of
other places, only the name used by Electron internally.
2025-05-15 16:12:51 +05:30
devendra-bruno
6598d23ff0 Removed mergeEnvrionmentVariables tests from common.spec.js 2025-05-15 15:57:43 +05:30
devendra-bruno
c83436655c Remove mergeEnvironmnetVariables from common utils 2025-05-15 15:57:00 +05:30
devendra-bruno
62595c519c Added lodash merge for combining vars before interpolateVars 2025-05-15 15:56:30 +05:30
anusree-bruno
d2eb2d2941 fix: ensure timestamp and isoTimestamp return current time instead of random values 2025-05-15 14:11:53 +05:30
betawait
1d12bebce4 Fix: Allow empty Content-Type when no body (#1693)
By default Axios will set the Content-Type for POST/PUT/PATCH requests
to "application/x-www-form-urlencoded" if the Content-Type header is not
specified.

This explicitly sets the content type to "false" when there the body
mode is set to "none", and the user has not set an explicit content type
themselves. Setting the content type to false directs Axios not to send
a Content-Type header.
2025-05-15 07:40:21 +09:00
Anoop M D
942c0ee113 Merge pull request #4671 from lohxt1/lint_gh_workflow_step
add lint step to the unit-tests gh workflow
2025-05-14 17:58:54 +05:30
pooja-bruno
fbd3a38587 fix 2025-05-14 17:55:50 +05:30
pooja-bruno
45b660985e fix: ui 2025-05-14 17:45:03 +05:30
pooja-bruno
0888125899 add: default auth mode inherit in folder 2025-05-14 16:12:48 +05:30
pooja-bruno
c85d9bcd84 fix: folder inherit auth 2025-05-14 16:01:42 +05:30
lohit
dbf8af1146 Merge branch 'main' into lint_gh_workflow_step 2025-05-14 15:41:35 +05:30
lohit
d7ccf1454e revert lint-staged step, make lint check as part of gh unit-tests workflow 2025-05-14 14:05:49 +05:30
Anoop M D
652d447f8b Merge pull request #4667 from usebruno/feature/playwright
Customize Playwright reporter and retries for dev and CI env
2025-05-14 13:28:03 +05:30
devendra-bruno
8e91640084 Added mergeEnvironmentVariables method for gql prep method 2025-05-14 12:25:41 +05:30
devendra-bruno
0ca2891166 Added mergeEnvironmentVariables method in electron common utils export 2025-05-14 12:24:09 +05:30
devendra-bruno
5000bb8db3 Added testcases for mergeEnvironmentVariables method 2025-05-14 12:23:32 +05:30
devendra-bruno
9927424826 Added mergeEnvironmentVariables method in electron common utils 2025-05-14 12:22:39 +05:30
ramki-bruno
2f58379feb Customize Playwright reporter and retries for dev and CI env 2025-05-14 11:54:56 +05:30
sanjai0py
c14d3f4274 feat: add test case for redirects with cookie authentication 2025-05-14 10:46:14 +05:30
Anoop M D
d4673a2f07 Merge pull request #4665 from lohxt1/eslint_node_space_issue
fix: eslint - javascript heap out of memory
2025-05-14 00:34:03 +05:30
Anoop M D
3a0c94577f Merge pull request #4666 from sreelakshmi-bruno/update_contributing_guidelines
Updating contributing.md
2025-05-13 23:59:59 +05:30
sanjai0py
5a4e33e503 Merge branch 'main' into fix/cli-not-following-redirects 2025-05-13 20:07:29 +05:30
sanjai0py
5649799167 feat: add maxRedirects configuration to runSingleRequest 2025-05-13 20:02:29 +05:30
sreelakshmi-bruno
c407b73c22 Updating contributing.md 2025-05-13 19:42:00 +05:30
lohit
361add3385 handle folder run action while a collection run is in progress (#4658)
Co-authored-by: lohit <lohit@usebruno.com>
2025-05-13 19:41:39 +05:30
lohit
9d6ab69d37 eslint - node out of memeory issue 2025-05-13 19:21:30 +05:30
sanjai0py
0f6da35c0b feat: enhance axios instance with redirect handling and cookie management 2025-05-13 17:27:55 +05:30
devendra-bruno
ad3f5de99a Added combined variable object for gqlIntrospectionRequest 2025-05-13 17:05:37 +05:30
devendra-bruno
2de7ba0d0c Added combined Vars for prepareGqlIntrospectionRequest for all interpolate 2025-05-13 16:06:20 +05:30
ramki-bruno
b699088dd6 Create/Import collection UX improvements (#4540)
* Fix: Improve UX for selecting location when create/import collection

Allow editing the input path where previously the `<input>` is marked
`readonly`.
Also this will allow automating test using Playwright.

* Fix: Import-collection select-location Modal closes on error

* Improved error-toast for creating and importing collections

- Added a util for formatting the error form IPC
- Updated Toast global styles to prevent text overflow.
  Whenever long file paths are shown, it overflows the Toast container.
2025-05-13 14:25:35 +05:30
ganesh
458c070004 Fix: Specify Node.js version in Contributing Guide (#4656)
* fix node version on contributing file

* updated to node 22 version
2025-05-13 14:10:10 +05:30
Anoop M D
babac6df3c Merge pull request #4651 from usebruno/feature/playwright
Playwright Codegen and CI setup
2025-05-12 22:08:31 +05:30
Pooja
f58477931f feat: add support for oauth2 in cli (#4578)
Co-authored-by: Pooja Belaramani <109731557+poojabela@users.noreply.github.com>
2025-05-12 21:37:42 +05:30
lohit
2171d491a6 Merge pull request #4641 from lohxt1/folder_sequencing_cli
refactor: `bruno-cli` - follow folder/request sequences during collection runs
2025-05-12 21:19:58 +05:30
ramki-bruno
aa911f88f2 Playwright Codegen and CI setup
- Improved the Codegen setup
  - Removed the app-launch related boilerplate from tests
  - Enable recording mode by default
  - Option to provide the test file name to save the recording
- Added GitHub workflow to run Playwright tests with Electron in
  Headless mode(mocking display using `xvfb`).
2025-05-12 20:35:05 +05:30
lohit
bdbcaeff67 updates 2025-05-12 20:06:26 +05:30
lohit
b2756b3c63 updates 2025-05-12 17:37:45 +05:30
lohit
27f11ab583 updates 2025-05-12 17:19:13 +05:30
lohit
2776970317 revert collection-pathname param 2025-05-12 16:57:27 +05:30
Anoop M D
9d28bf7e82 Merge pull request #4571 from pooja-bruno/feat/extend-cli-auth-for-Inherit-and-req
feat: extend cli auth for inherit and request
2025-05-12 16:15:17 +05:30
ramki-bruno
6455b00742 Removed old Playwright setup 2025-05-12 12:12:21 +05:30
lohit
16179a3b50 refactored getCollectionJsonFromPathname function and added tests 2025-05-11 23:08:44 +05:30
Anoop M D
6a37c9d076 Merge pull request #4636 from sreelakshmi-bruno/add-build-commands
Adding build instructions for new packages
2025-05-10 17:03:14 +05:30
Anoop M D
1915b1c00a Fix/add missing translations (#4637)
* fix: add missing deps
* feat: add missing translations
* fix: regex tranasaltion for to.have.headers
2025-05-10 16:59:21 +05:30
lohit
a9982d6e28 removed unused collectionPathnmae prop to components (#4640)
Co-authored-by: lohit <lohit@usebruno.com>
2025-05-10 15:11:26 +05:30
sanish-bruno
1daeb8fe93 fix: regex tranasaltion for to.have.headers 2025-05-09 19:12:52 +05:30
sanish-bruno
3dfb158382 feat: add missing translations 2025-05-09 17:56:32 +05:30
sanish-bruno
fb7d247fa7 fix: add missing deps 2025-05-09 17:37:16 +05:30
lohit
6bf2312a94 Merge branch 'main' into folder_sequencing_cli 2025-05-09 16:34:50 +05:30
sreelakshmi-bruno
0cdcb83a7a Adding build instructions for new packages 2025-05-09 15:48:49 +05:30
sanish chirayath
e4f48e81fc feat: add setBody test script to bruno-tests collection (#4415) 2025-05-09 14:16:29 +05:30
lohit
1d32a95a09 Merge pull request #4628 from lohxt1/fix_tests_converters_package
fix: tests for postmanToBrunoEnvironment function
2025-05-09 01:45:56 +05:30
lohit
4c934a78a6 fix tests for postmanToBrunoEnvironment function 2025-05-09 00:07:58 +05:30
Pooja
c47bc86d37 fix: Improve Variable Highlighting in Code Generation and Environment Views (#4593) 2025-05-08 21:53:14 +05:30
Sanjai Kumar
a125781312 feat/replace unsupported characters in env key during pm import (#4618)
---------

Co-authored-by: sanjai0py <sanjailucifer666@gmail.com>
2025-05-08 21:52:58 +05:30
sanish chirayath
dfa951e574 Feature: postman to bru translator (#4534) 2025-05-08 21:51:21 +05:30
naman-bruno
76779e6f95 Merge pull request #4615 from pooja-bruno/feat/add-openapi-to-bruno-import-in-cli
Feat: add openapi to bruno import in cli
2025-05-08 19:53:00 +05:30
lohit
e9a79a32da lint error fixes (#4623)
Co-authored-by: lohit <lohit@usebruno.com>
2025-05-08 18:12:16 +05:30
lohit
967170a7b2 eslint for bruno-app and bruno-electron packages (#4622)
Co-authored-by: lohit <lohit@usebruno.com>
2025-05-08 18:09:55 +05:30
Anoop M D
3326784315 Merge pull request #4620 from lohxt1/fix_regex_tests
fix: tests for sanitizeName function
2025-05-08 18:07:41 +05:30
lohit
fc553e1009 fix sanitize name function tests in bruno-electron 2025-05-07 22:24:52 +05:30
lohit
da172ff9b5 fix sanitize name function tests 2025-05-07 22:12:57 +05:30
lohit
fc422853ef update T_RunnerResults type to include summary prop (#4617)
Co-authored-by: lohit <lohit@usebruno.com>
2025-05-07 19:19:40 +05:30
Pooja Belaramani
2852c07ec7 feat: support tv4 as a inbuilt lib (#4589) 2025-05-07 17:44:29 +05:30
Anoop M D
ead1c9ecab Merge pull request #4542 from pooja-bruno/fix/app-crash-when-we-rename-folder-in-fs
fix: app crash when we rename folder in fs
2025-05-07 17:42:09 +05:30
Anoop M D
5b5066577f Merge pull request #4373 from vishnuprasanth-j/bugfix/regression-4350
Fix: Leading dot is not allowed for collections, folders and requests
2025-05-07 17:39:25 +05:30
sreelakshmi-bruno
4af0bb3943 Fix: ResponseSize component logic to handle size when it's undefined (#4613)
* Fix: ResponseSize component logic to handle size when it's undefined
* Improved check for valid response size

---------

Co-authored-by: Sreelakshmi Jayarajan <sreelakshmi@Sreelakshmis-MacBook-Air.local>
2025-05-07 16:59:35 +05:30
pooja-bruno
f2eaa79318 Feat: add openapi to bruno import in cli 2025-05-07 15:36:21 +05:30
lohit
2ee7ce5829 persist request/folder uids after request/folder resequencing and ui updates (#4611)
* move file/folder uids to new paths

* drag file/folder preview ui updates, can item be dropped ui hint check

---------

Co-authored-by: lohit <lohit@usebruno.com>
2025-05-06 22:20:59 +05:30
pooja-bruno
0d7c94e7e9 add: auth for other 2025-05-06 18:41:40 +05:30
pooja-bruno
9e29821012 feat: extend support for more auth in folder level 2025-05-06 17:56:34 +05:30
lohit
38c307d6f1 feat: folder sequencing (#4595)
Co-authored-by: Pooja Belaramani <pooja@usebruno.com>
Co-authored-by: naman-bruno <naman@usebruno.com>
Co-authored-by: lohit <lohit@usebruno.com>
2025-05-05 16:52:00 +05:30
lohit
520567793a feat(cli): Refactor request runner and improve folder sorting
~ remove duplicate code by consolidating request collection functionality
~ add proper sorting of folder and request items based on sequence numbers
~ add error request count to run summary output
~ update dev dependencies with proper markings in package-lock.json and removed previously added currently reverted entries
2025-05-03 23:50:12 +05:30
poojabela
e0fb379511 add: bru.collectionName api 2025-04-30 17:25:42 +05:30
poojabela
ba9362ccb2 add: getName in collection 2025-04-30 15:36:44 +05:30
poojabela
261a36c435 add: getName in hint 2025-04-30 15:29:10 +05:30
poojabela
cb92e46f8d feat: add req.getName api 2025-04-30 15:14:36 +05:30
Pooja Belaramani
126186041e add: tests for request level auth 2025-04-28 15:18:18 +05:30
Pooja Belaramani
6379e1703c feat: extend cli auth for inherit and request 2025-04-28 12:52:52 +05:30
Pooja Belaramani
2b246e431b change: no found folder tab 2025-04-25 15:58:53 +05:30
Anoop M D
526fcabffe Support Importing Collection Level Auth from Postman (Merge pull request #4475) 2025-04-22 21:27:06 +05:30
Anoop M D
75ff31f0cf Include globalEnvironmentVariables in runPostResponseVars result (Merge pull request #4520)
Include globalEnvironmentVariables in runPostResponseVars result
2025-04-22 20:30:43 +05:30
Pragadesh-45
46dab6e474 test: add request authentication tests for basic and bearer auth handling 2025-04-22 20:25:27 +05:45
Pragadesh-45
c7e8c07d40 test: add folder authentication tests for basic, bearer, API key, and digest auth 2025-04-22 19:56:03 +05:45
Pragadesh-45
932d2b77dc test: add collection authentication tests for basic, bearer, API key, and digest auth 2025-04-22 19:10:28 +05:45
Pragadesh-45
049de84cbb test: refactor postman-to-bruno.spec.js by adding a simple collection 2025-04-22 18:00:49 +05:45
pooja-bruno
3bd44ea7ef Refactor: Reorganize Postman translation tests into modules (#4524) 2025-04-22 16:42:09 +05:30
pooja-bruno
317ccccfc6 fix: Add null checks and fallbacks to Bruno-to-Postman converter to… (#4525) 2025-04-22 16:40:15 +05:30
lohit
220da6b58e feat: Moved logic related to html report generation to bruno-common package (#4536)
---------
Co-authored-by: lohit jiddimani <lohitjiddimani@lohits-MacBook-Air.local>
2025-04-22 16:35:54 +05:30
Pragadesh-45
6a7750d354 refactor: rename test files and update import paths for postman-to-bruno tests 2025-04-22 15:19:04 +05:45
Pooja Belaramani
529803f791 fix: app crash when we rename folder in fs 2025-04-22 13:18:25 +05:30
Pragadesh-45
4c23ab5664 Merge remote-tracking branch 'origin/main' into fix/import-pm-collection-improvements 2025-04-21 19:03:34 +05:45
Tim Nikischin
e3c28fd0ec feat: style skipped requests in runner and show skipped count (#3853)
Mostly taken from @JorgeTrovisco 's implementation #2397
Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
2025-04-19 18:14:45 +05:30
Anoop M D
56ab61c29c Fixed issue related to postman environment imports failure (#4523) 2025-04-18 21:33:12 +05:30
pooja-bruno
d3056ba843 Fix: Folder drag-and-drop crash (#3944) 2025-04-18 02:48:37 +05:30
lohit
e34e2ec1f1 feat: support object and array interpolation in bruno-common interpolate fn (#4519)
---------
Co-authored-by: Pooja Belaramani <pooja@usebruno.com>
Co-authored-by: lohit jiddimani <lohitjiddimani@lohits-MacBook-Air.local>
Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
2025-04-18 00:47:02 +05:30
lohit jiddimani
524bb5e4b7 fix: console errors if any while importing postman env collections 2025-04-17 20:56:22 +05:30
lohit jiddimani
3f8ea7764e fix: add JSON parsing and error handling for Postman environment imports
~ return parsed JSON object instead of raw file string
2025-04-17 20:41:14 +05:30
anusree-bruno
f0d1e6936e Include globalEnvironmentVariables in runPostResponseVars result 2025-04-17 16:18:08 +05:30
Andreas Wirth
9a21eec1b9 Bugfix: Add cheerio and xml2js modules to post-response scripts (#4516)
* Bugfix: Add cheerio and xml2js modules to post-response scripts
* chore: improved cheerio and xml2js test
---------

Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
2025-04-17 01:31:53 +05:30
pooja-bruno
1703346bb6 feat: improve postman translations: pm.request and pm.response (#4517) 2025-04-16 19:19:31 +05:30
ramki-bruno
b93d8e73a2 Allow leading dot for file and folder names
Co-authored-by: vishnuprasanth-j <jvpvis6@gmail.com>
2025-04-16 03:26:38 +05:30
ramki-bruno
17c9813c98 Regularize RegEx patterns for validating filenames
- Fixed inconsistency in validating last character between
  bruno-electron and bruno-app.
- Fixed inconsistency in sanitizing first character between
  bruno-electron and bruno-app.
- Updated the comments to accurately reflect the patterns
- Fixed inconsistencies in escaping certain characters in the patterns
  itself.
2025-04-16 03:20:58 +05:30
pooja-bruno
e5ebe20a20 feat: add insomnia v5 import (#4468) 2025-04-16 02:37:48 +05:30
Jonathan Perlman
b5861dae39 Fix Digest auth header field key value extraction 2025-04-15 14:31:08 -04:00
pooja-bruno
54a03fd0d3 fix: lint errors for atob/btoa redefinition (#4509)
* fix: lint errors for atob/btoa redefinition
2025-04-15 20:35:55 +05:30
Sanjai Kumar
e8affcfde9 feat: add tests for mock variable interpolation in interpolate function (#4507)
* feat: add tests for mock variable interpolation in interpolate function
* test: enhance mock variable interpolation tests for additional types and JSON validation

---------
Co-authored-by: sanjai0py <sanjailucifer666@gmail.com>
2025-04-15 17:24:24 +05:30
Sanjai Kumar
d376947a91 Move mock builtin vars interpolation to bruno-common for CLI support (#4497)
* move interpolateMockVars function inside the main interpolate logic inside bruno-common.
* improve comments for JSON escaping logic in interpolate function
* update faker-functions to use CommonJS module syntax to satisfy jest and add regex validation tests
---------

Co-authored-by: sanjai0py <sanjailucifer666@gmail.com>
Co-authored-by: ramki-bruno <ramki@usebruno.com>
2025-04-15 00:14:13 +05:30
anusree-bruno
5f112a318d added option to revert changes 2025-04-15 00:11:41 +05:30
Anoop M D
59e38fbdb0 Merge pull request #4487 from Skrivoo/bugfix/local_dev_requests_build
Fix: Missing bruno-requests module in `setup.js` and `package-lock.json`
2025-04-14 13:07:58 +05:30
Anoop M D
492449b7c5 Merge pull request #4483 from usebruno/fix/mock-builtin-bugs
Fix: Mock/Random built-in variables related issues
2025-04-14 12:11:44 +05:30
david.skrivanek
7cd21636d6 fix: setup file to build bruno-requests package 2025-04-11 23:42:57 +02:00
ramki-bruno
6ff49589be Fix: Line-breaks in $<mock> built-ins are breaking JSON req body 2025-04-11 17:03:19 +05:30
ramki-bruno
c950806541 Fix: Falsy values from $<mock> built-ins are not getting interpolated. 2025-04-11 12:50:21 +05:30
Pragadesh-45
3dcc12042f fix: add watch script for bruno-converters workspace 2025-04-10 21:14:22 +05:45
Pragadesh-45
92925648e6 fix: OAuth2 key value retrieval 2025-04-10 21:14:22 +05:45
Pragadesh-45
811c492bce fix: improve URL construction by handling empty input and filtering invalid query parameters 2025-04-10 21:14:22 +05:45
Pragadesh-45
73fa2e19e4 fix: enhance error handling for unsupported Postman schema versions and invalid JSON format 2025-04-10 21:13:49 +05:45
Anoop M D
921e1af72b Merge pull request #2958 from lzl0304/fix-2508
bugfix/chokidar disables globbing
2025-04-10 20:10:42 +05:30
pooja-bruno
cc905da630 Fix: Prevent --bail option from treating skipped requests as failures (#4166) 2025-04-10 19:58:08 +05:30
pooja-bruno
74bbfce8a0 fix: update global env in collection runner (#4135)
* fix: update global env in collection runner
2025-04-10 19:54:44 +05:30
pooja-bruno
8b67a0423d fix: header key variables not interpolating with capital letters (#4264) 2025-04-10 19:50:17 +05:30
Pragadesh-45
f1d527aa9c feat: implement support for various authentication types in Postman to Bruno converter 2025-04-10 18:55:03 +05:45
0xflotus
9e45d4d227 chore: updated required node version in german contributing file (#3875)
* chore: updated required node version in german contributing file
---------

Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
2025-04-10 14:59:44 +05:30
Sanjai Kumar
2dd0424d8f Add @usebruno/requests package with digest authentication support (#4417)
* Add @usebruno/requests package with digest authentication support
---------

Co-authored-by: sanjai0py <sanjailucifer666@gmail.com>
Co-authored-by: ramki-bruno <ramki@usebruno.com>
2025-04-10 14:49:21 +05:30
ganesh
838f25b9db added example to readme file (#4471)
* added example to readme file
* modified example
2025-04-10 03:55:30 +05:30
Anoop M D
8809469f8e Merge pull request #4465 from pooja-bruno/add/bruno-converters-paclage-in-workflow-file 2025-04-09 14:59:23 +05:30
Pooja Belaramani
289f138c2a add: bruno converters package in workfow file 2025-04-09 11:35:14 +05:30
lohxt1
3d0dd60f56 added build step for converters package in the tests' gh workflow script 2025-04-08 20:38:38 +05:30
lohxt1
9bb9a914ac postman-to-bruno converter package fixes 2025-04-08 20:38:38 +05:30
lohxt1
44cef9999c clear stored token when refresh call returns an error 2025-04-08 18:49:04 +05:30
lohxt1
3a792a021c oauth2 refresh token under request pane creates dup network logs 2025-04-08 18:49:04 +05:30
lohit
2e5c63cfb9 improve network error handling, oauth2 logic cleanup, tls settings, and ui/test updates (#4444)
~ axios error interceptor fixes and timeline network logs ui updates
~ axios instance error interceptor now returns promise rejects instead of plain objects
~ fixed digest_auth regression
~ removed the interceptor logic for the oauth2 token url calls
~ timeline network logs ui updates
~ updated oauth2 test collections

* ssl/tls fixes and error handling
~ set the min allowed tls version to 1.0 (TLSv1)
~ proxy/certs/tls setup error handling

* enhance JSON stringification with circular reference handling
- Add getCircularReplacer to safely handle circular references in objects
- Update safeStringifyJSON to support indentation and handle undefined values
~ we currently support digest auth for bruno-cli

---------

Co-authored-by: lohit <lohit@usebruno.com>
Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
2025-04-07 23:03:49 +05:30
Thim
9845363349 Feat: Standalone Package to convert to Bruno collection(Part 2)
This contains the bulk of the changes apart from renaming files.
This is a continuation of #2341.

Co-authored-by: lohit <lohit@usebruno.com>
Co-authored-by: pooja-bruno <pooja@usebruno.com>
2025-04-07 22:24:57 +05:30
Thim
1a6fa7a799 Feat: Standalone Package to convert to Bruno collection(Part 1)
This commit just moves the required files to the new destination
using `git mv` to force Git to recognise it as `Renamed`.
This is a continuation of #2341.

Co-authored-by: lohit <lohit@usebruno.com>
Co-authored-by: pooja-bruno <pooja@usebruno.com>
Co-authored-by: ramki-bruno <ramki@usebruno.com>
2025-04-07 22:24:57 +05:30
lohxt1
6cd44662a8 removed the dup refresh token checkbox field 2025-04-07 19:14:34 +05:30
lohxt1
9daf418886 pass global env vars to the fetch and refresh oauth2 requests 2025-04-07 19:14:34 +05:30
therealrinku
37ee13353d fix: user agent header 2025-04-07 17:40:07 +05:30
Daniel Roberto
8439e8871f fix: Oauth2 toast typo 2025-04-07 13:52:25 +05:30
lohit
84ef5b1044 Merge pull request #4446 from lohxt1/pr_4416
fix(oauth2): improve additional parameters handling and ui updates
2025-04-06 19:05:45 +05:30
lohit
3c85f44ed9 Merge pull request #4416 from naman-bruno/feat/oauth2-additional-params
Oauth2 additional params
2025-04-06 19:04:25 +05:30
lohxt1
dd7ff97090 fix(oauth2): improve additional parameters handling and ui updates
~ fix oauth2 additional parameters encoding and url handling
~ show authorization tab only for authorization_code grant type
~ set active tab based on grant type
~ update schema validation for grant type-specific parameters
~ add url tooltip in responsepane timeline
~ clean up variable naming and parameter handling
2025-04-06 19:01:23 +05:30
ramki-bruno
4c1d3b4f3a Added Playwright-codegen setup 2025-04-04 20:19:26 +05:30
S.M.TALHA
cd3c66cb14 Fix: Matching Brackets pair not highlighting (#4440)
Co-authored-by: smtalha682 <smtalha682@gmail.com>
2025-04-04 20:17:55 +05:30
sreelakshmi-bruno
265b0114e4 Updating issue template for github to track regression bugs (#4437)
---------
Co-authored-by: Sreelakshmi Jayarajan <sreelakshmi@Sreelakshmis-MacBook-Air.local>
2025-04-04 20:11:56 +05:30
ganesh-bruno
17a63d599d capitalize custom and default to follow same theme 2025-04-04 12:59:52 +05:30
ganesh-bruno
d9e87fcd82 updated readme file 2025-04-04 12:59:22 +05:30
Harry.Tao
78c4cb11eb fix unsupport symbolic link folders 2025-04-03 17:18:13 +05:30
tlaloc911
6feea75e45 fix console error Invalid DOM property stroke-width
Invalid DOM property `stroke-width`. Did you mean `strokeWidth`? Error Component Stack
2025-04-03 17:16:09 +05:30
naman-bruno
b9c2a42344 feat: added options to add additional params in oauth2 requests 2025-04-03 16:35:59 +05:30
ganesh
2d1f7d0f33 Update contributing.md with contribution guidelines and setup instructions (#4377)
---------
Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
2025-04-03 14:50:57 +05:30
lohxt1
f06eb86574 updates 2025-04-03 13:48:39 +05:30
Anoop M D
841facc853 chore: fixed indentation 2025-04-03 12:47:39 +05:30
Pragadesh-45
0e60bd3da7 fix: handle empty script.exec cases in postman collection importer
Updated the `importScriptsFromEvents` and `importPostmanV2CollectionItem` functions to properly handle cases where `event.script.exec` is an empty array. Now, if `exec` is empty, `requestObject.script.req` and `requestObject.tests` are set to an empty string instead of being undefined.
2025-04-03 12:47:39 +05:30
lohxt1
84cd91b798 updates 2025-04-03 12:37:17 +05:30
lohxt1
b1911d80e9 wip: oauth2 additional parameters 2025-04-03 12:34:24 +05:30
lohxt1
3c0d0c95ea oauth2 changes 2025-04-02 19:42:15 +05:30
sanjai0py
5dc7f1ae2f Refactoring and fixes in _Mock Variables Interpolation_ feature 2025-04-02 14:24:29 +05:30
Raghav Sethi
6862cb4e58 Feature: Mock Variables Interpolation (#3609)
Former title: Feature: adding dynamic variable support (#3609)
2025-04-02 14:24:29 +05:30
Carlos Florêncio
0591530d44 add scripts context to response scripts 2025-04-02 13:22:21 +05:30
sanish-bruno
592679538b Fix: res.setBody fails for Object in Developer-mode
vm2 returns a recursive Proxy for accessing the return value which
cannot be serialized for IPC using `structuredClone`.

Co-authored-by: ramki-bruno <ramki@usebruno.com>
2025-04-02 13:18:58 +05:30
ramki-bruno
9ef2699372 Update default collection name to 'Untitled Collection' 2025-04-02 13:15:41 +05:30
Pragadesh-45
e4c37b916a feat: set default names for folders and requests in Postman collection importer 2025-04-02 13:15:41 +05:30
ramki-bruno
7a8a0ae37e Fix: Remove unwanted transitive devDependencies of electron-store 2025-04-02 13:13:40 +05:30
Anoop M D
bd25097e44 Rename SECURITY.md to security.md 2025-03-31 14:03:06 +05:30
ganesh-bruno
3f140e818f replace example.com to usebruno website 2025-03-31 14:01:13 +05:30
lohxt1
dbba22131c fix: proxy and certs not being used for oauth2 calls 2025-03-27 22:56:00 +05:30
lohit
8908828af0 Merge pull request #4353 from naman-bruno/bugfix/system-proxy-agent
Fix: system proxy agent
2025-03-27 19:31:21 +05:30
lohit
20c9e1d406 removed the domain protocol check 2025-03-27 19:28:00 +05:30
naman-bruno
741576526d Fix: logic and design 2025-03-27 18:24:45 +05:30
naman-bruno
b928ec112e add: protocol verification for certificate domain 2025-03-27 16:36:42 +05:30
naman-bruno
559026b65c Fix: right Agent for system proxy 2025-03-27 16:36:22 +05:30
naman-bruno
eb6fef63b3 Removed log 2025-03-26 20:30:39 +05:30
naman-bruno
1b767f8d26 fix: params 2025-03-26 20:30:39 +05:30
naman-bruno
3b061cda89 Fix: agentOptions not passing properly to baseAgent 2025-03-26 20:30:39 +05:30
ganesh
e0d7bb50f3 2025-03-26 16:27:33 +05:30
ramki-bruno
20e8e9167f Perf improvements in Response-preview with useMemo 2025-03-25 23:07:47 +05:30
lohit
268ede869d handle oauth2 timeline response, remove dataBuffer from debugInfo obj (#4330) 2025-03-25 22:28:29 +05:30
ramki-bruno
8b8ddaf31b Revert "Fix: Prettify JSON for Res-preview without parsing to avoid JS specific roundings"
This reverts commit 56581b3641.
2025-03-25 21:58:18 +05:30
lohit
f16fbeade7 Merge pull request #4328 from lohxt1/main
revert serialization of debugInfo data
2025-03-25 19:52:35 +05:30
lohxt1
d27677030d revert serialization of debugInfo data 2025-03-25 19:50:06 +05:30
pooja-bruno
578e912faf fix: codemirror lint errors (#4321)
* fix: codemirror lint errors
* chore: added comments for await lint fix and removed the indent config prop that was not needed

---------

Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
2025-03-25 19:44:22 +05:30
lohit
bd8c6caa39 Merge pull request #4325 from lohxt1/main
oauth2 fixes
2025-03-25 18:33:10 +05:30
lohxt1
7635230c88 oauth2 fixes 2025-03-25 18:29:44 +05:30
lohit
eb0d746082 Merge pull request #4324 from naman-bruno/bugfix/redirect-proxy
Fix: Redirect not working on proxy
2025-03-25 18:05:17 +05:30
naman-bruno
61b3853390 overwrite maxredirect on request obj 2025-03-25 18:01:40 +05:30
naman-bruno
76485cdd56 reseted max redirect counts 2025-03-25 17:56:31 +05:30
lohit
3d5401a8db Merge pull request #4323 from lohxt1/timeline_fixes
oauth2 fixes
2025-03-25 17:53:00 +05:30
lohxt1
6faecc2874 setting the default value for auto_refresh_token to false 2025-03-25 17:46:06 +05:30
lohit
4650ca40c1 Merge pull request #4322 from lohxt1/timeline_fixes
oauth2 fixes and improvements
2025-03-25 17:19:27 +05:30
lohxt1
14ee26557a query stringify request payload data before the oauth2 token url request 2025-03-25 17:09:36 +05:30
lohxt1
8e873013a9 oauth2 fixes 2025-03-25 15:42:58 +05:30
Pooja Belaramani
b0caf46406 fix: request run crash 2025-03-25 15:31:28 +05:30
lohit
a0926c4064 Merge pull request #4309 from lohxt1/timeline_fixes
oauth2 related fixes
2025-03-25 12:22:30 +05:30
lohxt1
b795b1c5ce fixes 2025-03-25 12:03:38 +05:30
lohxt1
61ba5f5c39 check if token is expired only if expires_in prop is present, clear response and clear timeline are 2 different things, clear redux state after clearing oauth2 credentials cache 2025-03-24 22:49:21 +05:30
lohxt1
f177287fb6 fix folder settings auth selector comp prop 2025-03-24 19:43:56 +05:30
anusree-bruno
ef929e78f3 Create SECURITY.md (#4266) 2025-03-24 17:33:51 +05:30
lohxt1
274a55e257 folder level oauth2 save fn fix 2025-03-24 15:46:31 +05:30
Ryan
9e24223085 Delete .github/repository-metadata.yml 2025-03-21 19:47:23 +05:30
rreyn-bruno
3cd3d8bdcc Remove sponsorship content from repository 2025-03-21 19:47:23 +05:30
lohit
eed3f2ff4c Merge pull request #4300 from lohxt1/oauth2_fixes
timeline ui fixes, oauth2 validation fixes
2025-03-21 15:58:32 +05:30
lohxt1
b09b4b1d17 timeline ui fixes, oauth2 validation fixes 2025-03-21 15:56:02 +05:30
lohit
cd9c667e8a Merge pull request #4297 from lohxt1/oauth2_fixes
oauth2 fixes, ui validations, timeline ui updates
2025-03-21 00:44:54 +05:30
lohxt1
2675e79dbd oauth2 fixes, ui validations, timeline updates (wip) 2025-03-21 00:41:07 +05:30
lohit
ef94f55c82 Merge pull request #4296 from lohxt1/version_upgrade_2.0.0
chore: version upgrade to 2.0.0
2025-03-20 20:33:43 +05:30
lohxt1
926919524b chore: version upgrade to 2.0.0 2025-03-20 20:31:53 +05:30
lohit
087f691544 Merge pull request #3867 from usebruno/feat/oauth2-improvements
OAuth2 Revamp
2025-03-20 20:22:28 +05:30
lohxt1
3a81ebf0e2 oauth2 fixes 2025-03-20 20:11:12 +05:30
lohxt1
3ffaaab8f3 Merge remote-tracking branch 'upstream/main' into feat/oauth2-improvements 2025-03-20 19:38:54 +05:30
lohxt1
5a98da2031 oauth2 fixes 2025-03-20 19:27:14 +05:30
lohxt1
2e4014863f fix the validations for oauth2 json_to_bru 2025-03-20 17:06:47 +05:30
lohxt1
d3fcb42a8f timeline ui updates wip 2025-03-17 14:09:36 +05:30
lohxt1
51be153527 fix bruno-electron unit tests 2025-03-16 14:28:21 +05:30
lohxt1
5728b7c8a8 fix bruno-lang unit tests 2025-03-16 14:24:04 +05:30
lohxt1
71b6907c31 fix bruno-cli unit tests 2025-03-16 14:11:19 +05:30
lohxt1
eead96ca26 Merge remote-tracking branch 'upstream/main' into feat/oauth2-improvements 2025-03-16 14:02:12 +05:30
lohxt1
f99e8770f0 ~ reverting the bruno-electron ipc-network files refactoring work to keep the diff minimal 2025-03-16 13:37:59 +05:30
Pragadesh-45
f6ab59ceda feat: update Windows build configuration to support custom installation path from GUI installer 2025-03-06 17:40:15 +05:30
naman-bruno
8cda05c431 updated timeline to show body in oauth (#4168) 2025-03-06 17:04:07 +05:30
naman-bruno
7af7ff92bf Fix: redirect to relative path (#4167) 2025-03-06 14:26:02 +05:30
naman-bruno
3169e6cdf4 Oauth2 folder (#4105) 2025-03-06 11:03:34 +05:30
Pragadesh-45
f1004e2e36 Merge branch 'main' of https://github.com/Pragadesh-45/bruno 2025-03-06 00:27:18 +05:30
pooja-bruno
4e88cbf318 feat: add refresh url for oauth2 (#4028) 2025-02-18 17:24:56 +05:30
lohit
413b121ce1 Merge pull request #3989 from lohxt1/feat/oauth2__improvements
oauth2 improvements
2025-02-11 12:33:24 +05:30
lohit
90dff3d1e1 Merge branch 'feat/oauth2-improvements' into feat/oauth2__improvements 2025-02-11 12:32:04 +05:30
lohxt1
3fc0b0a668 oauth2 improvements - collection import default type 2025-02-11 12:27:58 +05:30
lohxt1
b5e53ec25c include oauth2 request data along with headers in the access token url call 2025-02-10 20:20:40 +05:30
Pragadesh-45
26eaec4c72 Merge branch 'usebruno:main' into main 2025-02-07 10:01:15 +05:30
lohxt1
01a62d66cc oauth2 postman import fix and include client certs and proxy config while fetching access token 2025-02-05 19:06:23 +05:30
lohxt1
f668e93f52 oauth2 postman import fix and include client certs and proxy config while fetching access token 2025-02-05 16:06:41 +05:30
Pragadesh-45
d0419edb92 fix: correct variable used in collection name update 2025-02-04 17:49:40 +05:30
lohit
c5eeb190d3 oauth2 updates (#3876)
~ changed tokenPrefix to tokenHeaderPrefix
~ updated the logic for token timer component
2025-01-24 19:39:29 +05:30
lohit
1d1e701ccb oauth2 workflow improvements (#3874)
~ basic auth credentials should be assigned to `request.basicAuth` instead `request.auth` object
~ added credentials_placement option, fixed headers issue client credentials flow
~ cache input field values when grant type select box value changes
~ updated logic for - cache input field values when grant type select box value changes
~ updated token expiry timer component logic
2025-01-24 18:44:02 +05:30
lohit
f38c7ae03a oauth2 ui/ux improvements (#3868) 2025-01-23 22:06:50 +05:30
Anoop M D
8f754142c7 Merge branch 'pr-2077' into feat/oauth2-improvements 2025-01-23 16:45:51 +05:30
Mateusz Pietryga
8c6ce2e084 fix: Allow quoting some special characters in names of multipart request body parts and headers in bru files
Fixes #571
2025-01-20 23:18:36 +01:00
Mateusz Pietryga
b02f6b61ee fix: Adjust Bruno grammar to allow quoting some special characters in names query parameters
Automatically quote query parameter keys if they contain characters sensitive for bru syntax: ':', '"', '{', '}' or ' '.
Quoted keys stored in .bru files now support escaping, so it is possible to store keys that themselves contain '"' character.

Fixes #3037
Fixes #2810
Fixes #2878
2025-01-20 23:10:50 +01:00
Mateusz Pietryga
3bd8f09c88 feat: OAuth2 - Supported at the collection level (#1704) 2024-09-23 21:59:16 +02:00
Mateusz Pietryga
dd9cb21f8c feat: OAuth2 - UI for OAuth2 Credentials independent of the Request Output pane
fix: typo - rename OAuth2PasswordCredentials component
fix: typo - Use the same name for AuthMode - OAuth 2.0 in collection and request level
2024-09-23 21:59:16 +02:00
Mateusz Pietryga
2064cc88ab feat: OAuth2 - automatically handle Bearer token type only
According to RFC6749 Section 7.1, The client MUST NOT use an access token
if it does not understand the token type.
At this point bruno only understands 'bearer' token_type.
2024-09-23 21:59:16 +02:00
Mateusz Pietryga
d982e35a17 feat: OAuth2 - Do not make axios request when executing collection level Get Access Token action
The actual the authorization request is now part of request preparation, and its response is returned for post-request script processing.
2024-09-23 21:59:16 +02:00
Mateusz Pietryga
4afcd44216 feat: OAuth2 - Include resolved authorization details in req object to be usable by scripts
The new variable 'credentials' is now available in 'req' object. It is added automatically during request preparation if oauth2 method is used and is value is either evaluated or retrieved from collection oauth2 cache.
2024-09-23 21:59:16 +02:00
Mateusz Pietryga
63252d3ee2 feat: OAuth2 - Store authorization information
Results of oauth2 authorization flow (i.e. access_token but also refresh_token, id_token, scope or any other information returned from token request) are stored in a collection specific cache. It is persisted in the file system, and will be automatically reused when executing requests until the cache is purged (using Clear Cache button available in all related views).
2024-09-23 20:50:41 +02:00
Mateusz Pietryga
22a9502976 fix: OAuth2 - auth is successful but token endpoint is returned instead of api endpoint (#1999)
Setting oauth2 authorization no longer equals overwriting user-specified data in a request. The pre-requests made to obtain oauth2 access_token are now separated from actual API request.
2024-09-23 20:50:37 +02:00
lzl0304
f972733426 bugfix/chokidar disables globbing 2024-08-29 10:30:38 +08:00
Nikolai2038
5f9c21d00f Update linux installation instructions via apt
- Add instructions to install gpg;
- Use "gpg --list-keys" to let gpg create ".gnupg" directory with correct rights;
- Use "arch=amd64" - see commit 6c8c87fe28.
2024-05-22 22:38:45 +03:00
1107 changed files with 99139 additions and 12192 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
* @helloanoop @maintainer-bruno @bijin-bruno @lohit-bruno @naman-bruno

1
.github/FUNDING.yml vendored
View File

@@ -1 +0,0 @@
github: helloanoop

View File

@@ -27,7 +27,9 @@ body:
required: false
- label: annoying
required: false
- label: this feature was working in a previous version but is broken in the current release.
required: false
- type: input
attributes:
label: Bruno version

View File

@@ -0,0 +1,26 @@
name: 'Setup Node Dependencies'
description: 'Install Node.js and npm dependencies'
runs:
using: 'composite'
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: v22.17.0
cache: 'npm'
cache-dependency-path: './package-lock.json'
- name: Install node dependencies
shell: bash
run: npm ci --legacy-peer-deps
- name: Build libraries
shell: bash
run: |
npm run build:graphql-docs
npm run build:bruno-query
npm run build:bruno-common
npm run sandbox:bundle-libraries --workspace=packages/bruno-js
npm run build:bruno-converters
npm run build:bruno-requests
npm run build:bruno-filestore

View File

@@ -0,0 +1,36 @@
name: 'Run Basic SSL CLI Tests - Linux'
description: 'Run basic SSL CLI tests on Linux'
runs:
using: 'composite'
steps:
- name: Run CLI tests
shell: bash
run: |
set -euo pipefail
# navigate to basic SSL test collection directory
cd tests/ssl/basic-ssl/collections/badssl
echo "basic ssl success"
# should pass
node ../../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit1.xml --insecure --format junit
xmllint --xpath 'count(//testsuite[@errors="0"])' junit1.xml | grep -q "^1$" || exit 1
echo "with default/system ca certs"
# should pass
node ../../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit2.xml --format junit
xmllint --xpath 'count(//testsuite[@errors="0"])' junit2.xml | grep -q "^1$" || exit 1
# navigate to self-signed SSL test collection directory
cd ../self-signed-badssl
echo "self-signed ssl with validation disabled"
# should pass
node ../../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit3.xml --insecure --format junit
xmllint --xpath 'count(//testsuite[@errors="0"])' junit3.xml | grep -q "^1$" || exit 1
echo "self-signed ssl with default/system ca certs"
echo "request will error"
# should fail
node ../../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit4.xml --format junit 2>/dev/null || true
xmllint --xpath 'count(//testsuite[@errors="1"])' junit4.xml | grep -q "^1$" || exit 1

View File

@@ -0,0 +1,33 @@
name: 'Run Custom CA Certs CLI Tests - Linux'
description: 'Run custom CA certs CLI tests on Linux'
runs:
using: 'composite'
steps:
- name: Run CLI tests
shell: bash
run: |
set -euo pipefail
# navigate to CA certificates test collection directory
cd tests/ssl/custom-ca-certs/collection
echo "custom valid ca cert"
# should pass
node ../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit1.xml --cacert ../server/certs/ca-cert.pem --ignore-truststore --format junit
xmllint --xpath 'count(//testsuite[@errors="0"])' junit1.xml | grep -q "^1$" || exit 1
echo "custom valid ca cert with defaults"
# should pass
node ../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit2.xml --cacert ../server/certs/ca-cert.pem --format junit
xmllint --xpath 'count(//testsuite[@errors="0"])' junit2.xml | grep -q "^1$" || exit 1
echo "custom invalid ca cert"
echo "request will error"
# should fail
node ../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit3.xml --cacert ../server/certs/ca-key.pem --ignore-truststore --format junit 2>/dev/null || true
xmllint --xpath 'count(//testsuite[@errors="1"])' junit3.xml | grep -q "^1$" || exit 1
echo "custom invalid ca cert with defaults"
# should pass
node ../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit4.xml --cacert ../server/certs/ca-key.pem --format junit
xmllint --xpath 'count(//testsuite[@errors="0"])' junit4.xml | grep -q "^1$" || exit 1

View File

@@ -0,0 +1,19 @@
name: 'Run SSL E2E Tests - Linux'
description: 'Run SSL E2E tests on Linux'
runs:
using: 'composite'
steps:
- name: Run E2E tests
shell: bash
run: |
set -euo pipefail
xvfb-run npm run test:e2e:ssl
- name: Upload Playwright Report
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: playwright-report-linux
path: playwright-report/
retention-days: 30

View File

@@ -0,0 +1,26 @@
name: 'Setup CA Certificates - Linux'
description: 'Setup CA certificates and start test server for custom CA certs tests on Linux'
runs:
using: 'composite'
steps:
- name: Setup CA certificates
shell: bash
run: |
set -euo pipefail
cd tests/ssl/custom-ca-certs/server
echo "running certificate setup"
node scripts/generate-certs.js
- name: Start test server
shell: bash
run: |
set -euo pipefail
cd tests/ssl/custom-ca-certs/server
echo "starting server in background"
node index.js &
echo "server started with PID: $!"

View File

@@ -0,0 +1,15 @@
name: 'Setup Custom CA Certs Feature Dependencies - Linux'
description: 'Setup feature-specific dependencies for custom CA certs tests on Linux'
runs:
using: 'composite'
steps:
- name: Install additional OS dependencies for custom CA certs
shell: bash
run: |
sudo apt-get update
sudo apt-get --no-install-recommends install -y \
libglib2.0-0 libnss3 libdbus-1-3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libgtk-3-0 libasound2t64 \
xvfb libxml2-utils
sudo chown root /home/runner/work/bruno/bruno/node_modules/electron/dist/chrome-sandbox
sudo chmod 4755 /home/runner/work/bruno/bruno/node_modules/electron/dist/chrome-sandbox

View File

@@ -0,0 +1,36 @@
name: 'Run Basic SSL CLI Tests - macOS'
description: 'Run basic SSL CLI tests on macOS'
runs:
using: 'composite'
steps:
- name: Run CLI tests
shell: bash
run: |
set -euo pipefail
# navigate to basic SSL test collection directory
cd tests/ssl/basic-ssl/collections/badssl
echo "basic ssl success"
# should pass
node ../../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit1.xml --insecure --format junit
xmllint --xpath 'count(//testsuite[@errors="0"])' junit1.xml | grep -q "^1$" || exit 1
echo "with default/system ca certs"
# should pass
node ../../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit2.xml --format junit
xmllint --xpath 'count(//testsuite[@errors="0"])' junit2.xml | grep -q "^1$" || exit 1
# navigate to self-signed SSL test collection directory
cd ../self-signed-badssl
echo "self-signed ssl with validation disabled"
# should pass
node ../../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit3.xml --insecure --format junit
xmllint --xpath 'count(//testsuite[@errors="0"])' junit3.xml | grep -q "^1$" || exit 1
echo "self-signed ssl with default/system ca certs"
echo "request will error"
# should fail
node ../../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit4.xml --format junit 2>/dev/null || true
xmllint --xpath 'count(//testsuite[@errors="1"])' junit4.xml | grep -q "^1$" || exit 1

View File

@@ -0,0 +1,33 @@
name: 'Run Custom CA Certs CLI Tests - macOS'
description: 'Run custom CA certs CLI tests on macOS'
runs:
using: 'composite'
steps:
- name: Run CLI tests
shell: bash
run: |
set -euo pipefail
# navigate to CA certificates test collection directory
cd tests/ssl/custom-ca-certs/collection
echo "custom valid ca cert"
# should pass
node ../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit1.xml --cacert ../server/certs/ca-cert.pem --ignore-truststore --format junit
xmllint --xpath 'count(//testsuite[@errors="0"])' junit1.xml | grep -q "^1$" || exit 1
echo "custom valid ca cert with defaults"
# should pass
node ../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit2.xml --cacert ../server/certs/ca-cert.pem --format junit
xmllint --xpath 'count(//testsuite[@errors="0"])' junit2.xml | grep -q "^1$" || exit 1
echo "custom invalid ca cert"
echo "request will error"
# should fail
node ../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit3.xml --cacert ../server/certs/ca-key.pem --ignore-truststore --format junit 2>/dev/null || true
xmllint --xpath 'count(//testsuite[@errors="1"])' junit3.xml | grep -q "^1$" || exit 1
echo "custom invalid ca cert with defaults"
# should pass
node ../../../../packages/bruno-cli/bin/bru.js run ./request.bru --output junit4.xml --cacert ../server/certs/ca-key.pem --format junit
xmllint --xpath 'count(//testsuite[@errors="0"])' junit4.xml | grep -q "^1$" || exit 1

View File

@@ -0,0 +1,17 @@
name: 'Run SSL E2E Tests - macOS'
description: 'Run SSL E2E tests on macOS'
runs:
using: 'composite'
steps:
- name: Run E2E tests
shell: bash
run: |
npm run test:e2e:ssl
- name: Upload Playwright Report
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: playwright-report-macos
path: playwright-report/
retention-days: 30

View File

@@ -0,0 +1,26 @@
name: 'Setup CA Certificates - macOS'
description: 'Setup CA certificates and start test server for custom CA certs tests on macOS'
runs:
using: 'composite'
steps:
- name: Setup CA certificates
shell: bash
run: |
set -euo pipefail
cd tests/ssl/custom-ca-certs/server
echo "running certificate setup"
node scripts/generate-certs.js
- name: Start test server
shell: bash
run: |
set -euo pipefail
cd tests/ssl/custom-ca-certs/server
echo "starting server in background"
node index.js &
echo "server started with PID: $!"

View File

@@ -0,0 +1,9 @@
name: 'Setup Custom CA Certs Feature Dependencies - macOS'
description: 'Setup feature-specific dependencies for custom CA certs tests on macOS'
runs:
using: 'composite'
steps:
- name: Install additional OS dependencies for custom CA certs
shell: bash
run: |
brew install libxml2

View File

@@ -0,0 +1,50 @@
name: 'Run Basic SSL CLI Tests - Windows'
description: 'Run basic SSL CLI tests on Windows'
runs:
using: 'composite'
steps:
- name: Run CLI tests
shell: pwsh
run: |
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# navigate to basic SSL test collection directory
Set-Location tests\ssl\basic-ssl\collections\badssl
Write-Host "basic ssl success"
# should pass
$process = Start-Process -FilePath "node" -ArgumentList "..\..\..\..\..\packages\bruno-cli\bin\bru.js run .\request.bru --output junit1.xml --insecure --format junit" -NoNewWindow -Wait -PassThru -RedirectStandardError "nul"
[xml]$xml1 = Get-Content junit1.xml
$testsuites1 = if ($xml1.testsuites) { $xml1.testsuites.testsuite } else { $xml1.testsuite }
$errorCount1 = ($testsuites1 | Where-Object { $_.errors -eq "0" } | Measure-Object).Count
if ($errorCount1 -ne 1) { exit 1 }
Write-Host "with default/system ca certs"
# should pass
$process = Start-Process -FilePath "node" -ArgumentList "..\..\..\..\..\packages\bruno-cli\bin\bru.js run .\request.bru --output junit2.xml --format junit" -NoNewWindow -Wait -PassThru -RedirectStandardError "nul"
[xml]$xml2 = Get-Content junit2.xml
$testsuites2 = if ($xml2.testsuites) { $xml2.testsuites.testsuite } else { $xml2.testsuite }
$errorCount2 = ($testsuites2 | Where-Object { $_.errors -eq "0" } | Measure-Object).Count
if ($errorCount2 -ne 1) { exit 1 }
# navigate to self-signed SSL test collection directory
Set-Location ..\self-signed-badssl
Write-Host "self-signed ssl with validation disabled"
# should pass
$process = Start-Process -FilePath "node" -ArgumentList "..\..\..\..\..\packages\bruno-cli\bin\bru.js run .\request.bru --output junit3.xml --insecure --format junit" -NoNewWindow -Wait -PassThru -RedirectStandardError "nul"
[xml]$xml3 = Get-Content junit3.xml
$testsuites3 = if ($xml3.testsuites) { $xml3.testsuites.testsuite } else { $xml3.testsuite }
$errorCount3 = ($testsuites3 | Where-Object { $_.errors -eq "0" } | Measure-Object).Count
if ($errorCount3 -ne 1) { exit 1 }
Write-Host "self-signed ssl with default/system ca certs"
Write-Host "request will error"
# should fail
$process = Start-Process -FilePath "node" -ArgumentList "..\..\..\..\..\packages\bruno-cli\bin\bru.js run .\request.bru --output junit4.xml --format junit" -NoNewWindow -Wait -PassThru -RedirectStandardError "nul"
# Ignore the exit code - we expect this to fail
[xml]$xml4 = Get-Content junit4.xml
$testsuites4 = if ($xml4.testsuites) { $xml4.testsuites.testsuite } else { $xml4.testsuite }
$errorCount4 = ($testsuites4 | Where-Object { $_.errors -eq "1" } | Measure-Object).Count
if ($errorCount4 -ne 1) { exit 1 }

View File

@@ -0,0 +1,47 @@
name: 'Run Custom CA Certs CLI Tests - Windows'
description: 'Run custom CA certs CLI tests on Windows'
runs:
using: 'composite'
steps:
- name: Run CLI tests
shell: pwsh
run: |
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# navigate to CA certificates test collection directory
Set-Location tests\ssl\custom-ca-certs\collection
Write-Host "custom valid ca cert"
# should pass
$process = Start-Process -FilePath "node" -ArgumentList "..\..\..\..\packages\bruno-cli\bin\bru.js run .\request.bru --output junit1.xml --cacert ..\server\certs\ca-cert.pem --ignore-truststore --format junit" -NoNewWindow -Wait -PassThru -RedirectStandardError "nul"
[xml]$xml1 = Get-Content junit1.xml
$testsuites1 = if ($xml1.testsuites) { $xml1.testsuites.testsuite } else { $xml1.testsuite }
$errorCount1 = ($testsuites1 | Where-Object { $_.errors -eq "0" } | Measure-Object).Count
if ($errorCount1 -ne 1) { exit 1 }
Write-Host "custom valid ca cert with defaults"
# should pass
$process = Start-Process -FilePath "node" -ArgumentList "..\..\..\..\packages\bruno-cli\bin\bru.js run .\request.bru --output junit2.xml --cacert ..\server\certs\ca-cert.pem --format junit" -NoNewWindow -Wait -PassThru -RedirectStandardError "nul"
[xml]$xml2 = Get-Content junit2.xml
$testsuites2 = if ($xml2.testsuites) { $xml2.testsuites.testsuite } else { $xml2.testsuite }
$errorCount2 = ($testsuites2 | Where-Object { $_.errors -eq "0" } | Measure-Object).Count
if ($errorCount2 -ne 1) { exit 1 }
Write-Host "custom invalid ca cert"
Write-Host "request will error"
# should fail
$process = Start-Process -FilePath "node" -ArgumentList "..\..\..\..\packages\bruno-cli\bin\bru.js run .\request.bru --output junit3.xml --cacert ..\server\certs\ca-key.pem --ignore-truststore --format junit" -NoNewWindow -Wait -PassThru -RedirectStandardError "nul"
# Ignore the exit code - we expect this to fail
[xml]$xml3 = Get-Content junit3.xml
$testsuites3 = if ($xml3.testsuites) { $xml3.testsuites.testsuite } else { $xml3.testsuite }
$errorCount3 = ($testsuites3 | Where-Object { $_.errors -eq "1" } | Measure-Object).Count
if ($errorCount3 -ne 1) { exit 1 }
Write-Host "custom invalid ca cert with defaults"
# should pass
$process = Start-Process -FilePath "node" -ArgumentList "..\..\..\..\packages\bruno-cli\bin\bru.js run .\request.bru --output junit4.xml --cacert ..\server\certs\ca-key.pem --format junit" -NoNewWindow -Wait -PassThru -RedirectStandardError "nul"
[xml]$xml4 = Get-Content junit4.xml
$testsuites4 = if ($xml4.testsuites) { $xml4.testsuites.testsuite } else { $xml4.testsuite }
$errorCount4 = ($testsuites4 | Where-Object { $_.errors -eq "0" } | Measure-Object).Count
if ($errorCount4 -ne 1) { exit 1 }

View File

@@ -0,0 +1,17 @@
name: 'Run SSL E2E Tests - Windows'
description: 'Run SSL E2E tests on Windows'
runs:
using: 'composite'
steps:
- name: Run E2E tests
shell: pwsh
run: |
npm run test:e2e:ssl
- name: Upload Playwright Report
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: playwright-report-windows
path: playwright-report/
retention-days: 30

View File

@@ -0,0 +1,25 @@
name: 'Setup CA Certificates - Windows'
description: 'Setup CA certificates and start test server for custom CA certs tests on Windows'
runs:
using: 'composite'
steps:
- name: Setup CA certificates
shell: pwsh
run: |
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
Set-Location tests\ssl\custom-ca-certs\server
Write-Host "running certificate setup"
node scripts/generate-certs.js
- name: Start test server
shell: pwsh
run: |
Set-StrictMode -Version Latest
Set-Location tests\ssl\custom-ca-certs\server
Write-Host "starting server in background"
Start-Process -FilePath "node" -ArgumentList "index.js" -PassThru -WindowStyle Hidden

View File

@@ -25,8 +25,8 @@ jobs:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version-file: '.nvmrc'

91
.github/workflows/ssl-tests.yml vendored Normal file
View File

@@ -0,0 +1,91 @@
name: SSL Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
tests-for-linux:
name: SSL Tests - Linux
timeout-minutes: 60
runs-on: ubuntu-latest
permissions:
checks: write
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v5
- name: Setup Node Dependencies
uses: ./.github/actions/common/setup-node-deps
- name: Setup Feature Dependencies
uses: ./.github/actions/ssl/linux/setup-feature-specific-deps
- name: Setup CA Certificates
uses: ./.github/actions/ssl/linux/setup-ca-certs
- name: Run Basic SSL CLI Tests
uses: ./.github/actions/ssl/linux/run-basic-ssl-cli-tests
- name: Run Custom CA Certs CLI Tests
uses: ./.github/actions/ssl/linux/run-custom-ca-certs-cli-tests
- name: Run Custom CA Certs E2E Tests
uses: ./.github/actions/ssl/linux/run-ssl-e2e-tests
tests-for-macos:
name: SSL Tests - macOS
timeout-minutes: 60
runs-on: macos-latest
permissions:
checks: write
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v5
- name: Setup Node Dependencies
uses: ./.github/actions/common/setup-node-deps
- name: Setup Feature Dependencies
uses: ./.github/actions/ssl/macos/setup-feature-specific-deps
- name: Setup CA Certificates
uses: ./.github/actions/ssl/macos/setup-ca-certs
- name: Run Basic SSL CLI Tests
uses: ./.github/actions/ssl/macos/run-basic-ssl-cli-tests
- name: Run Custom CA Certs CLI Tests
uses: ./.github/actions/ssl/macos/run-custom-ca-certs-cli-tests
- name: Run Custom CA Certs E2E Tests
uses: ./.github/actions/ssl/macos/run-ssl-e2e-tests
tests-for-windows:
name: SSL Tests - Windows
timeout-minutes: 60
runs-on: windows-latest
permissions:
checks: write
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v5
- name: Setup Node Dependencies
uses: ./.github/actions/common/setup-node-deps
- name: Setup CA Certificates
uses: ./.github/actions/ssl/windows/setup-ca-certs
- name: Run Basic SSL CLI Tests
uses: ./.github/actions/ssl/windows/run-basic-ssl-cli-tests
- name: Run Custom CA Certs CLI Tests
uses: ./.github/actions/ssl/windows/run-custom-ca-certs-cli-tests
- name: Run Custom CA Certs E2E Tests
uses: ./.github/actions/ssl/windows/run-ssl-e2e-tests

View File

@@ -13,8 +13,8 @@ jobs:
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version-file: '.nvmrc'
cache: 'npm'
@@ -28,6 +28,14 @@ jobs:
npm run build --workspace=packages/bruno-common
npm run build --workspace=packages/bruno-query
npm run sandbox:bundle-libraries --workspace=packages/bruno-js
npm run build --workspace=packages/bruno-converters
npm run build --workspace=packages/bruno-requests
npm run build --workspace=packages/bruno-filestore
- name: Lint Check
run: npm run lint
env:
ESLINT_PLUGIN_DIFF_COMMIT: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref || 'main' }}
# tests
- name: Test Package bruno-js
@@ -45,6 +53,8 @@ jobs:
run: npm run test --workspace=packages/bruno-app
- name: Test Package bruno-common
run: npm run test --workspace=packages/bruno-common
- name: Test Package bruno-converters
run: npm run test --workspace=packages/bruno-converters
- name: Test Package bruno-electron
run: npm run test --workspace=packages/bruno-electron
@@ -56,8 +66,8 @@ jobs:
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version-file: '.nvmrc'
cache: 'npm'
@@ -71,6 +81,14 @@ jobs:
npm run build --workspace=packages/bruno-query
npm run build --workspace=packages/bruno-common
npm run sandbox:bundle-libraries --workspace=packages/bruno-js
npm run build --workspace=packages/bruno-converters
npm run build --workspace=packages/bruno-requests
npm run build --workspace=packages/bruno-filestore
- name: Run Local Testbench
run: |
npm start --workspace=packages/bruno-tests &
sleep 5
- name: Run tests
run: |
@@ -82,5 +100,48 @@ jobs:
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
check_name: CLI Test Results
files: packages/bruno-tests/collection/junit.xml
comment_mode: always
e2e-test:
name: Playwright E2E Tests
timeout-minutes: 60
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: v22.11.x
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get --no-install-recommends install -y \
libglib2.0-0 libnss3 libdbus-1-3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libgtk-3-0 libasound2t64 \
xvfb
npm ci --legacy-peer-deps
sudo chown root /home/runner/work/bruno/bruno/node_modules/electron/dist/chrome-sandbox
sudo chmod 4755 /home/runner/work/bruno/bruno/node_modules/electron/dist/chrome-sandbox
- name: Install dependencies for test collection environment
run: |
npm ci --prefix packages/bruno-tests/collection
- name: Build libraries
run: |
npm run build:graphql-docs
npm run build:bruno-query
npm run build:bruno-common
npm run sandbox:bundle-libraries --workspace=packages/bruno-js
npm run build:bruno-converters
npm run build:bruno-requests
npm run build:bruno-filestore
- name: Run Playwright tests
run: |
xvfb-run npm run test:e2e
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30

6
.gitignore vendored
View File

@@ -46,4 +46,8 @@ yarn-error.log*
#dev editor
bruno.iml
.idea
.idea
.vscode
# Playwright
/blob-report/

1
.husky/pre-commit Normal file
View File

@@ -0,0 +1 @@
npx nano-staged

Binary file not shown.

Before

Width:  |  Height:  |  Size: 537 KiB

After

Width:  |  Height:  |  Size: 813 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

View File

@@ -15,15 +15,15 @@
| [正體中文](docs/contributing/contributing_zhtw.md)
| [日本語](docs/contributing/contributing_ja.md)
| [हिंदी](docs/contributing/contributing_hi.md)
| [Nederlands](docs/contributing/contributing_nl.md)
| [Dutch](docs/contributing/contributing_nl.md)
## Let's make Bruno better, together!!
We are happy that you are looking to improve Bruno. Below are the guidelines to get started bringing up Bruno on your computer.
We are happy that you are looking to improve Bruno. Below are the guidelines to run Bruno on your computer.
### Technology Stack
Bruno is built using Next.js and React. We also use electron to ship a desktop version (that supports local collections)
Bruno is built using React and Electron.
Libraries we use
@@ -37,38 +37,77 @@ Libraries we use
- Filesystem Watcher - chokidar
- i18n - i18next
### Dependencies
You would need [Node v20.x or the latest LTS version](https://nodejs.org/en/) and npm 8.x. We use npm workspaces in the project
> [!IMPORTANT]
> You would need [Node v22.x or the latest LTS version](https://nodejs.org/en/). We use npm workspaces in the project
## Development
Bruno is being developed as a desktop app. You need to load the app by running the Next.js app in one terminal and then run the electron app in another terminal.
Bruno is a desktop app. Below are the instructions to run Bruno.
### Local Development
> Note: We use React for the frontend and rsbuild for build and dev server.
## Install Dependencies
```bash
# use nodejs 20 version
# use nodejs 22 version
nvm use
# install deps
npm i --legacy-peer-deps
```
### Local Development
#### Build packages
##### Option 1
```bash
# build packages
npm run build:graphql-docs
npm run build:bruno-query
npm run build:bruno-common
npm run build:bruno-converters
npm run build:bruno-requests
npm run build:bruno-filestore
# bundle js sandbox libraries
npm run sandbox:bundle-libraries --workspace=packages/bruno-js
```
##### Option 2
# run next app (terminal 1)
```bash
# install dependencies and setup
npm run setup
```
#### Run the app
##### Option 1
```bash
# run react app (terminal 1)
npm run dev:web
# run electron app (terminal 2)
npm run dev:electron
```
##### Option 2
```bash
# run electron and react app concurrently
npm run dev
```
#### Customize Electron `userData` path
If `ELECTRON_USER_DATA_PATH` env-variable is present and its development mode, then `userData` path is modified accordingly.
e.g.
```sh
ELECTRON_USER_DATA_PATH=$(realpath ~/Desktop/bruno-test) npm run dev:electron
```
This will create a `bruno-test` folder on your Desktop and use it as the `userData` path.
### Troubleshooting
You might encounter a `Unsupported platform` error when you run `npm install`. To fix this, you will need to delete `node_modules` and `package-lock.json` and run `npm install`. This should install all the necessary packages needed to run the app.
@@ -87,7 +126,28 @@ find . -type f -name "package-lock.json" -delete
```bash
# run bruno-schema tests
npm test --workspace=packages/bruno-schema
npm run test --workspace=packages/bruno-schema
# run bruno-query tests
npm run test --workspace=packages/bruno-query
# run bruno-common tests
npm run test --workspace=packages/bruno-common
# run bruno-converters tests
npm run test --workspace=packages/bruno-converters
# run bruno-app tests
npm run test --workspace=packages/bruno-app
# run bruno-electron tests
npm run test --workspace=packages/bruno-electron
# run bruno-lang tests
npm run test --workspace=packages/bruno-lang
# run bruno-toml tests
npm run test --workspace=packages/bruno-toml
# run tests over all workspaces
npm test --workspaces --if-present

View File

@@ -21,7 +21,7 @@ Bibliotheken die wir benutzen
### Abhängigkeiten
Du benötigst [Node v20.x oder die neuste LTS Version](https://nodejs.org/en/) und npm 8.x. Wir benutzen npm workspaces in dem Projekt.
Du benötigst [Node v22.x oder die neuste LTS Version](https://nodejs.org/en/) und npm 8.x. Wir benutzen npm workspaces in dem Projekt.
### Lass uns coden
@@ -42,12 +42,12 @@ Bruno wird als Desktop-Anwendung entwickelt. Um die App zu starten, musst Du zue
### Abhängigkeiten
- NodeJS v18
- NodeJS v22
### Lokales Entwickeln
```bash
# use nodejs 18 version
# use nodejs 22 version
nvm use
# install deps

View File

@@ -1,4 +1,4 @@
[English](../../contributing.md)
[Inglés](../../contributing.md)
## ¡Juntos, hagamos a Bruno mejor!
@@ -6,58 +6,111 @@ Estamos encantados de que quieras ayudar a mejorar Bruno. A continuación encont
### Tecnologías utilizadas
Bruno está construido con NextJs y React. También usamos electron para distribuir una versión de escritorio (que soporta colecciones locales).
Bruno está construido con React y Electron
Librerías que utilizamos:
- CSS - Tailwind
- Editores de código - Codemirror
- CSS - TailwindCSS
- Editores de código - CodeMirror
- Manejo del estado - Redux
- Íconos - Tabler Icons
- Formularios - formik
- Validación de esquemas - Yup
- Cliente de peticiones - axios
- Monitor del sistema de archivos - chokidar
- i18n (internacionalización) - i18next
### Dependencias
Necesitarás [Node v20.x o la última versión LTS](https://nodejs.org/es) y npm 8.x. Ten en cuenta que utilizamos espacios de trabajo de npm en el proyecto.
> [!IMPORTANT]
> Necesitarás [Node v22.x o la última versión LTS](https://nodejs.org/es/). Ten en cuenta que Bruno usa los espacios de trabajo de npm
## Desarrollo
Bruno está siendo desarrollado como una aplicación de escritorio. Para ejecutarlo, primero debes ejecutar la aplicación de nextjs en una terminal y luego ejecutar la aplicación de electron en otra terminal.
Bruno es una aplicación de escritorio. A continuación se detallan las instrucciones paso a paso para ejecutar Bruno.
### Dependencias
> Nota: Utilizamos React para el frontend y rsbuild para el servidor de desarrollo.
- NodeJS v18
### Instalar dependencias
```bash
# Use la versión 22.x o LTS (Soporte a Largo Plazo) de Node.js
nvm use 22.11.0
# instalar las dependencias
npm i --legacy-peer-deps
```
> ¿Por qué `--legacy-peer-deps`?: Fuerza la instalación ignorando conflictos en dependencias “peer”, evitando errores de árbol de dependencias.
### Desarrollo local
#### Construir paquetes
##### Opción 1
```bash
# Utiliza la versión 18 de nodejs
nvm use
# Instala las dependencias
npm i --legacy-peer-deps
# Construye la documentación de graphql
# construir paquetes
npm run build:graphql-docs
# Construye bruno-query
npm run build:bruno-query
npm run build:bruno-common
npm run build:bruno-converters
npm run build:bruno-requests
# Ejecuta la aplicación de nextjs (terminal 1)
# empaquetar bibliotecas JavaScript del entorno de pruebas aislado
npm run sandbox:bundle-libraries --workspace=packages/bruno-js
```
##### Opción 2
```bash
# instalar dependencias y configurar el entorno
npm run setup
```
#### Ejecutar la aplicación
```bash
# ejecutar aplicación react (terminal 1)
npm run dev:web
# Ejecuta la aplicación de electron (terminal 2)
# ejecutar aplicación electron (terminal 2)
npm run dev:electron
```
##### Opción 1
```bash
# ejecutar aplicación react (terminal 1)
npm run dev:web
# ejecutar aplicación electron (terminal 2)
npm run dev:electron
```
##### Opción 2
```bash
# ejecutar aplicación electron y react de forma concurrente
npm run dev
```
#### Personalizar la ruta `userData` de Electron
Si la variable de entorno `ELECTRON_USER_DATA_PATH` está presente y se encuentra en modo de desarrollo, entonces la ruta `userData` se modifica en consecuencia.
ejemplo:
```sh
ELECTRON_USER_DATA_PATH=$(realpath ~/Desktop/bruno-test) npm run dev:electron
```
Esto creará una carpeta llamada `bruno-test` en tu escritorio y la usará como la ruta userData.
### Solución de problemas
Es posible que encuentres un error de `Unsupported platform` cuando ejecutes `npm install`. Para solucionarlo, debes eliminar la carpeta `node_modules` y el archivo `package-lock.json`, luego, ejecuta `npm install`. Lo anterior debería instalar todos los paquetes necesarios para ejecutar la aplicación.
Es posible que te encuentres con un error `Unsupported platform` cuando ejecutes `npm install`. Para solucionarlo, tendrás que eliminar las carpetas `node_modules` y el archivo `package-lock.json`, y luego volver a ejecutar `npm install`. Esto debería instalar todos los paquetes necesarios para que la aplicación funcione.
```shell
```sh
# Elimina la carpeta node_modules en los subdirectorios
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
rm -rf "$dir"
@@ -69,10 +122,42 @@ find . -type f -name "package-lock.json" -delete
### Pruebas
```bash
# ejecutar pruebas de esquema bruno
npm test --workspace=packages/bruno-schema
#### Pruebas individuales
```bash
# ejecutar pruebas de bruno-app
npm run test --workspace=packages/bruno-app
# ejecutar pruebas de bruno-electron
npm run test --workspace=packages/bruno-electron
# ejecutar pruebas de bruno-cli
npm run test --workspace=packages/bruno-cli
# ejecutar pruebas de bruno-common
npm run test --workspace=packages/bruno-common
# ejecutar pruebas de bruno-converters
npm run test --workspace=packages/bruno-converters
# ejecutar pruebas de bruno-schema
npm run test --workspace=packages/bruno-schema
# ejecutar pruebas de bruno-query
npm run test --workspace=packages/bruno-query
# ejecutar pruebas de bruno-js
npm run test --workspace=packages/bruno-js
# ejecutar pruebas de bruno-lang
npm run test --workspace=packages/bruno-lang
# ejecutar pruebas de bruno-toml
npm run test --workspace=packages/bruno-toml
```
#### Pruebas en conjunto
```bash
# ejecutar pruebas en todos los espacios de trabajo
npm test --workspaces --if-present
```

View File

@@ -40,6 +40,8 @@ npm i --legacy-peer-deps
npm run build:graphql-docs
npm run build:bruno-query
npm run build:bruno-common
npm run build:bruno-converters
npm run build:bruno-requests
# Next.js ऐप चलाएँ (टर्मिनल 1 पर)
npm run dev:web

View File

@@ -40,6 +40,8 @@ npm i --legacy-peer-deps
npm run build:graphql-docs
npm run build:bruno-query
npm run build:bruno-common
npm run build:bruno-converters
npm run build:bruno-requests
# run next app (terminal 1)
npm run dev:web

View File

@@ -40,6 +40,8 @@ npm i --legacy-peer-deps
npm run build:graphql-docs
npm run build:bruno-query
npm run build:bruno-common
npm run build:bruno-converters
npm run build:bruno-requests
# next 앱 실행 (1번 터미널)
npm run dev:web

View File

@@ -40,6 +40,8 @@ npm i --legacy-peer-deps
npm run build:graphql-docs
npm run build:bruno-query
npm run build:bruno-common
npm run build:bruno-converters
npm run build:bruno-requests
# draai next app (terminal 1)
npm run dev:web

View File

@@ -42,6 +42,8 @@ npm i --legacy-peer-deps
npm run build:graphql-docs
npm run build:bruno-query
npm run build:bruno-common
npm run build:bruno-converters
npm run build:bruno-requests
# spustite ďalšiu aplikáciu (terminál 1)
npm run dev:web

View File

@@ -0,0 +1,470 @@
# Playwright Testing Guide for Bruno
This guide explains how to create and run Playwright test cases for the Bruno application using the UI.
## Table of Contents
- [Overview](#overview)
- [Prerequisites](#prerequisites)
- [Creating Tests Using Codegen](#creating-tests-using-codegen)
- [Manual Test Creation](#manual-test-creation)
- [Test Structure and Organization](#test-structure-and-organization)
- [Available Test Fixtures](#available-test-fixtures)
- [Running Tests](#running-tests)
- [Best Practices](#best-practices)
- [Examples](#examples)
- [Troubleshooting](#troubleshooting)
## Overview
Bruno uses Playwright for end-to-end testing of its Electron application. The testing setup includes custom fixtures for Electron app testing and utilities for managing test data.
## Prerequisites
- Node.js installed
- All dependencies installed (`npm install`)
- Electron app can be built and run
## Creating Tests Using Codegen
The easiest way to create tests is using Playwright's codegen feature, which records your UI interactions and generates test code.
### Using the Built-in Codegen Script
```bash
# Generate a test with a specific name
npm run test:codegen my-new-test
# Generate a test without specifying a name (will prompt for input)
npm run test:codegen
```
### What Happens During Codegen
1. The Electron app launches automatically
2. Playwright Inspector opens in a separate window
3. You interact with the Bruno UI
4. Actions are recorded and converted to test code
5. The generated test file is saved in `e2e-tests/`
### Codegen Workflow
1. **Start Recording**: Run the codegen command
2. **Interact with UI**: Perform the actions you want to test
3. **Add Assertions**: Use the inspector to add assertions
4. **Save Test**: The test file is automatically generated
5. **Review and Refine**: Edit the generated test as needed
## Manual Test Creation
You can also create tests manually by following the established patterns.
### Basic Test Structure
```typescript
import { test, expect } from '../../playwright';
test('Test description', async ({ page }) => {
// Test steps here
await page.getByLabel('Some Label').click();
// Assertions
await expect(page.getByText('Expected Text')).toBeVisible();
});
```
### Test with Temporary Data
```typescript
import { test, expect } from '../../playwright';
test('Test with temporary data', async ({ page, createTmpDir }) => {
// Create temporary directory for test data
const testDir = await createTmpDir('test-collection');
// Test steps
await page.getByLabel('Create Collection').click();
await page.getByLabel('Name').fill('test-collection');
await page.getByLabel('Location').fill(testDir);
// Assertions
await expect(page.getByText('test-collection')).toBeVisible();
});
```
## Test Structure and Organization
### Directory Structure
```
e2e-tests/
├── 001-sanity-tests/ # Basic functionality tests
│ ├── 001-home-screen.spec.ts
│ └── 002-create-new-collection-and-new-request.spec.ts
├── 002-feature-tests/ # Specific feature tests
├── 003-integration-tests/ # Complex workflow tests
└── bruno-testbench/ # Test utilities and helpers
```
### Naming Conventions
- **Files**: Use descriptive names with `.spec.ts` extension
- **Tests**: Use clear, descriptive test names
- **Folders**: Use numbered prefixes for ordering
### Test File Template
```typescript
import { test, expect } from '../../playwright';
test.describe('Feature Name', () => {
test('should perform specific action', async ({ page }) => {
// Arrange
// Act
// Assert
});
test('should handle error case', async ({ page }) => {
// Test error scenarios
});
});
```
## Available Test Fixtures
The Bruno Playwright setup provides several custom fixtures:
### Core Fixtures
- `page`: Main page for testing
- `context`: Browser context
- `electronApp`: Electron application instance
### Utility Fixtures
- `createTmpDir`: Creates temporary directories for test data
- `newPage`: Creates a new page instance
- `pageWithUserData`: Page with custom user data
- `launchElectronApp`: Launches a new Electron app instance
- `reuseOrLaunchElectronApp`: Reuses existing app or launches new one
### Using Fixtures
```typescript
test('Test with multiple fixtures', async ({ page, createTmpDir, electronApp }) => {
const testDir = await createTmpDir('test-data');
// Your test logic here
});
```
## Running Tests
### Basic Commands
```bash
# Run all tests
npm run test:e2e
# Run specific test file
npx playwright test e2e-tests/001-sanity-tests/001-home-screen.spec.ts
# Run tests in a specific folder
npx playwright test e2e-tests/001-sanity-tests/
```
### Advanced Options
```bash
# Run with UI mode (for debugging)
npx playwright test --ui
# Run in headed mode (see browser)
npx playwright test --headed
# Run with specific browser
npx playwright test --project="Bruno Electron App"
# Run with debugging
npx playwright test --debug
# Run with trace recording
npx playwright test --trace on
```
### CI/CD Integration
```bash
# Install browsers for CI
npx playwright install
# Run tests in CI mode
npm run test:e2e
```
## Best Practices
### 1. Use Semantic Selectors
**Preferred:**
```typescript
await page.getByRole('button', { name: 'Create' }).click();
await page.getByLabel('Collection Name').fill('test');
await page.getByText('Success message').toBeVisible();
```
**Avoid:**
```typescript
await page.locator('.btn-primary').click();
await page.locator('#collection-name').fill('test');
```
### 2. Create Isolated Tests
Each test should be independent and not rely on other tests:
```typescript
test('should create collection', async ({ page, createTmpDir }) => {
const testDir = await createTmpDir('collection-test');
// Test creates its own data
await page.getByLabel('Create Collection').click();
await page.getByLabel('Name').fill('test-collection');
await page.getByLabel('Location').fill(testDir);
// Clean up happens automatically via createTmpDir
});
```
### 3. Add Meaningful Assertions
Always verify the expected outcomes:
```typescript
test('should save request successfully', async ({ page }) => {
// Arrange
await page.getByLabel('Create Collection').click();
// Act
await page.getByRole('button', { name: 'Save' }).click();
// Assert
await expect(page.getByText('Request saved successfully')).toBeVisible();
await expect(page.getByRole('tab', { name: 'GET request' })).toBeVisible();
});
```
### 4. Handle Async Operations
```typescript
test('should wait for network requests', async ({ page }) => {
// Wait for specific network request
await page.waitForResponse((response) => response.url().includes('/api/endpoint'));
// Or wait for element to be stable
await page.waitForSelector('[data-testid="loading"]', { state: 'hidden' });
});
```
### 5. Use Test Data Management
```typescript
test('should work with test data', async ({ page, createTmpDir }) => {
const testDir = await createTmpDir('test-data');
// Create test files
await fs.writeFile(path.join(testDir, 'test.bru'), testContent);
// Use in test
await page.getByLabel('Open Collection').click();
await page.getByText(testDir).click();
});
```
## Examples
### Example 1: Basic Collection Creation
```typescript
import { test, expect } from '../../playwright';
test('should create a new collection', async ({ page, createTmpDir }) => {
const testDir = await createTmpDir('new-collection');
await page.getByLabel('Create Collection').click();
await page.getByLabel('Name').fill('My Test Collection');
await page.getByLabel('Location').fill(testDir);
await page.getByRole('button', { name: 'Create' }).click();
await expect(page.getByText('My Test Collection')).toBeVisible();
});
```
### Example 2: Request Creation and Execution
```typescript
import { test, expect } from '../../playwright';
test('should create and execute HTTP request', async ({ page, createTmpDir }) => {
const testDir = await createTmpDir('request-test');
// Create collection
await page.getByLabel('Create Collection').click();
await page.getByLabel('Name').fill('Request Test');
await page.getByLabel('Location').fill(testDir);
await page.getByRole('button', { name: 'Create' }).click();
// Create request
await page.locator('#create-new-tab').getByRole('img').click();
await page.getByPlaceholder('Request Name').fill('Test Request');
await page.locator('#new-request-url .CodeMirror').click();
await page.locator('textarea').fill('http://localhost:8081/ping');
await page.getByRole('button', { name: 'Create' }).click();
// Execute request
await page.locator('#send-request').getByRole('img').nth(2).click();
// Verify response
await expect(page.getByRole('main')).toContainText('200 OK');
});
```
### Example 3: Environment Management
```typescript
import { test, expect } from '../../playwright';
test('should create and use environment variables', async ({ page, createTmpDir }) => {
const testDir = await createTmpDir('env-test');
// Setup collection
await page.getByLabel('Create Collection').click();
await page.getByLabel('Name').fill('Environment Test');
await page.getByLabel('Location').fill(testDir);
await page.getByRole('button', { name: 'Create' }).click();
// Create environment
await page.getByRole('button', { name: 'Environments' }).click();
await page.getByRole('button', { name: 'Add Environment' }).click();
await page.getByLabel('Environment Name').fill('Development');
await page.getByRole('button', { name: 'Create' }).click();
// Add variable
await page.getByRole('button', { name: 'Add Variable' }).click();
await page.getByLabel('Variable Name').fill('API_URL');
await page.getByLabel('Variable Value').fill('http://localhost:3000');
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByText('API_URL')).toBeVisible();
});
```
## Troubleshooting
### Common Issues
1. **Electron App Not Starting**
```bash
# Ensure dependencies are installed
npm install
# Try running the app manually first
npm run dev:electron
```
2. **Tests Timing Out**
```typescript
// Increase timeout for specific test
test('slow test', async ({ page }) => {
test.setTimeout(60000); // 60 seconds
// Test steps
});
```
3. **Element Not Found**
```typescript
// Wait for element to be present
await page.waitForSelector('[data-testid="element"]');
// Or use more specific selectors
await page.getByRole('button', { name: 'Exact Button Text' }).click();
```
4. **Flaky Tests**
```typescript
// Use stable selectors
await page.getByTestId('stable-id').click();
// Wait for state changes
await page.waitForLoadState('networkidle');
```
### Debug Mode
```bash
# Run with debug mode
npx playwright test --debug
# Run specific test in debug mode
npx playwright test --debug e2e-tests/001-sanity-tests/001-home-screen.spec.ts
```
### Trace Analysis
```bash
# Run with trace recording
npx playwright test --trace on
# View trace in browser
npx playwright show-trace test-results/trace-*.zip
```
## Configuration
The Playwright configuration is in `playwright.config.ts`:
```typescript
export default defineConfig({
testDir: './e2e-tests',
fullyParallel: false,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 1 : 0,
workers: process.env.CI ? undefined : 1,
projects: [
{
name: 'Bruno Electron App'
}
],
webServer: [
{
command: 'npm run dev:web',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI
},
{
command: 'npm start --workspace=packages/bruno-tests',
url: 'http://localhost:8081/ping',
reuseExistingServer: !process.env.CI
}
]
});
```
## Additional Resources
- [Playwright Documentation](https://playwright.dev/)
- [Playwright Test API](https://playwright.dev/docs/api/class-test)
- [Electron Testing with Playwright](https://playwright.dev/docs/api/class-electronapplication)
- [Bruno Project Structure](../readme.md)
---
For questions or issues with testing, please refer to the project's contributing guidelines or create an issue in the repository.

View File

@@ -74,12 +74,14 @@ flatpak install com.usebruno.Bruno
# على نظام Linux عبر 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### التشغيل عبر منصات متعددة 🖥️

View File

@@ -59,12 +59,14 @@ snap install bruno
# 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### একাধিক প্ল্যাটফর্মে চালান 🖥️

View File

@@ -37,13 +37,37 @@ Bruno 直接在您的电脑文件夹中存储您的 API 信息。我们使用纯
Bruno 仅限离线使用。我们计划永不向 Bruno 添加云同步功能。我们重视您的数据隐私,并认为它应该留在您的设备上。阅读我们的长期愿景 [点击查看](https://github.com/usebruno/bruno/discussions/269)
[下载 Bruno](https://www.usebruno.com/downloads)
📢 观看我们在印度 FOSS 3.0 会议上的最新演讲 [点击查看](https://www.youtube.com/watch?v=7bSMFpbcPiY)
![bruno](../../assets/images/landing-2.png) <br /><br />
### 安装
## 商业版本 ✨
Bruno 可以在我们的 [网站上下载](https://www.usebruno.com/downloads) Mac、Windows 和 Linux 的可执行文件
我们的大多数功能都是免费且开源的
我们致力于在 [开源与可持续性发展](https://github.com/usebruno/bruno/discussions/269) 之间取得和谐的平衡
欢迎使用我们的 [付费版本](https://www.usebruno.com/pricing) ,看看附加的功能是否对您或团队有所帮助! <br/>
## 目录
- [安装](#安装)
- [特性](#特性)
- [跨平台使用 🖥️](#跨平台使用-)
- [通过Git协作 👩‍💻🧑‍💻](#通过git协作-)
- [重要链接 📌](#重要链接-)
- [展示 🎥](#展示-)
- [分享评价 📣](#分享评价-)
- [发布到新的包管理器](#发布到新的包管理器)
- [联系方式 🌐](#联系方式-)
- [商标](#商标)
- [贡献 👩‍💻🧑‍💻](#贡献-)
- [作者](#作者)
- [许可证 📄](#许可证-)
## 安装
Bruno 可以在我们的 [网站上下载](https://www.usebruno.com/downloads) 适用于Mac、Windows 和 Linux 的可执行文件。
您也可以通过包管理器如 Homebrew、Chocolatey、Scoop、Snap 和 Apt 安装 Bruno。
@@ -58,80 +82,71 @@ choco install bruno
scoop bucket add extras
scoop install bruno
# 在 Windows 上用 winget 安装
winget install Bruno.Bruno
# 在 Linux 上用 Snap 安装
snap install bruno
# 在 Linux 上用 Flatpak 安装
flatpak install com.usebruno.Bruno
# 在 Linux 上用 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### 在 Mac 上通过 Homebrew 安装 🖥️
## 特性
### 跨平台使用 🖥️
![bruno](../../assets/images/run-anywhere.png) <br /><br />
### Collaborate 安装 👩‍💻🧑‍💻
### 通过Git协作 👩‍💻🧑‍💻
或者任何您选择的版本控制系统
![bruno](../../assets/images/version-control.png) <br /><br />
### 重要链接 📌
## 重要链接 📌
- [我们的愿景](https://github.com/usebruno/bruno/discussions/269)
- [路线图](https://github.com/usebruno/bruno/discussions/384)
- [路线图](https://www.usebruno.com/roadmap)
- [文档](https://docs.usebruno.com)
- [Stack Overflow](https://stackoverflow.com/questions/tagged/bruno)
- [网站](https://www.usebruno.com)
- [价格](https://www.usebruno.com/pricing)
- [下载](https://www.usebruno.com/downloads)
- [GitHub 赞助](https://github.com/sponsors/helloanoop).
### 展示 🎥
## 展示 🎥
- [Testimonials](https://github.com/usebruno/bruno/discussions/343)
- [Knowledge Hub](https://github.com/usebruno/bruno/discussions/386)
- [Scriptmania](https://github.com/usebruno/bruno/discussions/385)
### 支持 ❤️
如果您喜欢 Bruno 并想支持我们的开源工作,请考虑通过 [GitHub Sponsors](https://github.com/sponsors/helloanoop) 来赞助我们。
### 分享评价 📣
## 分享评价 📣
如果 Bruno 在您的工作和团队中帮助了您,请不要忘记在我们的 GitHub 讨论上分享您的 [评价](https://github.com/usebruno/bruno/discussions/343)
### 发布到新的包管理器
## 发布到新的包管理器
有关更多信息,请参见 [此处](../publishing/publishing_cn.md) 。
如需了解更多信息,请参见 [此处](../publishing/publishing_cn.md) 。
### 贡献 👩‍💻🧑‍💻
我很高兴您希望改进 bruno。请查看 [贡献指南](../contributing/contributing_cn.md)。
即使您无法通过代码做出贡献,我们仍然欢迎您提出 BUG 和新的功能需求。
### 作者
<div align="center">
<a href="https://github.com/usebruno/bruno/graphs/contributors">
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
</a>
</div>
### 联系方式 🌐
## 联系方式 🌐
[𝕏 (Twitter)](https://twitter.com/use_bruno) <br />
[Website](https://www.usebruno.com) <br />
[Discord](https://discord.com/invite/KgcZUncpjq) <br />
[LinkedIn](https://www.linkedin.com/company/usebruno)
### 商标
## 商标
**名称**
@@ -141,6 +156,20 @@ sudo apt install bruno
Logo 源自 [OpenMoji](https://openmoji.org/library/emoji-1F436/). License: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
### 许可证 📄
## 贡献 👩‍💻🧑‍💻
很高兴您希望改进 bruno。请查看 [贡献指南](../contributing/contributing_cn.md)。
即使您无法通过代码做出贡献,我们仍然欢迎您提出 BUG 和新的功能需求。
## 作者
<div align="center">
<a href="https://github.com/usebruno/bruno/graphs/contributors">
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
</a>
</div>
## 许可证 📄
[MIT](../../license.md)

View File

@@ -78,12 +78,14 @@ flatpak install com.usebruno.Bruno
# Auf 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### Einsatz auf verschiedensten Plattformen 🖥️

View File

@@ -75,12 +75,14 @@ flatpak install com.usebruno.Bruno
# En Linux con 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### Ejecútalo en múltiples plataformas 🖥️

View File

@@ -63,12 +63,14 @@ snap install bruno
# 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### Fonctionne sur de multiples plateformes 🖥️

152
docs/readme/readme_hi.md Normal file
View File

@@ -0,0 +1,152 @@
<br />
<img src="../../assets/images/logo-transparent.png" width="80"/>
### ब्रूनो - API इंटरफेस (API) का अन्वेषण और परीक्षण करने के लिए एक ओपन-सोर्स विकास वातावरण।
[![GitHub संस्करण](https://badge.fury.io/gh/usebruno%2Fbruno.svg)](https://badge.fury.io/gh/usebruno%2Fbruno)
[![CI](https://github.com/usebruno/bruno/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/usebruno/bruno/actions/workflows/tests.yml)
[![कमिट गतिविधि](https://img.shields.io/github/commit-activity/m/usebruno/bruno)](https://github.com/usebruno/bruno/pulse)
[![X](https://img.shields.io/twitter/follow/use_bruno?style=social&logo=x)](https://twitter.com/use_bruno)
[![वेबसाइट](https://img.shields.io/badge/Website-Visit-blue)](https://www.usebruno.com)
[![डाउनलोड](https://img.shields.io/badge/Download-Latest-brightgreen)](https://www.usebruno.com/downloads)
[English](../../readme.md)
| [Українська](./readme_ua.md)
| [Русский](./readme_ru.md)
| [Türkçe](./readme_tr.md)
| [Deutsch](./readme_de.md)
| [Français](./readme_fr.md)
| [Português (BR)](./readme_pt_br.md)
| [한국어](./readme_kr.md)
| [বাংলা](./readme_bn.md)
| [Español](./readme_es.md)
| [Italiano](./readme_it.md)
| [Română](./readme_ro.md)
| [Polski](./readme_pl.md)
| [简体中文](./readme_cn.md)
| [正體中文](./readme_zhtw.md)
| [العربية](./readme_ar.md)
| [日本語](./readme_ja.md)
| [ქართული](./readme_ka.md)
| **हिन्दी**
ब्रूनो एक नया और अभिनव API क्लाइंट है, जिसका उद्देश्य Postman और अन्य समान उपकरणों द्वारा प्रस्तुत स्थिति को बदलना है।
ब्रूनो आपकी कलेक्शनों को सीधे आपकी फाइल सिस्टम के एक फ़ोल्डर में संग्रहीत करता है। हम API अनुरोधों के बारे में जानकारी सहेजने के लिए एक सामान्य टेक्स्ट मार्कअप भाषा, Bru, का उपयोग करते हैं।
आप अपनी API कलेक्शनों पर सहयोग करने के लिए Git या अपनी पसंद के किसी भी संस्करण नियंत्रण प्रणाली का उपयोग कर सकते हैं।
ब्रूनो केवल ऑफ़लाइन उपयोग के लिए है। ब्रूनो में कभी भी क्लाउड-सिंक जोड़ने की कोई योजना नहीं है। हम आपके डेटा की गोपनीयता को महत्व देते हैं और मानते हैं कि इसे आपके डिवाइस पर ही रहना चाहिए। हमारी दीर्घकालिक दृष्टि [यहाँ](https://github.com/usebruno/bruno/discussions/269) पढ़ें।
📢 हमारे हालिया India FOSS 3.0 सम्मेलन में हमारे वार्तालाप को [यहाँ](https://www.youtube.com/watch?v=7bSMFpbcPiY) देखें।
![bruno](/assets/images/landing-2.png) <br /><br />
### गोल्डन संस्करण ✨
हमारी अधिकांश सुविधाएँ मुफ्त और ओपन-सोर्स हैं।
हम [पारदर्शिता और स्थिरता के सिद्धांतों](https://github.com/usebruno/bruno/discussions/269) के बीच एक सामंजस्यपूर्ण संतुलन प्राप्त करने का प्रयास करते हैं।
[गोल्डन संस्करण](https://www.usebruno.com/pricing) के लिए खरीदारी जल्द ही $9 की कीमत पर उपलब्ध होगी! <br/>
[यहाँ सदस्यता लें](https://usebruno.ck.page/4c65576bd4) ताकि आपको लॉन्च पर सूचनाएं मिलें।
### स्थापना
ब्रूनो Mac, Windows और Linux के लिए हमारे [वेबसाइट](https://www.usebruno.com/downloads) पर एक बाइनरी डाउनलोड के रूप में उपलब्ध है।
आप ब्रूनो को Homebrew, Chocolatey, Scoop, Snap, Flatpak और Apt जैसे पैकेज प्रबंधकों के माध्यम से भी स्थापित कर सकते हैं।
```sh
# Mac पर Homebrew के माध्यम से
brew install bruno
# Windows पर Chocolatey के माध्यम से
choco install bruno
# Windows पर Scoop के माध्यम से
scoop bucket add extras
scoop install bruno
# Linux पर Snap के माध्यम से
snap install bruno
# Linux पर Flatpak के माध्यम से
flatpak install com.usebruno.Bruno
# Linux पर Apt के माध्यम से
sudo mkdir -p /etc/apt/keyrings
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
कई प्लेटफार्मों पर चलाएं 🖥️
<br /><br />
Git के माध्यम से सहयोग करें 👩‍💻🧑‍💻
या अपनी पसंद के किसी भी संस्करण नियंत्रण प्रणाली का उपयोग करें
<br /><br />
महत्वपूर्ण लिंक 📌
हमारी दीर्घकालिक दृष्टि
रोडमैप
प्रलेखन
Stack Overflow
वेबसाइट
मूल्य निर्धारण
डाउनलोड
GitHub प्रायोजक
प्रस्तुतियाँ 🎥
प्रशंसापत्र
ज्ञान केंद्र
Scriptmania
समर्थन ❤️
यदि आप ब्रूनो को पसंद करते हैं और हमारे ओपन-सोर्स कार्य का समर्थन करना चाहते हैं, तो कृपया GitHub प्रायोजक के माध्यम से हमें प्रायोजित करने पर विचार करें।
प्रशंसापत्र साझा करें 📣
यदि ब्रूनो ने आपके और आपकी टीमों के लिए काम में मदद की है, तो कृपया हमारे GitHub चर्चा में अपने प्रशंसापत्र साझा करना न भूलें
नए पैकेज प्रबंधकों में प्रकाशित करना
अधिक जानकारी के लिए कृपया यहाँ देखें।
हमसे संपर्क करें 🌐
𝕏 (ट्विटर) <br />
वेबसाइट <br />
डिस्कॉर्ड <br />
लिंक्डइन
ट्रेडमार्क
नाम
ब्रूनो एक ट्रेडमार्क है जो अनूप एम डी के स्वामित्व में है।
लोगो
लोगो OpenMoji से लिया गया है। लाइसेंस: CC BY-SA 4.0
योगदान 👩‍💻🧑‍💻
हमें खुशी है कि आप ब्रूनो को बेहतर बनाने में रुचि रखते हैं। कृपया योगदान गाइड देखें।
यदि आप सीधे कोड के माध्यम से योगदान नहीं कर सकते, तो भी कृपया बग्स की रिपोर्ट करने और उन सुविधाओं का अनुरोध करने में संकोच न करें जिन्हें आपकी स्थिति को हल करने के लिए लागू किया जाना चाहिए।
लेखक
<div align="center"> <a href="https://github.com/usebruno/bruno/graphs/contributors"> <img src="https://contrib.rocks/image?repo=usebruno/bruno" /> </a> </div>
लाइसेंस 📄
MIT

View File

@@ -59,12 +59,14 @@ snap install bruno
# Su Linux tramite 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### Funziona su diverse piattaforme 🖥️

View File

@@ -78,12 +78,14 @@ flatpak install com.usebruno.Bruno
# Linuxで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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### マルチプラットフォームでの実行に対応 🖥️

View File

@@ -77,12 +77,14 @@ flatpak install com.usebruno.Bruno
# Linux-ზე 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 [arch=amd64 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### პლატფორმებს შორის მუშაობა 🖥️

View File

@@ -59,12 +59,14 @@ 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### 여러 플랫폼에서 실행하세요. 🖥️

View File

@@ -61,12 +61,14 @@ flatpak install com.usebruno.Bruno
# Op 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 [arch=amd64 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### Draai op meerdere platformen 🖥️

View File

@@ -69,12 +69,14 @@ flatpak install com.usebruno.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 [arch=amd64 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### Uruchom na wielu platformach 🖥️

View File

@@ -76,12 +76,14 @@ flatpak install com.usebruno.Bruno
# No 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### Execute em várias plataformas 🖥️

View File

@@ -59,12 +59,14 @@ snap install bruno
# Pe Linux cu 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### Utilizați pe mai multe platforme 🖥️

View File

@@ -63,12 +63,14 @@ snap install bruno
# Apt aracılığıyla Linux'ta
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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### Birden fazla platformda çalıştırın 🖥️

View File

@@ -63,12 +63,14 @@ snap install bruno
# 在 Linux 上使用 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
sudo apt update && sudo apt install gpg curl
curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9FA6017ECABE0266" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/bruno.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/bruno.gpg
echo "deb [arch=amd64 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
```
### 跨多個平台運行 🖥️

263
eslint.config.js Normal file
View File

@@ -0,0 +1,263 @@
// eslint.config.js
const { defineConfig } = require("eslint/config");
const globals = require("globals");
const { fixupPluginRules } = require('@eslint/compat');
const eslintPluginDiff = require('eslint-plugin-diff');
let stylistic;
const runESMImports = async () => {
stylistic = await import('@stylistic/eslint-plugin').then((d) => d.default);
};
module.exports = runESMImports().then(() => defineConfig([
{
plugins: {
'diff': fixupPluginRules(eslintPluginDiff),
'@stylistic': stylistic
},
languageOptions: {
parser: require('@typescript-eslint/parser'),
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module'
}
},
files: [
'./eslint.config.js',
'tests/**/*.{ts,js}',
'packages/bruno-app/**/*.{js,jsx,ts}',
'packages/bruno-app/src/test-utils/mocks/codemirror.js',
'packages/bruno-cli/**/*.js',
'packages/bruno-common/**/*.ts',
'packages/bruno-converters/**/*.js',
'packages/bruno-electron/**/*.js',
'packages/bruno-filestore/**/*.ts',
'packages/bruno-js/**/*.js',
'packages/bruno-lang/**/*.js',
'packages/bruno-requests/**/*.ts',
'packages/bruno-requests/**/*.js',
'packages/bruno-tests/**/*.{js,ts}'
],
processor: 'diff/diff',
rules: {
...stylistic.configs.customize({
indent: 2,
quotes: 'single',
semi: true,
jsx: true
}).rules,
'@stylistic/comma-dangle': ['error', 'never'],
'@stylistic/brace-style': ['error', '1tbs', { allowSingleLine: true }],
'@stylistic/arrow-parens': ['error', 'always'],
'@stylistic/curly-newline': ['error', {
multiline: true,
minElements: 2,
consistent: true
}],
'@stylistic/function-paren-newline': ['error', 'never'],
'@stylistic/array-bracket-spacing': ['error', 'never'],
'@stylistic/arrow-spacing': ['error', { before: true, after: true }],
'@stylistic/function-call-spacing': ['error', 'never'],
'@stylistic/multiline-ternary': ['off'],
'@stylistic/padding-line-between-statements': ['off'],
'@stylistic/semi-style': ['error', 'last'],
'@stylistic/max-len': ['off'],
'@stylistic/jsx-one-expression-per-line': ['off']
}
},
{
files: ["packages/bruno-app/**/*.{js,jsx,ts}"],
ignores: ["**/*.config.js", "**/public/**/*"],
languageOptions: {
globals: {
...globals.browser,
...globals.jest,
global: false,
require: false,
Buffer: false,
process: false,
ipcRenderer: false
},
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
rules: {
"no-undef": "error",
},
},
{
// It prevents lint errors when using CommonJS exports (module.exports) in Jest mocks.
files: ["packages/bruno-app/src/test-utils/mocks/codemirror.js"],
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
},
rules: {
"no-undef": "error",
},
},
{
files: ["packages/bruno-cli/**/*.js"],
ignores: ["**/*.config.js"],
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
parserOptions: {
ecmaVersion: "latest"
},
},
rules: {
"no-undef": "error",
},
},
{
files: ["packages/bruno-common/**/*.ts"],
ignores: ["**/*.config.js", "**/dist/**/*"],
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
parser: require("@typescript-eslint/parser"),
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
project: "./packages/bruno-common/tsconfig.json",
},
},
rules: {
"no-undef": "error",
},
},
{
files: ["packages/bruno-converters/**/*.js"],
ignores: ["**/*.config.js", "**/dist/**/*"],
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
},
rules: {
"no-undef": "error",
},
},
{
files: ["packages/bruno-electron/**/*.js"],
ignores: ["**/*.config.js", "**/web/**/*"],
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
},
rules: {
"no-undef": "error",
},
},
{
files: ["packages/bruno-filestore/**/*.ts"],
ignores: ["**/*.config.js", "**/dist/**/*"],
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
parser: require("@typescript-eslint/parser"),
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
project: "./packages/bruno-filestore/tsconfig.json",
},
},
rules: {
"no-undef": "error",
},
},
{
files: ["packages/bruno-js/**/*.js"],
ignores: ["**/*.config.js", "**/dist/**/*"],
languageOptions: {
globals: {
...globals.node,
...globals.jest,
window: false,
self: false,
HTMLElement: false,
typeDetectGlobalObject: false
},
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
},
rules: {
"no-undef": "error",
},
},
{
files: ["packages/bruno-lang/**/*.js"],
ignores: ["**/*.config.js", "**/dist/**/*"],
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
},
rules: {
"no-undef": "error",
},
},
{
files: ["packages/bruno-requests/**/*.ts"],
ignores: ["**/*.config.js", "**/dist/**/*"],
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
parser: require("@typescript-eslint/parser"),
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
project: "./packages/bruno-requests/tsconfig.json",
},
},
rules: {
"no-undef": "error",
},
},
{
files: ["packages/bruno-requests/**/*.js"],
ignores: ["**/*.config.js", "**/dist/**/*"],
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
},
rules: {
"no-undef": "error",
},
},
]));

8812
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,24 +6,39 @@
"packages/bruno-electron",
"packages/bruno-cli",
"packages/bruno-common",
"packages/bruno-converters",
"packages/bruno-schema",
"packages/bruno-query",
"packages/bruno-js",
"packages/bruno-lang",
"packages/bruno-tests",
"packages/bruno-toml",
"packages/bruno-graphql-docs"
"packages/bruno-graphql-docs",
"packages/bruno-requests",
"packages/bruno-filestore"
],
"homepage": "https://usebruno.com",
"devDependencies": {
"@eslint/compat": "^1.3.2",
"@faker-js/faker": "^7.6.0",
"@jest/globals": "^29.2.0",
"@playwright/test": "^1.27.1",
"@playwright/test": "^1.51.1",
"@rollup/plugin-json": "^6.1.0",
"@stylistic/eslint-plugin": "^5.3.1",
"@types/jest": "^29.5.11",
"@types/lodash-es": "^4.17.12",
"@types/node": "^22.14.1",
"@typescript-eslint/parser": "^8.39.0",
"concurrently": "^8.2.2",
"eslint": "^9.26.0",
"eslint-plugin-diff": "^2.0.3",
"fs-extra": "^11.1.1",
"husky": "^8.0.3",
"globals": "^16.1.0",
"husky": "^9.1.7",
"jest": "^29.2.0",
"lodash-es": "^4.17.21",
"nano-staged": "^0.8.0",
"playwright": "^1.51.1",
"pretty-quick": "^3.1.3",
"randomstring": "^1.2.2",
"rimraf": "^6.0.1",
@@ -31,13 +46,19 @@
},
"scripts": {
"setup": "node ./scripts/setup.js",
"watch:converters": "npm run watch --workspace=packages/bruno-converters",
"dev": "concurrently --kill-others \"npm run dev:web\" \"npm run dev:electron\"",
"watch": "npm run dev:watch",
"dev:watch": "node ./scripts/dev-hot-reload.js",
"dev:web": "npm run dev --workspace=packages/bruno-app",
"build:web": "npm run build --workspace=packages/bruno-app",
"prettier:web": "npm run prettier --workspace=packages/bruno-app",
"dev:electron": "npm run dev --workspace=packages/bruno-electron",
"dev:electron:debug": "npm run debug --workspace=packages/bruno-electron",
"build:bruno-common": "npm run build --workspace=packages/bruno-common",
"build:bruno-requests": "npm run build --workspace=packages/bruno-requests",
"build:bruno-filestore": "npm run build --workspace=packages/bruno-filestore",
"build:bruno-converters": "npm run build --workspace=packages/bruno-converters",
"build:bruno-query": "npm run build --workspace=packages/bruno-query",
"build:graphql-docs": "npm run build --workspace=packages/bruno-graphql-docs",
"build:electron": "node ./scripts/build-electron.js",
@@ -47,12 +68,26 @@
"build:electron:deb": "./scripts/build-electron.sh deb",
"build:electron:rpm": "./scripts/build-electron.sh rpm",
"build:electron:snap": "./scripts/build-electron.sh snap",
"test:e2e": "npx playwright test",
"test:report": "npx playwright show-report",
"watch:common": "npm run watch --workspace=packages/bruno-common",
"test:codegen": "node playwright/codegen.ts",
"test:e2e": "playwright test --project=default",
"test:e2e:ssl": "playwright test --project=ssl",
"test:prettier:web": "npm run test:prettier --workspace=packages/bruno-app",
"prepare": "husky install"
"lint": "node --max_old_space_size=4096 $(npx which eslint)",
"lint:fix": "node --max_old_space_size=4096 $(npx which eslint) --fix",
"prepare": "husky"
},
"nano-staged": {
"*.{js,ts,jsx}": [
"npm run lint:fix"
]
},
"overrides": {
"rollup": "3.29.5"
"rollup": "3.29.5",
"electron-store": {
"conf": {
"json-schema-typed": "8.0.1"
}
}
}
}

View File

@@ -1,4 +1,4 @@
{
"presets": ["@babel/preset-env"],
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": [["styled-components", { "ssr": true }]]
}

View File

@@ -0,0 +1,9 @@
module.exports = {
presets: [
'@babel/preset-env',
['@babel/preset-react', {
runtime: 'automatic'
}]
],
plugins: ['babel-plugin-styled-components']
};

View File

@@ -1,5 +1,11 @@
module.exports = {
rootDir: '.',
transform: {
'^.+\\.[jt]sx?$': 'babel-jest',
},
transformIgnorePatterns: [
"/node_modules/(?!strip-json-comments|nanoid|xml-formatter)/",
],
moduleNameMapper: {
'^assets/(.*)$': '<rootDir>/src/assets/$1',
'^components/(.*)$': '<rootDir>/src/components/$1',
@@ -8,9 +14,17 @@ module.exports = {
'^api/(.*)$': '<rootDir>/src/api/$1',
'^pageComponents/(.*)$': '<rootDir>/src/pageComponents/$1',
'^providers/(.*)$': '<rootDir>/src/providers/$1',
'^utils/(.*)$': '<rootDir>/src/utils/$1'
'^utils/(.*)$': '<rootDir>/src/utils/$1',
'^test-utils/(.*)$': '<rootDir>/src/test-utils/$1'
},
clearMocks: true,
moduleDirectories: ['node_modules', 'src'],
testEnvironment: 'node'
};
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['@testing-library/jest-dom'],
setupFiles: [
'<rootDir>/jest.setup.js',
],
testMatch: [
'<rootDir>/src/**/*.spec.[jt]s?(x)'
]
};

View File

@@ -0,0 +1,11 @@
jest.mock('nanoid', () => {
return {
nanoid: () => {}
};
});
jest.mock('strip-json-comments', () => {
return {
stripJsonComments: (str) => str
};
});

View File

@@ -6,6 +6,7 @@
"baseUrl": "./",
"paths": {
"assets/*": ["src/assets/*"],
"ui/*": ["src/ui/*"],
"components/*": ["src/components/*"],
"hooks/*": ["src/hooks/*"],
"themes/*": ["src/themes/*"],

View File

@@ -1,6 +1,7 @@
{
"name": "@usebruno/app",
"version": "1.39.0",
"version": "2.0.0",
"license": "MIT",
"private": true,
"scripts": {
"dev": "rsbuild dev",
@@ -11,11 +12,11 @@
"prettier": "prettier --write \"./src/**/*.{js,jsx,json,ts,tsx}\""
},
"dependencies": {
"@babel/preset-env": "^7.26.0",
"@fontsource/inter": "^5.0.15",
"@prantlf/jsonlint": "^16.0.0",
"@reduxjs/toolkit": "^1.8.0",
"@tabler/icons": "^1.46.0",
"@testing-library/user-event": "^14.6.1",
"@tippyjs/react": "^4.2.6",
"@usebruno/common": "0.1.0",
"@usebruno/graphql-docs": "0.1.0",
@@ -67,39 +68,54 @@
"react-hot-toast": "^2.4.0",
"react-i18next": "^15.0.1",
"react-inspector": "^6.0.2",
"react-json-view": "^1.21.3",
"react-pdf": "9.1.1",
"react-player": "^2.16.0",
"react-redux": "^7.2.9",
"react-tooltip": "^5.5.2",
"sass": "^1.46.0",
"semver": "^7.7.1",
"shell-quote": "^1.8.3",
"strip-json-comments": "^5.0.1",
"styled-components": "^5.3.3",
"system": "^2.0.1",
"url": "^0.11.3",
"xml-formatter": "^3.5.0",
"yargs-parser": "^21.1.1",
"yup": "^0.32.11"
},
"devDependencies": {
"@babel/core": "^7.27.1",
"@babel/preset-env": "^7.27.2",
"@babel/preset-react": "^7.27.1",
"@rsbuild/core": "^1.1.2",
"@rsbuild/plugin-babel": "^1.0.3",
"@rsbuild/plugin-node-polyfill": "^1.2.0",
"@rsbuild/plugin-react": "^1.0.7",
"@rsbuild/plugin-sass": "^1.1.0",
"@rsbuild/plugin-styled-components": "1.1.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"autoprefixer": "10.4.20",
"babel-jest": "^29.7.0",
"babel-plugin-react-compiler": "19.0.0-beta-a7bf2bd-20241110",
"babel-plugin-styled-components": "^2.1.4",
"cross-env": "^7.0.3",
"css-loader": "7.1.2",
"file-loader": "^6.2.0",
"html-loader": "^3.0.1",
"html-webpack-plugin": "^5.5.0",
"jest-environment-jsdom": "^29.7.0",
"mini-css-extract-plugin": "^2.4.5",
"postcss": "8.4.47",
"style-loader": "^3.3.1",
"tailwindcss": "^3.4.1",
"webpack": "^5.64.4",
"webpack-cli": "^4.9.1"
},
"overrides": {
"httpsnippet": {
"form-data": "4.0.4"
}
}
}

View File

@@ -19,7 +19,12 @@ export default defineConfig({
})
],
source: {
tsconfigPath: './jsconfig.json', // Specifies the path to the JavaScript/TypeScript configuration file
tsconfigPath: './jsconfig.json', // Specifies the path to the JavaScript/TypeScript configuration file,
exclude: [
'**/test-utils/**',
'**/*.test.*',
'**/*.spec.*'
]
},
html: {
title: 'Bruno'
@@ -34,6 +39,16 @@ export default defineConfig({
},
},
},
ignoreWarnings: [
(warning) => warning.message.includes('Critical dependency: the request of a dependency is an expression') && warning?.moduleDescriptor?.name?.includes('flow-parser')
],
// Add externals configuration to exclude Node.js libraries
externals: {
// List specific Node.js modules you want to exclude
// Format: 'module-name': 'commonjs module-name'
'worker_threads': 'commonjs worker_threads',
// 'path': 'commonjs path'
}
},
}
});

View File

@@ -0,0 +1,40 @@
import React, { useMemo } from 'react';
import CodeEditor from 'components/CodeEditor';
import { useTheme } from 'providers/Theme';
import { useSelector } from 'react-redux';
import { parseBulkKeyValue, serializeBulkKeyValue } from 'utils/common/bulkKeyValueUtils';
const BulkEditor = ({ params, onChange, onToggle, onSave, onRun }) => {
const preferences = useSelector((state) => state.app.preferences);
const { displayedTheme } = useTheme();
const parsedParams = useMemo(() => serializeBulkKeyValue(params), [params]);
const handleEdit = (value) => {
const parsed = parseBulkKeyValue(value);
onChange(parsed);
};
return (
<>
<div className="h-[200px]">
<CodeEditor
mode="text/plain"
theme={displayedTheme}
font={preferences.codeFont || 'default'}
value={parsedParams}
onEdit={handleEdit}
onSave={onSave}
onRun={onRun}
/>
</div>
<div className="flex btn-action justify-between items-center mt-3">
<button className="text-link select-none ml-auto" onClick={onToggle}>
Key/Value Edit
</button>
</div>
</>
);
};
export default BulkEditor;

View File

@@ -102,6 +102,24 @@ const StyledWrapper = styled.div`
.cm-s-default span.cm-variable {
color: #397d13 !important;
}
//matching bracket fix
.CodeMirror-matchingbracket {
background: #5cc0b48c !important;
text-decoration:unset;
}
.cm-search-line-highlight {
background: ${(props) => props.theme.codemirror.searchLineHighlightCurrent};
}
.cm-search-match {
background: rgba(255, 193, 7, 0.25);
}
.cm-search-current {
background: rgba(255, 193, 7, 0.4);
}
`;
export default StyledWrapper;

View File

@@ -8,116 +8,20 @@
import React from 'react';
import { isEqual, escapeRegExp } from 'lodash';
import { defineCodeMirrorBrunoVariablesMode } from 'utils/common/codemirror';
import { setupAutoComplete } from 'utils/codemirror/autocomplete';
import StyledWrapper from './StyledWrapper';
import * as jsonlint from '@prantlf/jsonlint';
import { JSHINT } from 'jshint';
import stripJsonComments from 'strip-json-comments';
import { getAllVariables } from 'utils/collections';
import CodeMirrorSearch from 'components/CodeMirrorSearch';
const CodeMirror = require('codemirror');
window.jsonlint = jsonlint;
window.JSHINT = JSHINT;
let CodeMirror;
const SERVER_RENDERED = typeof window === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
const TAB_SIZE = 2;
if (!SERVER_RENDERED) {
CodeMirror = require('codemirror');
window.jsonlint = jsonlint;
window.JSHINT = JSHINT;
//This should be done dynamically if possible
const hintWords = [
'res',
'res.status',
'res.statusText',
'res.headers',
'res.body',
'res.responseTime',
'res.getStatus()',
'res.getStatusText()',
'res.getHeader(name)',
'res.getHeaders()',
'res.getBody()',
'res.getResponseTime()',
'req',
'req.url',
'req.method',
'req.headers',
'req.body',
'req.timeout',
'req.getUrl()',
'req.setUrl(url)',
'req.getMethod()',
'req.getAuthMode()',
'req.setMethod(method)',
'req.getHeader(name)',
'req.getHeaders()',
'req.setHeader(name, value)',
'req.setHeaders(data)',
'req.getBody()',
'req.setBody(data)',
'req.setMaxRedirects(maxRedirects)',
'req.getTimeout()',
'req.setTimeout(timeout)',
'req.getExecutionMode()',
'bru',
'bru.cwd()',
'bru.getEnvName()',
'bru.getProcessEnv(key)',
'bru.hasEnvVar(key)',
'bru.getEnvVar(key)',
'bru.getFolderVar(key)',
'bru.getCollectionVar(key)',
'bru.setEnvVar(key,value)',
'bru.deleteEnvVar(key)',
'bru.hasVar(key)',
'bru.getVar(key)',
'bru.setVar(key,value)',
'bru.deleteVar(key)',
'bru.deleteAllVars()',
'bru.setNextRequest(requestName)',
'req.disableParsingResponseJson()',
'bru.getRequestVar(key)',
'bru.runRequest(requestPathName)',
'bru.getAssertionResults()',
'bru.getTestResults()',
'bru.sleep(ms)',
'bru.getGlobalEnvVar(key)',
'bru.setGlobalEnvVar(key, value)',
'bru.runner',
'bru.runner.setNextRequest(requestName)',
'bru.runner.skipRequest()',
'bru.runner.stopExecution()'
];
CodeMirror.registerHelper('hint', 'brunoJS', (editor, options) => {
const cursor = editor.getCursor();
const currentLine = editor.getLine(cursor.line);
let startBru = cursor.ch;
let endBru = startBru;
while (endBru < currentLine.length && /[\w.]/.test(currentLine.charAt(endBru))) ++endBru;
while (startBru && /[\w.]/.test(currentLine.charAt(startBru - 1))) --startBru;
let curWordBru = startBru != endBru && currentLine.slice(startBru, endBru);
let start = cursor.ch;
let end = start;
while (end < currentLine.length && /[\w]/.test(currentLine.charAt(end))) ++end;
while (start && /[\w]/.test(currentLine.charAt(start - 1))) --start;
const jsHinter = CodeMirror.hint.javascript;
let result = jsHinter(editor) || { list: [] };
result.to = CodeMirror.Pos(cursor.line, end);
result.from = CodeMirror.Pos(cursor.line, start);
if (curWordBru) {
hintWords.forEach((h) => {
if (h.includes('.') == curWordBru.includes('.') && h.startsWith(curWordBru)) {
result.list.push(curWordBru.includes('.') ? h.split('.')?.at(-1) : h);
}
});
result.list?.sort();
}
return result;
});
CodeMirror.commands.autocomplete = (cm, hint, options) => {
cm.showHint({ hint, ...options });
};
}
export default class CodeEditor extends React.Component {
constructor(props) {
super(props);
@@ -134,15 +38,24 @@ export default class CodeEditor extends React.Component {
expr: true,
asi: true
};
this.state = {
searchBarVisible: false
};
}
componentDidMount() {
const variables = getAllVariables(this.props.collection, this.props.item);
const editor = (this.editor = CodeMirror(this._node, {
value: this.props.value || '',
lineNumbers: true,
lineWrapping: true,
lineWrapping: this.props.enableLineWrapping ?? true,
tabSize: TAB_SIZE,
mode: this.props.mode || 'application/ld+json',
brunoVarInfo: {
variables
},
keyMap: 'sublime',
autoCloseBrackets: true,
matchBrackets: true,
@@ -175,24 +88,14 @@ export default class CodeEditor extends React.Component {
}
},
'Cmd-F': (cm) => {
if (this._isSearchOpen()) {
// replace the older search component with the new one
const search = document.querySelector('.CodeMirror-dialog.CodeMirror-dialog-top');
search && search.remove();
if (!this.state.searchBarVisible) {
this.setState({ searchBarVisible: true });
}
cm.execCommand('findPersistent');
this._bindSearchHandler();
this._appendSearchResultsCount();
},
'Ctrl-F': (cm) => {
if (this._isSearchOpen()) {
// replace the older search component with the new one
const search = document.querySelector('.CodeMirror-dialog.CodeMirror-dialog-top');
search && search.remove();
if (!this.state.searchBarVisible) {
this.setState({ searchBarVisible: true });
}
cm.execCommand('findPersistent');
this._bindSearchHandler();
this._appendSearchResultsCount();
},
'Cmd-H': 'replace',
'Ctrl-H': 'replace',
@@ -221,7 +124,19 @@ export default class CodeEditor extends React.Component {
} else {
this.editor.toggleComment();
}
}
},
'Esc': () => {
if (this.state.searchBarVisible) {
this.setState({ searchBarVisible: false });
}
},
// Pass through tab navigation shortcuts to global handlers
'Cmd-W': () => CodeMirror.Pass,
'Ctrl-W': () => CodeMirror.Pass,
'Cmd-PageUp': () => CodeMirror.Pass,
'Ctrl-PageUp': () => CodeMirror.Pass,
'Cmd-PageDown': () => CodeMirror.Pass,
'Ctrl-PageDown': () => CodeMirror.Pass
},
foldOptions: {
widget: (from, to) => {
@@ -274,30 +189,26 @@ export default class CodeEditor extends React.Component {
}
return found;
});
if (editor) {
editor.setOption('lint', this.props.mode && editor.getValue().trim().length > 0 ? this.lintOptions : false);
editor.on('change', this._onEdit);
editor.on('scroll', this.onScroll);
editor.scrollTo(null, this.props.initialScroll);
this.addOverlay();
}
if (this.props.mode == 'javascript') {
editor.on('keyup', function (cm, event) {
const cursor = editor.getCursor();
const currentLine = editor.getLine(cursor.line);
let start = cursor.ch;
let end = start;
while (end < currentLine.length && /[^{}();\s\[\]\,]/.test(currentLine.charAt(end))) ++end;
while (start && /[^{}();\s\[\]\,]/.test(currentLine.charAt(start - 1))) --start;
let curWord = start != end && currentLine.slice(start, end);
// Qualify if autocomplete will be shown
if (
/^(?!Shift|Tab|Enter|Escape|ArrowUp|ArrowDown|ArrowLeft|ArrowRight|Meta|Alt|Home|End\s)\w*/.test(event.key) &&
curWord.length > 0 &&
!/\/\/|\/\*|.*{{|`[^$]*{|`[^{]*$/.test(currentLine.slice(0, end)) &&
/(?<!\d)[a-zA-Z\._]$/.test(curWord)
) {
CodeMirror.commands.autocomplete(cm, CodeMirror.hint.brunoJS, { completeSingle: false });
}
});
const getAllVariablesHandler = () => getAllVariables(this.props.collection, this.props.item);
// Setup AutoComplete Helper for all modes
const autoCompleteOptions = {
showHintsFor: this.props.showHintsFor,
getAllVariables: getAllVariablesHandler
};
this.brunoAutoCompleteCleanup = setupAutoComplete(
editor,
autoCompleteOptions
);
}
}
@@ -328,16 +239,28 @@ export default class CodeEditor extends React.Component {
if (this.props.theme !== prevProps.theme && this.editor) {
this.editor.setOption('theme', this.props.theme === 'dark' ? 'monokai' : 'default');
}
if (this.props.initialScroll !== prevProps.initialScroll) {
this.editor.scrollTo(null, this.props.initialScroll);
}
if (this.props.enableLineWrapping !== prevProps.enableLineWrapping) {
this.editor.setOption('lineWrapping', this.props.enableLineWrapping);
}
if (this.props.mode !== prevProps.mode) {
this.editor.setOption('mode', this.props.mode);
}
this.ignoreChangeEvent = false;
}
componentWillUnmount() {
if (this.editor) {
this.editor.off('change', this._onEdit);
this.editor.off('scroll', this.onScroll);
this.editor = null;
}
this._unbindSearchHandler();
}
render() {
@@ -350,10 +273,18 @@ export default class CodeEditor extends React.Component {
aria-label="Code Editor"
font={this.props.font}
fontSize={this.props.fontSize}
ref={(node) => {
this._node = node;
}}
/>
>
<CodeMirrorSearch
visible={this.state.searchBarVisible}
editor={this.editor}
onClose={() => this.setState({ searchBarVisible: false })}
/>
<div
className={`editor-container${this.state.searchBarVisible ? ' search-bar-visible' : ''}`}
ref={(node) => { this._node = node; }}
style={{ height: '100%', width: '100%' }}
/>
</StyledWrapper>
);
}
@@ -362,10 +293,12 @@ export default class CodeEditor extends React.Component {
let variables = getAllVariables(this.props.collection, this.props.item);
this.variables = variables;
defineCodeMirrorBrunoVariablesMode(variables, mode);
defineCodeMirrorBrunoVariablesMode(variables, mode, false, this.props.enableVariableHighlighting);
this.editor.setOption('mode', 'brunovariables');
};
onScroll = (event) => this.props.onScroll?.(event);
_onEdit = () => {
if (!this.ignoreChangeEvent && this.editor) {
this.editor.setOption('lint', this.editor.getValue().trim().length > 0 ? this.lintOptions : false);
@@ -375,67 +308,4 @@ export default class CodeEditor extends React.Component {
}
}
};
_isSearchOpen = () => {
return document.querySelector('.CodeMirror-dialog.CodeMirror-dialog-top');
};
/**
* Bind handler to search input to count number of search results
*/
_bindSearchHandler = () => {
const searchInput = document.querySelector('.CodeMirror-search-field');
if (searchInput) {
searchInput.addEventListener('input', this._countSearchResults);
}
};
/**
* Unbind handler to search input to count number of search results
*/
_unbindSearchHandler = () => {
const searchInput = document.querySelector('.CodeMirror-search-field');
if (searchInput) {
searchInput.removeEventListener('input', this._countSearchResults);
}
};
/**
* Append search results count to search dialog
*/
_appendSearchResultsCount = () => {
const dialog = document.querySelector('.CodeMirror-dialog.CodeMirror-dialog-top');
if (dialog) {
const searchResultsCount = document.createElement('span');
searchResultsCount.id = this.searchResultsCountElementId;
dialog.appendChild(searchResultsCount);
this._countSearchResults();
}
};
/**
* Count search results and update state
*/
_countSearchResults = () => {
let count = 0;
const searchInput = document.querySelector('.CodeMirror-search-field');
if (searchInput && searchInput.value.length > 0) {
// Escape special characters in search input to prevent RegExp crashes. Fixes #3051
const text = new RegExp(escapeRegExp(searchInput.value), 'gi');
const matches = this.editor.getValue().match(text);
count = matches ? matches.length : 0;
}
const searchResultsCountElement = document.querySelector(`#${this.searchResultsCountElementId}`);
if (searchResultsCountElement) {
searchResultsCountElement.innerText = `${count} results`;
}
};
}

View File

@@ -0,0 +1,51 @@
import React from 'react';
import { render, act } from '@testing-library/react';
import CodeEditor from './index';
import { ThemeProvider } from 'styled-components';
jest.mock('codemirror', () => {
const codemirror = require('test-utils/mocks/codemirror');
return codemirror;
});
const MOCK_THEME = {
codemirror: {
bg: "#1e1e1e",
border: "#333",
},
textLink: "#007acc",
};
const setupEditorState = (editor, { value, cursorPosition }) => {
editor._currentValue = value;
editor.getCursor.mockReturnValue({ line: 0, ch: cursorPosition });
editor.getRange.mockImplementation((from, to) => {
if (from.line === 0 && from.ch === 0 && to.line === 0 && to.ch === cursorPosition) {
return value;
}
return editor._currentValue.slice(from.ch, to.ch);
});
editor.state = {
completionActive: null,
}
};
const setupEditorWithRef = () => {
const ref = React.createRef();
const { rerender } = render(
<ThemeProvider theme={MOCK_THEME}>
<CodeEditor ref={ref} />
</ThemeProvider>
);
return { ref, rerender };
};
describe('CodeEditor', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.resetModules();
});
it("add CodeEditor related tests here", () => {});
});

View File

@@ -0,0 +1,99 @@
import styled from 'styled-components';
const StyledWrapper = styled.div`
.bruno-search-bar {
position: absolute;
top: 8px;
right: 8px;
z-index: 20;
display: flex;
align-items: center;
flex-wrap: nowrap;
padding: 0 2px;
min-height: 36px;
background: ${(props) => props.theme.sidebar.search.bg} !important;
border-radius: 4px;
border: 1px solid ${(props) => props.theme.sidebar.search.bg} !important;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
width: auto;
min-width: 180px;
max-width: 320px;
}
.bruno-search-bar input {
min-width: 80px;
background: transparent;
color: inherit;
border: none;
outline: none;
padding: 1px 2px;
font-size: 13px;
margin: 0 1px;
height: 28px;
}
.searchbar-icon-btn {
background: none;
border: none;
padding: 0 1px;
margin: 0 1px;
cursor: pointer;
color: #aaa;
border-radius: 3px;
height: 18px;
width: 18px;
display: flex;
align-items: center;
justify-content: center;
}
.searchbar-result-count {
min-width: 28px;
text-align: center;
font-size: 11px;
color: #aaa;
margin: 0 8px 0 1px;
white-space: nowrap;
}
.bruno-search-bar.compact {
background: ${(props) => props.theme.codemirror.bg};
color: ${(props) => props.theme.codemirror.text || props.theme.text};
border: none;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
border-radius: 4px;
padding: 1px 3px;
min-height: 22px;
display: flex;
align-items: center;
gap: 0;
}
.bruno-search-bar input {
background: transparent;
color: inherit;
border: none;
outline: none;
font-size: 13px;
padding: 1px 2px;
min-width: 80px;
}
.searchbar-icon-btn:focus {
outline: 1px solid ${(props) => props.theme.codemirror.border};
}
.bruno-search-bar, .bruno-search-bar input {
font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
}
.cm-search-line-highlight {
background: ${(props) => props.theme.codemirror.searchLineHighlightCurrent};
}
.searchbar-icon-btn.active {
color: #f39c12 !important;
}
`;
export default StyledWrapper;

View File

@@ -0,0 +1,201 @@
import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import { IconRegex, IconArrowUp, IconArrowDown, IconX, IconLetterCase, IconLetterW } from '@tabler/icons';
import ToolHint from 'components/ToolHint';
import StyledWrapper from './StyledWrapper';
import useDebounce from 'hooks/useDebounce';
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');
}
const CodeMirrorSearch = ({ visible, editor, onClose }) => {
const [searchText, setSearchText] = useState('');
const [regex, setRegex] = useState(false);
const [caseSensitive, setCaseSensitive] = useState(false);
const [wholeWord, setWholeWord] = useState(false);
const [matchIndex, setMatchIndex] = useState(0);
const [matchCount, setMatchCount] = useState(0);
const searchMarks = useRef([]);
const searchLineHighlight = useRef(null);
const searchMatches = useRef([]);
const debouncedSearchText = useDebounce(searchText, 150);
const memoizedMatches = useMemo(() => {
if (!editor || !visible) return [];
if (!debouncedSearchText) return [];
try {
let query, options = {};
if (regex) {
try {
query = new RegExp(debouncedSearchText, caseSensitive ? 'g' : 'gi');
} catch {
return [];
}
} else if (wholeWord) {
const escaped = escapeRegExp(debouncedSearchText);
query = new RegExp(`\\b${escaped}\\b`, caseSensitive ? 'g' : 'gi');
} else {
query = debouncedSearchText;
options = { caseFold: !caseSensitive };
}
const cursor = editor.getSearchCursor(query, { line: 0, ch: 0 }, options);
const out = [];
while (cursor.findNext()) {
out.push({ from: cursor.from(), to: cursor.to() });
}
return out;
} catch (e) {
console.error('Search error:', e);
return [];
}
}, [editor, visible, debouncedSearchText, regex, caseSensitive, wholeWord]);
const doSearch = useCallback((newIndex = 0) => {
if (!editor) return;
// Clear previous marks
searchMarks.current.forEach((mark) => mark.clear());
searchMarks.current = [];
// Clear previous line highlight
if (searchLineHighlight.current !== null) {
editor.removeLineClass(searchLineHighlight.current, 'wrap', 'cm-search-line-highlight');
searchLineHighlight.current = null;
}
if (!debouncedSearchText) {
setMatchCount(0);
setMatchIndex(0);
searchMatches.current = [];
return;
}
try {
const matches = memoizedMatches;
let matchIndex = matches.length ? Math.max(0, Math.min(newIndex, matches.length - 1)) : 0;
matches.forEach((m, i) => {
const mark = editor.markText(m.from, m.to, {
className: i === matchIndex ? 'cm-search-current' : 'cm-search-match',
clearOnEnter: true
});
searchMarks.current.push(mark);
});
if (matches.length) {
const currentLine = matches[matchIndex].from.line;
editor.addLineClass(currentLine, 'wrap', 'cm-search-line-highlight');
searchLineHighlight.current = currentLine;
editor.scrollIntoView(matches[matchIndex].from, 100);
editor.setSelection(matches[matchIndex].from, matches[matchIndex].to);
} else {
searchLineHighlight.current = null;
}
setMatchCount(matches.length);
setMatchIndex(matchIndex);
searchMatches.current = matches;
} catch (e) {
console.error('Search error:', e);
setMatchCount(0);
setMatchIndex(0);
searchMatches.current = [];
}
}, [debouncedSearchText, regex, caseSensitive, wholeWord, editor, memoizedMatches]);
useEffect(() => {
doSearch(0, debouncedSearchText);
}, [debouncedSearchText, doSearch]);
const handleSearchBarClose = useCallback(() => {
searchMarks.current.forEach((mark) => mark.clear());
searchMarks.current = [];
if (searchLineHighlight.current !== null && editor) {
editor.removeLineClass(searchLineHighlight.current, 'wrap', 'cm-search-line-highlight');
searchLineHighlight.current = null;
}
searchMatches.current = [];
if (onClose) onClose();
// Focus the editor after closing the search bar
if (editor) {
setTimeout(() => editor.focus(), 0);
}
}, [editor, onClose]);
const handleSearchTextChange = (text) => {
setSearchText(text);
setMatchIndex(0);
};
const handleToggleRegex = () => {
setRegex((prev) => !prev);
setMatchIndex(0);
doSearch(0);
};
const handleToggleCase = () => {
setCaseSensitive((prev) => !prev);
setMatchIndex(0);
doSearch(0);
};
const handleToggleWholeWord = () => {
setWholeWord((prev) => !prev);
setMatchIndex(0);
doSearch(0);
};
const handleNext = () => {
if (!searchMatches.current || !searchMatches.current.length) return;
let next = (matchIndex + 1) % searchMatches.current.length;
setMatchIndex(next);
doSearch(next);
};
const handlePrev = () => {
if (!searchMatches.current || !searchMatches.current.length) return;
let prev = (matchIndex - 1 + searchMatches.current.length) % searchMatches.current.length;
setMatchIndex(prev);
doSearch(prev);
};
if (!visible) return null;
return (
<StyledWrapper>
<div className="bruno-search-bar compact">
<input
autoFocus
type="text"
value={searchText}
onChange={(e) => handleSearchTextChange(e.target.value)}
placeholder="Search..."
spellCheck={false}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) handleNext();
if (e.key === 'Enter' && e.shiftKey) handlePrev();
if (e.key === 'Escape') handleSearchBarClose();
}}
/>
<span className="searchbar-result-count">{matchCount > 0 ? `${matchIndex + 1} / ${matchCount}` : '0 results'}</span>
<ToolHint text="Regex search" toolhintId="searchbar-regex-toolhint" place="top">
<button className={`searchbar-icon-btn ${regex ? 'active' : ''}`} onClick={handleToggleRegex}><IconRegex size={16} /></button>
</ToolHint>
<ToolHint text="Case sensitive" toolhintId="searchbar-case-toolhint" place="top">
<button className={`searchbar-icon-btn ${caseSensitive ? 'active' : ''}`} onClick={handleToggleCase}><IconLetterCase size={14} /></button>
</ToolHint>
<ToolHint text="Whole word" toolhintId="searchbar-wholeword-toolhint" place="top">
<button className={`searchbar-icon-btn ${wholeWord ? 'active' : ''}`} onClick={handleToggleWholeWord}><IconLetterW size={14} /></button>
</ToolHint>
<button className="searchbar-icon-btn" title="Previous" onClick={handlePrev}><IconArrowUp size={14} /></button>
<button className="searchbar-icon-btn" title="Next" onClick={handleNext}><IconArrowDown size={14} /></button>
<button className="searchbar-icon-btn" title="Close" onClick={handleSearchBarClose}><IconX size={14} /></button>
</div>
</StyledWrapper>
);
};
export default CodeMirrorSearch;

View File

@@ -95,7 +95,7 @@ const AuthMode = ({ collection }) => {
onModeChange('oauth2');
}}
>
Oauth2
OAuth 2.0
</div>
<div
className="dropdown-item"

View File

@@ -1,4 +1,6 @@
import React from 'react';
import SensitiveFieldWarning from 'components/SensitiveFieldWarning';
import { useDetectSensitiveField } from 'hooks/useDetectSensitiveField';
import get from 'lodash/get';
import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
@@ -12,6 +14,8 @@ const AwsV4Auth = ({ collection }) => {
const { storedTheme } = useTheme();
const awsv4Auth = get(collection, 'root.request.auth.awsv4', {});
const { isSensitive } = useDetectSensitiveField(collection);
const { showWarning, warningMessage } = isSensitive(awsv4Auth?.secretAccessKey);
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
@@ -21,12 +25,12 @@ const AwsV4Auth = ({ collection }) => {
mode: 'awsv4',
collectionUid: collection.uid,
content: {
accessKeyId: accessKeyId,
secretAccessKey: awsv4Auth.secretAccessKey,
sessionToken: awsv4Auth.sessionToken,
service: awsv4Auth.service,
region: awsv4Auth.region,
profileName: awsv4Auth.profileName
accessKeyId: accessKeyId || '',
secretAccessKey: awsv4Auth.secretAccessKey || '',
sessionToken: awsv4Auth.sessionToken || '',
service: awsv4Auth.service || '',
region: awsv4Auth.region || '',
profileName: awsv4Auth.profileName || ''
}
})
);
@@ -38,12 +42,12 @@ const AwsV4Auth = ({ collection }) => {
mode: 'awsv4',
collectionUid: collection.uid,
content: {
accessKeyId: awsv4Auth.accessKeyId,
secretAccessKey: secretAccessKey,
sessionToken: awsv4Auth.sessionToken,
service: awsv4Auth.service,
region: awsv4Auth.region,
profileName: awsv4Auth.profileName
accessKeyId: awsv4Auth.accessKeyId || '',
secretAccessKey: secretAccessKey || '',
sessionToken: awsv4Auth.sessionToken || '',
service: awsv4Auth.service || '',
region: awsv4Auth.region || '',
profileName: awsv4Auth.profileName || ''
}
})
);
@@ -55,12 +59,12 @@ const AwsV4Auth = ({ collection }) => {
mode: 'awsv4',
collectionUid: collection.uid,
content: {
accessKeyId: awsv4Auth.accessKeyId,
secretAccessKey: awsv4Auth.secretAccessKey,
sessionToken: sessionToken,
service: awsv4Auth.service,
region: awsv4Auth.region,
profileName: awsv4Auth.profileName
accessKeyId: awsv4Auth.accessKeyId || '',
secretAccessKey: awsv4Auth.secretAccessKey || '',
sessionToken: sessionToken || '',
service: awsv4Auth.service || '',
region: awsv4Auth.region || '',
profileName: awsv4Auth.profileName || ''
}
})
);
@@ -72,12 +76,12 @@ const AwsV4Auth = ({ collection }) => {
mode: 'awsv4',
collectionUid: collection.uid,
content: {
accessKeyId: awsv4Auth.accessKeyId,
secretAccessKey: awsv4Auth.secretAccessKey,
sessionToken: awsv4Auth.sessionToken,
service: service,
region: awsv4Auth.region,
profileName: awsv4Auth.profileName
accessKeyId: awsv4Auth.accessKeyId || '',
secretAccessKey: awsv4Auth.secretAccessKey || '',
sessionToken: awsv4Auth.sessionToken || '',
service: service || '',
region: awsv4Auth.region || '',
profileName: awsv4Auth.profileName || ''
}
})
);
@@ -89,12 +93,12 @@ const AwsV4Auth = ({ collection }) => {
mode: 'awsv4',
collectionUid: collection.uid,
content: {
accessKeyId: awsv4Auth.accessKeyId,
secretAccessKey: awsv4Auth.secretAccessKey,
sessionToken: awsv4Auth.sessionToken,
service: awsv4Auth.service,
region: region,
profileName: awsv4Auth.profileName
accessKeyId: awsv4Auth.accessKeyId || '',
secretAccessKey: awsv4Auth.secretAccessKey || '',
sessionToken: awsv4Auth.sessionToken || '',
service: awsv4Auth.service || '',
region: region || '',
profileName: awsv4Auth.profileName || ''
}
})
);
@@ -106,12 +110,12 @@ const AwsV4Auth = ({ collection }) => {
mode: 'awsv4',
collectionUid: collection.uid,
content: {
accessKeyId: awsv4Auth.accessKeyId,
secretAccessKey: awsv4Auth.secretAccessKey,
sessionToken: awsv4Auth.sessionToken,
service: awsv4Auth.service,
region: awsv4Auth.region,
profileName: profileName
accessKeyId: awsv4Auth.accessKeyId || '',
secretAccessKey: awsv4Auth.secretAccessKey || '',
sessionToken: awsv4Auth.sessionToken || '',
service: awsv4Auth.service || '',
region: awsv4Auth.region || '',
profileName: profileName || ''
}
})
);
@@ -131,7 +135,7 @@ const AwsV4Auth = ({ collection }) => {
</div>
<label className="block font-medium mb-2">Secret Access Key</label>
<div className="single-line-editor-wrapper mb-2">
<div className="single-line-editor-wrapper mb-2 flex items-center">
<SingleLineEditor
value={awsv4Auth.secretAccessKey || ''}
theme={storedTheme}
@@ -140,6 +144,7 @@ const AwsV4Auth = ({ collection }) => {
collection={collection}
isSecret={true}
/>
{showWarning && <SensitiveFieldWarning fieldName="awsv4-secret-access-key" warningMessage={warningMessage} />}
</div>
<label className="block font-medium mb-2">Session Token</label>

View File

@@ -1,4 +1,6 @@
import React from 'react';
import SensitiveFieldWarning from 'components/SensitiveFieldWarning';
import { useDetectSensitiveField } from 'hooks/useDetectSensitiveField';
import get from 'lodash/get';
import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
@@ -12,6 +14,8 @@ const BasicAuth = ({ collection }) => {
const { storedTheme } = useTheme();
const basicAuth = get(collection, 'root.request.auth.basic', {});
const { isSensitive } = useDetectSensitiveField(collection);
const { showWarning, warningMessage } = isSensitive(basicAuth?.password);
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
@@ -21,8 +25,8 @@ const BasicAuth = ({ collection }) => {
mode: 'basic',
collectionUid: collection.uid,
content: {
username: username,
password: basicAuth.password
username: username || '',
password: basicAuth.password || ''
}
})
);
@@ -34,8 +38,8 @@ const BasicAuth = ({ collection }) => {
mode: 'basic',
collectionUid: collection.uid,
content: {
username: basicAuth.username,
password: password
username: basicAuth.username || '',
password: password || ''
}
})
);
@@ -55,7 +59,7 @@ const BasicAuth = ({ collection }) => {
</div>
<label className="block font-medium mb-2">Password</label>
<div className="single-line-editor-wrapper">
<div className="single-line-editor-wrapper flex items-center">
<SingleLineEditor
value={basicAuth.password || ''}
theme={storedTheme}
@@ -64,6 +68,7 @@ const BasicAuth = ({ collection }) => {
collection={collection}
isSecret={true}
/>
{showWarning && <SensitiveFieldWarning fieldName="basic-password" warningMessage={warningMessage} />}
</div>
</StyledWrapper>
);

View File

@@ -1,4 +1,6 @@
import React from 'react';
import SensitiveFieldWarning from 'components/SensitiveFieldWarning';
import { useDetectSensitiveField } from 'hooks/useDetectSensitiveField';
import get from 'lodash/get';
import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
@@ -12,6 +14,8 @@ const BearerAuth = ({ collection }) => {
const { storedTheme } = useTheme();
const bearerToken = get(collection, 'root.request.auth.bearer.token', '');
const { isSensitive } = useDetectSensitiveField(collection);
const { showWarning, warningMessage } = isSensitive(bearerToken);
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
@@ -30,7 +34,7 @@ const BearerAuth = ({ collection }) => {
return (
<StyledWrapper className="mt-2 w-full">
<label className="block font-medium mb-2">Token</label>
<div className="single-line-editor-wrapper">
<div className="single-line-editor-wrapper flex items-center">
<SingleLineEditor
value={bearerToken}
theme={storedTheme}
@@ -39,6 +43,7 @@ const BearerAuth = ({ collection }) => {
collection={collection}
isSecret={true}
/>
{showWarning && <SensitiveFieldWarning fieldName="bearer-token" warningMessage={warningMessage} />}
</div>
</StyledWrapper>
);

View File

@@ -1,4 +1,6 @@
import React from 'react';
import SensitiveFieldWarning from 'components/SensitiveFieldWarning';
import { useDetectSensitiveField } from 'hooks/useDetectSensitiveField';
import get from 'lodash/get';
import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
@@ -12,6 +14,8 @@ const DigestAuth = ({ collection }) => {
const { storedTheme } = useTheme();
const digestAuth = get(collection, 'root.request.auth.digest', {});
const { isSensitive } = useDetectSensitiveField(collection);
const { showWarning, warningMessage } = isSensitive(digestAuth?.password);
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
@@ -21,8 +25,8 @@ const DigestAuth = ({ collection }) => {
mode: 'digest',
collectionUid: collection.uid,
content: {
username: username,
password: digestAuth.password
username: username || '',
password: digestAuth.password || ''
}
})
);
@@ -34,8 +38,8 @@ const DigestAuth = ({ collection }) => {
mode: 'digest',
collectionUid: collection.uid,
content: {
username: digestAuth.username,
password: password
username: digestAuth.username || '',
password: password || ''
}
})
);
@@ -55,7 +59,7 @@ const DigestAuth = ({ collection }) => {
</div>
<label className="block font-medium mb-2">Password</label>
<div className="single-line-editor-wrapper">
<div className="single-line-editor-wrapper flex items-center">
<SingleLineEditor
value={digestAuth.password || ''}
theme={storedTheme}
@@ -64,6 +68,7 @@ const DigestAuth = ({ collection }) => {
collection={collection}
isSecret={true}
/>
{showWarning && <SensitiveFieldWarning fieldName="digest-password" warningMessage={warningMessage} />}
</div>
</StyledWrapper>
);

View File

@@ -1,4 +1,6 @@
import React from 'react';
import SensitiveFieldWarning from 'components/SensitiveFieldWarning';
import { useDetectSensitiveField } from 'hooks/useDetectSensitiveField';
import get from 'lodash/get';
import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
@@ -18,6 +20,8 @@ const NTLMAuth = ({ collection }) => {
const { storedTheme } = useTheme();
const ntlmAuth = get(collection, 'root.request.auth.ntlm', {});
const { isSensitive } = useDetectSensitiveField(collection);
const { showWarning, warningMessage } = isSensitive(ntlmAuth?.password);
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
@@ -28,9 +32,9 @@ const NTLMAuth = ({ collection }) => {
mode: 'ntlm',
collectionUid: collection.uid,
content: {
username: username,
password: ntlmAuth.password,
domain: ntlmAuth.domain
username: username || '',
password: ntlmAuth.password || '',
domain: ntlmAuth.domain || ''
}
})
@@ -43,9 +47,9 @@ const NTLMAuth = ({ collection }) => {
mode: 'ntlm',
collectionUid: collection.uid,
content: {
username: ntlmAuth.username,
password: password,
domain: ntlmAuth.domain
username: ntlmAuth.username || '',
password: password || '',
domain: ntlmAuth.domain || ''
}
})
);
@@ -57,9 +61,9 @@ const NTLMAuth = ({ collection }) => {
mode: 'ntlm',
collectionUid: collection.uid,
content: {
username: ntlmAuth.username,
password: ntlmAuth.password,
domain: domain
username: ntlmAuth.username || '',
password: ntlmAuth.password || '',
domain: domain || ''
}
})
);
@@ -82,7 +86,7 @@ const NTLMAuth = ({ collection }) => {
</div>
<label className="block font-medium mb-2">Password</label>
<div className="single-line-editor-wrapper">
<div className="single-line-editor-wrapper flex items-center">
<SingleLineEditor
value={ntlmAuth.password || ''}
theme={storedTheme}
@@ -91,6 +95,7 @@ const NTLMAuth = ({ collection }) => {
collection={collection}
isSecret={true}
/>
{showWarning && <SensitiveFieldWarning fieldName="ntlm-password" warningMessage={warningMessage} />}
</div>
<label className="block font-medium mb-2">Domain</label>

View File

@@ -1,120 +0,0 @@
import React from 'react';
import get from 'lodash/get';
import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
import SingleLineEditor from 'components/SingleLineEditor';
import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions';
import StyledWrapper from './StyledWrapper';
import { inputsConfig } from './inputsConfig';
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index';
import { clearOauth2Cache } from 'utils/network/index';
import toast from 'react-hot-toast';
const OAuth2AuthorizationCode = ({ collection }) => {
const dispatch = useDispatch();
const { storedTheme } = useTheme();
const oAuth = get(collection, 'root.request.auth.oauth2', {});
const handleRun = async () => {
dispatch(sendCollectionOauth2Request(collection.uid));
};
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
const { callbackUrl, authorizationUrl, accessTokenUrl, clientId, clientSecret, scope, state, pkce } = oAuth;
const handleChange = (key, value) => {
dispatch(
updateCollectionAuth({
mode: 'oauth2',
collectionUid: collection.uid,
content: {
grantType: 'authorization_code',
callbackUrl,
authorizationUrl,
accessTokenUrl,
clientId,
clientSecret,
scope,
state,
pkce,
[key]: value
}
})
);
};
const handlePKCEToggle = (e) => {
dispatch(
updateCollectionAuth({
mode: 'oauth2',
collectionUid: collection.uid,
content: {
grantType: 'authorization_code',
callbackUrl,
authorizationUrl,
accessTokenUrl,
clientId,
clientSecret,
scope,
state,
pkce: !Boolean(oAuth?.['pkce'])
}
})
);
};
const handleClearCache = (e) => {
clearOauth2Cache(collection?.uid)
.then(() => {
toast.success('cleared cache successfully');
})
.catch((err) => {
toast.error(err.message);
});
};
return (
<StyledWrapper className="mt-2 flex w-full gap-4 flex-col">
{inputsConfig.map((input) => {
const { key, label, isSecret } = input;
return (
<div className="flex flex-col w-full gap-1" key={`input-${key}`}>
<label className="block font-medium">{label}</label>
<div className="single-line-editor-wrapper">
<SingleLineEditor
value={oAuth[key] || ''}
theme={storedTheme}
onSave={handleSave}
onChange={(val) => handleChange(key, val)}
onRun={handleRun}
collection={collection}
isSecret={isSecret}
/>
</div>
</div>
);
})}
<div className="flex flex-row w-full gap-4" key="pkce">
<label className="block font-medium">Use PKCE</label>
<input
className="cursor-pointer"
type="checkbox"
checked={Boolean(oAuth?.['pkce'])}
onChange={handlePKCEToggle}
/>
</div>
<div className="flex flex-row gap-4">
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
Get Access Token
</button>
<button onClick={handleClearCache} className="submit btn btn-sm btn-secondary w-fit">
Clear Cache
</button>
</div>
</StyledWrapper>
);
};
export default OAuth2AuthorizationCode;

View File

@@ -1,16 +0,0 @@
import styled from 'styled-components';
const Wrapper = styled.div`
label {
font-size: 0.8125rem;
}
.single-line-editor-wrapper {
max-width: 400px;
padding: 0.15rem 0.4rem;
border-radius: 3px;
border: solid 1px ${(props) => props.theme.input.border};
background-color: ${(props) => props.theme.input.bg};
}
`;
export default Wrapper;

View File

@@ -1,70 +0,0 @@
import React from 'react';
import get from 'lodash/get';
import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
import SingleLineEditor from 'components/SingleLineEditor';
import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions';
import StyledWrapper from './StyledWrapper';
import { inputsConfig } from './inputsConfig';
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index';
const OAuth2ClientCredentials = ({ collection }) => {
const dispatch = useDispatch();
const { storedTheme } = useTheme();
const oAuth = get(collection, 'root.request.auth.oauth2', {});
const handleRun = async () => {
dispatch(sendCollectionOauth2Request(collection.uid));
};
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
const { accessTokenUrl, clientId, clientSecret, scope } = oAuth;
const handleChange = (key, value) => {
dispatch(
updateCollectionAuth({
mode: 'oauth2',
collectionUid: collection.uid,
content: {
grantType: 'client_credentials',
accessTokenUrl,
clientId,
clientSecret,
scope,
[key]: value
}
})
);
};
return (
<StyledWrapper className="mt-2 flex w-full gap-4 flex-col">
{inputsConfig.map((input) => {
const { key, label, isSecret } = input;
return (
<div className="flex flex-col w-full gap-1" key={`input-${key}`}>
<label className="block font-medium">{label}</label>
<div className="single-line-editor-wrapper">
<SingleLineEditor
value={oAuth[key] || ''}
theme={storedTheme}
onSave={handleSave}
onChange={(val) => handleChange(key, val)}
onRun={handleRun}
collection={collection}
isSecret={isSecret}
/>
</div>
</div>
);
})}
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
Get Access Token
</button>
</StyledWrapper>
);
};
export default OAuth2ClientCredentials;

View File

@@ -1,21 +0,0 @@
const inputsConfig = [
{
key: 'accessTokenUrl',
label: 'Access Token URL'
},
{
key: 'clientId',
label: 'Client ID'
},
{
key: 'clientSecret',
label: 'Client Secret',
isSecret: true
},
{
key: 'scope',
label: 'Scope'
}
];
export { inputsConfig };

View File

@@ -1,98 +0,0 @@
import React, { useRef, forwardRef } from 'react';
import get from 'lodash/get';
import Dropdown from 'components/Dropdown';
import { useDispatch } from 'react-redux';
import StyledWrapper from './StyledWrapper';
import { IconCaretDown } from '@tabler/icons';
import { updateAuth } from 'providers/ReduxStore/slices/collections';
import { humanizeGrantType } from 'utils/collections';
import { useEffect } from 'react';
import { updateCollectionAuth, updateCollectionAuthMode } from 'providers/ReduxStore/slices/collections/index';
const GrantTypeSelector = ({ collection }) => {
const dispatch = useDispatch();
const dropdownTippyRef = useRef();
const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
const oAuth = get(collection, 'root.request.auth.oauth2', {});
const Icon = forwardRef((props, ref) => {
return (
<div ref={ref} className="flex items-center justify-end grant-type-label select-none">
{humanizeGrantType(oAuth?.grantType)} <IconCaretDown className="caret ml-1 mr-1" size={14} strokeWidth={2} />
</div>
);
});
const onGrantTypeChange = (grantType) => {
dispatch(
updateCollectionAuth({
mode: 'oauth2',
collectionUid: collection.uid,
content: {
grantType
}
})
);
};
useEffect(() => {
// initialize redux state with a default oauth2 grant type
// authorization_code - default option
!oAuth?.grantType &&
dispatch(
updateCollectionAuthMode({
mode: 'oauth2',
collectionUid: collection.uid
})
);
!oAuth?.grantType &&
dispatch(
updateCollectionAuth({
mode: 'oauth2',
collectionUid: collection.uid,
content: {
grantType: 'authorization_code'
}
})
);
}, [oAuth]);
return (
<StyledWrapper>
<label className="block font-medium mb-2">Grant Type</label>
<div className="inline-flex items-center cursor-pointer grant-type-mode-selector w-fit">
<Dropdown onCreate={onDropdownCreate} icon={<Icon />} placement="bottom-end">
<div
className="dropdown-item"
onClick={() => {
dropdownTippyRef.current.hide();
onGrantTypeChange('password');
}}
>
Password Credentials
</div>
<div
className="dropdown-item"
onClick={() => {
dropdownTippyRef.current.hide();
onGrantTypeChange('authorization_code');
}}
>
Authorization Code
</div>
<div
className="dropdown-item"
onClick={() => {
dropdownTippyRef.current.hide();
onGrantTypeChange('client_credentials');
}}
>
Client Credentials
</div>
</Dropdown>
</div>
</StyledWrapper>
);
};
export default GrantTypeSelector;

View File

@@ -1,16 +0,0 @@
import styled from 'styled-components';
const Wrapper = styled.div`
label {
font-size: 0.8125rem;
}
.single-line-editor-wrapper {
max-width: 400px;
padding: 0.15rem 0.4rem;
border-radius: 3px;
border: solid 1px ${(props) => props.theme.input.border};
background-color: ${(props) => props.theme.input.bg};
}
`;
export default Wrapper;

View File

@@ -1,72 +0,0 @@
import React from 'react';
import get from 'lodash/get';
import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
import SingleLineEditor from 'components/SingleLineEditor';
import { saveCollectionRoot, sendCollectionOauth2Request } from 'providers/ReduxStore/slices/collections/actions';
import StyledWrapper from './StyledWrapper';
import { inputsConfig } from './inputsConfig';
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index';
const OAuth2AuthorizationCode = ({ item, collection }) => {
const dispatch = useDispatch();
const { storedTheme } = useTheme();
const oAuth = get(collection, 'root.request.auth.oauth2', {});
const handleRun = async () => {
dispatch(sendCollectionOauth2Request(collection.uid));
};
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
const { accessTokenUrl, username, password, clientId, clientSecret, scope } = oAuth;
const handleChange = (key, value) => {
dispatch(
updateCollectionAuth({
mode: 'oauth2',
collectionUid: collection.uid,
content: {
grantType: 'password',
accessTokenUrl,
username,
password,
clientId,
clientSecret,
scope,
[key]: value
}
})
);
};
return (
<StyledWrapper className="mt-2 flex w-full gap-4 flex-col">
{inputsConfig.map((input) => {
const { key, label, isSecret } = input;
return (
<div className="flex flex-col w-full gap-1" key={`input-${key}`}>
<label className="block font-medium">{label}</label>
<div className="single-line-editor-wrapper">
<SingleLineEditor
value={oAuth[key] || ''}
theme={storedTheme}
onSave={handleSave}
onChange={(val) => handleChange(key, val)}
onRun={handleRun}
collection={collection}
isSecret={isSecret}
/>
</div>
</div>
);
})}
<button onClick={handleRun} className="submit btn btn-sm btn-secondary w-fit">
Get Access Token
</button>
</StyledWrapper>
);
};
export default OAuth2AuthorizationCode;

View File

@@ -1,29 +0,0 @@
const inputsConfig = [
{
key: 'accessTokenUrl',
label: 'Access Token URL'
},
{
key: 'username',
label: 'Username'
},
{
key: 'password',
label: 'Password'
},
{
key: 'clientId',
label: 'Client ID'
},
{
key: 'clientSecret',
label: 'Client Secret',
isSecret: true
},
{
key: 'scope',
label: 'Scope'
}
];
export { inputsConfig };

View File

@@ -1,21 +1,37 @@
import React from 'react';
import get from 'lodash/get';
import StyledWrapper from './StyledWrapper';
import GrantTypeSelector from './GrantTypeSelector/index';
import OAuth2PasswordCredentials from './PasswordCredentials/index';
import OAuth2AuthorizationCode from './AuthorizationCode/index';
import OAuth2ClientCredentials from './ClientCredentials/index';
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
import OAuth2AuthorizationCode from 'components/RequestPane/Auth/OAuth2/AuthorizationCode/index';
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections/index';
import { useDispatch } from 'react-redux';
import OAuth2PasswordCredentials from 'components/RequestPane/Auth/OAuth2/PasswordCredentials/index';
import OAuth2ClientCredentials from 'components/RequestPane/Auth/OAuth2/ClientCredentials/index';
import OAuth2Implicit from 'components/RequestPane/Auth/OAuth2/Implicit/index';
import GrantTypeSelector from 'components/RequestPane/Auth/OAuth2/GrantTypeSelector/index';
const GrantTypeComponentMap = ({collection }) => {
const dispatch = useDispatch();
const save = () => {
dispatch(saveCollectionRoot(collection.uid));
};
let request = collection.draft ? get(collection, 'draft.request', {}) : get(collection, 'root.request', {});
const grantType = get(request, 'auth.oauth2.grantType', {});
const grantTypeComponentMap = (grantType, collection) => {
switch (grantType) {
case 'password':
return <OAuth2PasswordCredentials collection={collection} />;
return <OAuth2PasswordCredentials save={save} request={request} updateAuth={updateCollectionAuth} collection={collection} />;
break;
case 'authorization_code':
return <OAuth2AuthorizationCode collection={collection} />;
return <OAuth2AuthorizationCode save={save} request={request} updateAuth={updateCollectionAuth} collection={collection} />;
break;
case 'client_credentials':
return <OAuth2ClientCredentials collection={collection} />;
return <OAuth2ClientCredentials save={save} request={request} updateAuth={updateCollectionAuth} collection={collection} />;
break;
case 'implicit':
return <OAuth2Implicit save={save} request={request} updateAuth={updateCollectionAuth} collection={collection} />;
break;
default:
return <div>TBD</div>;
@@ -24,12 +40,12 @@ const grantTypeComponentMap = (grantType, collection) => {
};
const OAuth2 = ({ collection }) => {
const oAuth = get(collection, 'root.request.auth.oauth2', {});
let request = collection.draft ? get(collection, 'draft.request', {}) : get(collection, 'root.request', {});
return (
<StyledWrapper className="mt-2 w-full">
<GrantTypeSelector collection={collection} />
{grantTypeComponentMap(oAuth?.grantType, collection)}
<GrantTypeSelector request={request} updateAuth={updateCollectionAuth} collection={collection} />
<GrantTypeComponentMap collection={collection} />
</StyledWrapper>
);
};

View File

@@ -1,4 +1,6 @@
import React from 'react';
import SensitiveFieldWarning from 'components/SensitiveFieldWarning';
import { useDetectSensitiveField } from 'hooks/useDetectSensitiveField';
import get from 'lodash/get';
import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
@@ -12,6 +14,8 @@ const WsseAuth = ({ collection }) => {
const { storedTheme } = useTheme();
const wsseAuth = get(collection, 'root.request.auth.wsse', {});
const { isSensitive } = useDetectSensitiveField(collection);
const { showWarning, warningMessage } = isSensitive(wsseAuth?.password);
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
@@ -21,8 +25,8 @@ const WsseAuth = ({ collection }) => {
mode: 'wsse',
collectionUid: collection.uid,
content: {
username,
password: wsseAuth.password
username: username || '',
password: wsseAuth.password || ''
}
})
);
@@ -34,8 +38,8 @@ const WsseAuth = ({ collection }) => {
mode: 'wsse',
collectionUid: collection.uid,
content: {
username: wsseAuth.username,
password
username: wsseAuth.username || '',
password: password || ''
}
})
);
@@ -55,14 +59,16 @@ const WsseAuth = ({ collection }) => {
</div>
<label className="block font-medium mb-2">Password</label>
<div className="single-line-editor-wrapper">
<div className="single-line-editor-wrapper flex items-center">
<SingleLineEditor
value={wsseAuth.password || ''}
theme={storedTheme}
onSave={handleSave}
onChange={(val) => handlePasswordChange(val)}
collection={collection}
isSecret={true}
/>
{showWarning && <SensitiveFieldWarning fieldName="wsse-password" warningMessage={warningMessage} />}
</div>
</StyledWrapper>
);

View File

@@ -38,6 +38,48 @@ const StyledWrapper = styled.div`
outline: none !important;
}
}
.protocol-placeholder {
height: 100%;
position: relative;
display: inline-block;
width: 60px;
overflow: hidden;
}
.protocol-https,
.protocol-grpcs {
position: absolute;
right: 8px;
top: 0;
bottom: 0;
transition: transform 0.3s ease-in-out;
display: flex;
align-items: center;
justify-content: center;
}
.protocol-https {
animation: slideUpDown 6s infinite;
transform: translateY(0);
}
.protocol-grpcs {
animation: slideUpDown 6s infinite 3s;
transform: translateY(100%);
}
@keyframes slideUpDown {
0%, 45% {
transform: translateY(0);
}
50%, 95% {
transform: translateY(100%);
}
100% {
transform: translateY(0);
}
}
`;
export default StyledWrapper;

View File

@@ -25,7 +25,10 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
passphrase: ''
},
validationSchema: Yup.object({
domain: Yup.string().required(),
domain: Yup.string()
.required()
.trim()
.test('not-empty-after-trim', 'Domain is required', value => value && value.trim().length > 0),
type: Yup.string().required().oneOf(['cert', 'pfx']),
certFilePath: Yup.string().when('type', {
is: (type) => type == 'cert',
@@ -45,7 +48,7 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
let relevantValues = {};
if (values.type === 'cert') {
relevantValues = {
domain: values.domain,
domain: values.domain?.trim(),
type: values.type,
certFilePath: values.certFilePath,
keyFilePath: values.keyFilePath,
@@ -53,7 +56,7 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
};
} else {
relevantValues = {
domain: values.domain,
domain: values.domain?.trim(),
type: values.type,
pfxFilePath: values.pfxFilePath,
passphrase: values.passphrase
@@ -127,15 +130,23 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
<label className="settings-label" htmlFor="domain">
Domain
</label>
<input
id="domain"
type="text"
name="domain"
placeholder="*.example.org"
className="block textbox non-passphrase-input"
onChange={formik.handleChange}
value={formik.values.domain || ''}
/>
<div className="relative flex items-center">
<div className="absolute left-0 pl-2 text-gray-400 pointer-events-none flex items-center h-full">
<span className="protocol-placeholder">
<span className="protocol-https">https://</span>
<span className="protocol-grpcs">grpcs://</span>
</span>
</div>
<input
id="domain"
type="text"
name="domain"
placeholder="example.org"
className="block textbox non-passphrase-input !pl-[60px]"
onChange={formik.handleChange}
value={formik.values.domain || ''}
/>
</div>
{formik.touched.domain && formik.errors.domain ? (
<div className="ml-1 text-red-500">{formik.errors.domain}</div>
) : null}

View File

@@ -46,7 +46,7 @@ const Docs = ({ collection }) => {
}
return (
<StyledWrapper className="mt-1 h-full w-full relative flex flex-col">
<StyledWrapper className="h-full w-full relative flex flex-col">
<div className='flex flex-row w-full justify-between items-center mb-4'>
<div className='text-lg font-medium flex items-center gap-2'>
<IconFileText size={20} strokeWidth={1.5} />
@@ -119,6 +119,6 @@ This documentation supports Markdown formatting! You can use:
- **Bold** and *italic* text
- \`code blocks\` and syntax highlighting
- Tables and lists
- [Links](https://example.com)
- [Links](https://usebruno.com)
- And more!
`;

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import get from 'lodash/get';
import cloneDeep from 'lodash/cloneDeep';
import { IconTrash } from '@tabler/icons';
@@ -7,19 +7,30 @@ import { useTheme } from 'providers/Theme';
import {
addCollectionHeader,
updateCollectionHeader,
deleteCollectionHeader
deleteCollectionHeader,
setCollectionHeaders
} from 'providers/ReduxStore/slices/collections';
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
import SingleLineEditor from 'components/SingleLineEditor';
import StyledWrapper from './StyledWrapper';
import { headers as StandardHTTPHeaders } from 'know-your-http-well';
import { MimeTypes } from 'utils/codemirror/autocompleteConstants';
import BulkEditor from 'components/BulkEditor/index';
const headerAutoCompleteList = StandardHTTPHeaders.map((e) => e.header);
const Headers = ({ collection }) => {
const dispatch = useDispatch();
const { storedTheme } = useTheme();
const headers = get(collection, 'root.request.headers', []);
const [isBulkEditMode, setIsBulkEditMode] = useState(false);
const toggleBulkEditMode = () => {
setIsBulkEditMode(!isBulkEditMode);
};
const handleBulkHeadersChange = (newHeaders) => {
dispatch(setCollectionHeaders({ collectionUid: collection.uid, headers: newHeaders }));
};
const addHeader = () => {
dispatch(
@@ -63,6 +74,22 @@ const Headers = ({ collection }) => {
);
};
if (isBulkEditMode) {
return (
<StyledWrapper className="h-full w-full">
<div className="text-xs mb-4 text-muted">
Add request headers that will be sent with every request in this collection.
</div>
<BulkEditor
params={headers}
onChange={handleBulkHeadersChange}
onToggle={toggleBulkEditMode}
onSave={handleSave}
/>
</StyledWrapper>
);
}
return (
<StyledWrapper className="h-full w-full">
<div className="text-xs mb-4 text-muted">
@@ -141,9 +168,14 @@ const Headers = ({ collection }) => {
: null}
</tbody>
</table>
<button className="btn-add-header text-link pr-2 py-3 mt-2 select-none" onClick={addHeader}>
+ Add Header
</button>
<div className="flex justify-between mt-2">
<button className="btn-add-header text-link pr-2 py-3 select-none" onClick={addHeader}>
+ Add Header
</button>
<button className="text-link select-none" onClick={toggleBulkEditMode}>
Bulk Edit
</button>
</div>
<div className="mt-6">
<button type="submit" className="submit btn btn-sm btn-secondary" onClick={handleSave}>

View File

@@ -53,7 +53,7 @@ const Info = ({ collection }) => {
</div>
<div className="ml-4">
<div className="font-semibold text-sm">Requests</div>
<div className="mt-1 text-sm text-muted font-mono">
<div className="mt-1 text-sm text-muted">
{
isCollectionLoading? `${totalItems - itemsLoadingCount} out of ${totalItems} requests in the collection loaded` : `${totalRequestsInCollection} request${totalRequestsInCollection !== 1 ? 's' : ''} in collection`
}
@@ -72,7 +72,7 @@ const Info = ({ collection }) => {
</div>
</div>
</div>
{showShareCollectionModal && <ShareCollection collection={collection} onClose={handleToggleShowShareCollectionModal(false)} />}
{showShareCollectionModal && <ShareCollection collectionUid={collection.uid} onClose={handleToggleShowShareCollectionModal(false)} />}
</div>
</div>
</div>

View File

@@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React from 'react';
import { useFormik } from 'formik';
import { useDispatch } from 'react-redux';
import StyledWrapper from './StyledWrapper';
@@ -62,6 +62,19 @@ const PresetsSettings = ({ collection }) => {
<label htmlFor="graphql" className="ml-1 cursor-pointer select-none">
GraphQL
</label>
<input
id="grpc"
className="ml-4 cursor-pointer"
type="radio"
name="requestType"
onChange={formik.handleChange}
value="grpc"
checked={formik.values.requestType === 'grpc'}
/>
<label htmlFor="grpc" className="ml-1 cursor-pointer select-none">
gRPC
</label>
</div>
</div>
<div className="mb-3 flex items-center">
@@ -74,7 +87,7 @@ const PresetsSettings = ({ collection }) => {
id="request-url"
type="text"
name="requestUrl"
placeholder='Request URL'
placeholder="Request URL"
className="block textbox"
autoComplete="off"
autoCorrect="off"
@@ -87,6 +100,7 @@ const PresetsSettings = ({ collection }) => {
</div>
</div>
</div>
<div className="mt-6">
<button type="submit" className="submit btn btn-sm btn-secondary">
Save

View File

@@ -0,0 +1,13 @@
import styled from 'styled-components';
const StyledWrapper = styled.div`
.available-certificates {
background-color: ${(props) => props.theme.requestTabPanel.url.bg};
button.remove-certificate {
color: ${(props) => props.theme.colors.text.danger};
}
}
`;
export default StyledWrapper;

View File

@@ -0,0 +1,336 @@
import React, { useRef } from 'react';
import StyledWrapper from './StyledWrapper';
import {
IconTrash,
IconFile,
IconFileImport,
IconAlertCircle,
IconFolder
} from '@tabler/icons';
import { getBasename } from 'utils/common/path';
import { Tooltip } from 'react-tooltip';
import useProtoFileManagement from '../../../hooks/useProtoFileManagement';
const ProtobufSettings = ({ collection }) => {
const {
protoFiles,
importPaths,
addProtoFileToCollection,
addImportPathToCollection,
toggleImportPath,
browseForProtoFile,
browseForImportDirectory,
removeProtoFileFromCollection,
removeImportPathFromCollection,
replaceImportPathInCollection,
replaceProtoFileInCollection
} = useProtoFileManagement(collection);
const fileInputRef = useRef(null);
// Get file path using the ipcRenderer
const getProtoFile = async (event) => {
const files = event?.files;
if (files && files.length > 0) {
for (let i = 0; i < files.length; i++) {
const filePath = window?.ipcRenderer?.getFilePath(files[i]);
if (filePath) {
await addProtoFileToCollection(filePath);
}
}
// Reset the file input
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
}
};
const handleRemoveProtoFile = async (index) => {
await removeProtoFileFromCollection(index);
};
const handleBrowseClick = () => {
if (fileInputRef.current) {
fileInputRef.current.click();
}
};
const handleReplaceProtoFile = async (index) => {
const result = await browseForProtoFile();
if (result.success) {
await replaceProtoFileInCollection(index, result.filePath);
}
};
const handleReplaceImportPath = async (index) => {
const result = await browseForImportDirectory();
if (result.success) {
await replaceImportPathInCollection(index, result.directoryPath);
}
};
const handleFileInputChange = (e) => {
getProtoFile(e.target);
};
const getImportPath = async () => {
const result = await browseForImportDirectory();
if (result.success) {
await addImportPathToCollection(result.directoryPath);
}
};
const handleRemoveImportPath = async (index) => {
await removeImportPathFromCollection(index);
};
const handleToggleImportPath = async (index) => {
await toggleImportPath(index);
};
const handleBrowseImportPathClick = () => {
getImportPath();
};
return (
<StyledWrapper className="h-full w-full">
{/* Hidden file input for file selection */}
<input
type="file"
ref={fileInputRef}
style={{ display: 'none' }}
accept=".proto"
multiple
onChange={handleFileInputChange}
/>
{/* Proto Files Section */}
<div className="mb-6" data-testid="protobuf-proto-files-section">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center">
<label className="font-semibold text-sm flex items-center" htmlFor="protoFiles">
Proto Files (
{protoFiles.length}
)
<span id="proto-files-tooltip" className="ml-2">
<IconAlertCircle size={16} className="text-gray-500 cursor-pointer" />
</span>
<Tooltip
anchorId="proto-files-tooltip"
className="tooltip-mod font-normal"
html="Keep your proto files within the collection folder or the corresponding git repository to ensure paths remain valid when sharing the collection."
/>
</label>
</div>
</div>
<div>
{protoFiles.some((file) => !file.exists) && (
<div className="text-xs text-red-600 dark:text-red-400 mb-2 flex items-center p-2 rounded" data-testid="protobuf-invalid-files-message">
<IconAlertCircle size={14} className="mr-1" />
Some proto files cannot be found. Use the replace option to update their locations.
</div>
)}
<table className="w-full border-collapse" data-testid="protobuf-proto-files-table">
<thead>
<tr>
<th className="text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider border border-gray-200 dark:border-gray-700 px-3 py-2">
File
</th>
<th className="text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider border border-gray-200 dark:border-gray-700 px-3 py-2">
Path
</th>
<th className="text-right text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider border border-gray-200 dark:border-gray-700 px-3 py-2">
Actions
</th>
</tr>
</thead>
<tbody>
{protoFiles.length === 0 ? (
<tr>
<td colSpan="3" className="border border-gray-200 dark:border-gray-700 px-3 py-8 text-center">
<div className="flex flex-col items-center">
<IconFile size={24} className="text-gray-400 mb-2" />
<span className="text-sm text-gray-500 dark:text-gray-400">No proto files added</span>
</div>
</td>
</tr>
) : (
protoFiles.map((file, index) => {
const isValid = file.exists;
return (
<tr key={index}>
<td className="border border-gray-200 dark:border-gray-700 px-3 py-2">
<div className="flex items-center">
<IconFile size={16} className="text-gray-500 dark:text-gray-400 mr-2" />
<span className="text-sm font-medium text-gray-900 dark:text-gray-100">
{getBasename(collection.pathname, file.path)}
</span>
{!isValid && <IconAlertCircle size={12} className="text-red-600 dark:text-red-400 ml-2" />}
</div>
</td>
<td className="border border-gray-200 dark:border-gray-700 px-3 py-2">
<div className="text-xs text-gray-600 dark:text-gray-400 font-mono">
{file.path}
</div>
</td>
<td className="border border-gray-200 dark:border-gray-700 px-3 py-2 text-right">
<div className="flex items-center justify-end space-x-1">
{!isValid && (
<button
type="button"
onClick={() => handleReplaceProtoFile(index)}
className="text-red-600 hover:text-red-900 dark:text-red-400 dark:hover:text-red-300 p-1 rounded"
title="Replace file"
>
<IconFileImport size={14} />
</button>
)}
<button
type="button"
onClick={() => handleRemoveProtoFile(index)}
className="text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-300 p-1 rounded"
title="Remove file"
data-testid="protobuf-remove-file-button"
>
<IconTrash size={14} />
</button>
</div>
</td>
</tr>
);
})
)}
</tbody>
</table>
<button type="button" className="btn-add-param text-link pr-2 py-3 mt-2 select-none" onClick={handleBrowseClick} data-testid="protobuf-add-file-button">
+ Add Proto File
</button>
</div>
</div>
{/* Import Paths Section */}
<div className="mb-6" data-testid="protobuf-import-paths-section">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center">
<label className="font-semibold text-sm flex items-center" htmlFor="importPaths">
Import Paths (
{importPaths.length}
)
<span id="import-paths-tooltip" className="ml-2">
<IconAlertCircle size={16} className="text-gray-500 cursor-pointer" />
</span>
<Tooltip
anchorId="import-paths-tooltip"
className="tooltip-mod font-normal"
html="Add directories that contain proto files to be imported. These paths help resolve import statements in your proto files."
/>
</label>
</div>
</div>
<div>
{importPaths.some((path) => !path.exists) && (
<div className="text-xs text-red-600 dark:text-red-400 mb-2 flex items-center p-2 rounded" data-testid="protobuf-invalid-import-paths-message">
<IconAlertCircle size={14} className="mr-1" />
Some import paths cannot be found at their specified locations.
</div>
)}
<table className="w-full border-collapse" data-testid="protobuf-import-paths-table">
<thead>
<tr>
<th className="text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider border border-gray-200 dark:border-gray-700 px-3 py-2">
</th>
<th className="text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider border border-gray-200 dark:border-gray-700 px-3 py-2">
Directory
</th>
<th className="text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider border border-gray-200 dark:border-gray-700 px-3 py-2">
Path
</th>
<th className="text-right text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider border border-gray-200 dark:border-gray-700 px-3 py-2">
Actions
</th>
</tr>
</thead>
<tbody>
{importPaths.length === 0 ? (
<tr>
<td colSpan="4" className="border border-gray-200 dark:border-gray-700 px-3 py-8 text-center">
<div className="flex flex-col items-center">
<IconFolder size={24} className="text-gray-400 mb-2" />
<span className="text-sm text-gray-500 dark:text-gray-400">No import paths added</span>
</div>
</td>
</tr>
) : (
importPaths.map((importPath, index) => {
const isValid = importPath.exists;
return (
<tr key={index}>
<td className="border border-gray-200 dark:border-gray-700 px-3 py-2">
<input
type="checkbox"
checked={importPath.enabled}
onChange={() => handleToggleImportPath(index)}
className="h-4 w-4 text-gray-600 focus:ring-gray-500 border-gray-300 dark:border-gray-600 rounded"
title={importPath.enabled ? 'Disable this import path' : 'Enable this import path'}
data-testid="protobuf-import-path-checkbox"
/>
</td>
<td className="border border-gray-200 dark:border-gray-700 px-3 py-2">
<div className="flex items-center">
<IconFolder size={16} className="text-gray-500 dark:text-gray-400 mr-2" />
<span className="text-sm font-medium text-gray-900 dark:text-gray-100">
{getBasename(collection.pathname, importPath.path)}
</span>
{!isValid && <IconAlertCircle size={12} className="text-red-600 dark:text-red-400 ml-2" />}
</div>
</td>
<td className="border border-gray-200 dark:border-gray-700 px-3 py-2">
<div className="text-xs text-gray-600 dark:text-gray-400 font-mono">
{importPath.path}
</div>
</td>
<td className="border border-gray-200 dark:border-gray-700 px-3 py-2 text-right">
<div className="flex items-center justify-end space-x-1">
{!isValid && (
<button
type="button"
onClick={() => handleReplaceImportPath(index)}
className="text-red-600 hover:text-red-900 dark:text-red-400 dark:hover:text-red-300 p-1 rounded"
title="Replace directory"
>
<IconFileImport size={14} />
</button>
)}
<button
type="button"
onClick={() => handleRemoveImportPath(index)}
className="text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-300 p-1 rounded"
title="Remove import path"
data-testid="protobuf-remove-import-path-button"
>
<IconTrash size={14} />
</button>
</div>
</td>
</tr>
);
})
)}
</tbody>
</table>
<button type="button" className="btn-add-param text-link pr-2 py-3 mt-2 select-none" onClick={handleBrowseImportPathClick} data-testid="protobuf-add-import-path-button">
+ Add Import Path
</button>
</div>
</div>
</StyledWrapper>
);
};
export default ProtobufSettings;

View File

@@ -53,6 +53,7 @@ const Script = ({ collection }) => {
onSave={handleSave}
font={get(preferences, 'font.codeFont', 'default')}
fontSize={get(preferences, 'font.codeFontSize')}
showHintsFor={['req', 'bru']}
/>
</div>
<div className="flex-1 mt-6">
@@ -66,6 +67,7 @@ const Script = ({ collection }) => {
onSave={handleSave}
font={get(preferences, 'font.codeFont', 'default')}
fontSize={get(preferences, 'font.codeFontSize')}
showHintsFor={['req', 'res', 'bru']}
/>
</div>

View File

@@ -37,6 +37,7 @@ const Tests = ({ collection }) => {
onSave={handleSave}
font={get(preferences, 'font.codeFont', 'default')}
fontSize={get(preferences, 'font.codeFontSize')}
showHintsFor={['req', 'res', 'bru']}
/>
<div className="mt-6">

View File

@@ -13,19 +13,12 @@ import Auth from './Auth';
import Script from './Script';
import Test from './Tests';
import Presets from './Presets';
import Protobuf from './Protobuf';
import StyledWrapper from './StyledWrapper';
import Vars from './Vars/index';
import DotIcon from 'components/Icons/Dot';
import StatusDot from 'components/StatusDot';
import Overview from './Overview/index';
const ContentIndicator = () => {
return (
<sup className="ml-[.125rem] opacity-80 font-medium">
<DotIcon width="10"></DotIcon>
</sup>
);
};
const CollectionSettings = ({ collection }) => {
const dispatch = useDispatch();
const tab = collection.settingsSelectedTab;
@@ -49,11 +42,15 @@ const CollectionSettings = ({ collection }) => {
const requestVars = get(collection, 'root.request.vars.req', []);
const responseVars = get(collection, 'root.request.vars.res', []);
const activeVarsCount = requestVars.filter((v) => v.enabled).length + responseVars.filter((v) => v.enabled).length;
const auth = get(collection, 'root.request.auth', {}).mode;
const authMode = get(collection, 'root.request.auth', {}).mode || 'none';
const presets = get(collection, 'brunoConfig.presets', []);
const hasPresets = presets && presets.requestUrl !== '';
const proxyConfig = get(collection, 'brunoConfig.proxy', {});
const proxyEnabled = proxyConfig.hostname ? true : false;
const clientCertConfig = get(collection, 'brunoConfig.clientCertificates.certs', []);
const protobufConfig = get(collection, 'brunoConfig.protobuf', {});
const onProxySettingsUpdate = (config) => {
const brunoConfig = cloneDeep(collection.brunoConfig);
@@ -130,6 +127,9 @@ const CollectionSettings = ({ collection }) => {
/>
);
}
case 'protobuf': {
return <Protobuf collection={collection} />;
}
}
};
@@ -140,9 +140,9 @@ const CollectionSettings = ({ collection }) => {
};
return (
<StyledWrapper className="flex flex-col h-full relative px-4 py-4">
<StyledWrapper className="flex flex-col h-full relative px-4 py-4 overflow-hidden">
<div className="flex flex-wrap items-center tabs" role="tablist">
<div className={getTabClassname('overview')} role="tab" onClick={() => setTab('overview')}>
<div className={getTabClassname('overview')} role="tab" onClick={() => setTab('overview')}>
Overview
</div>
<div className={getTabClassname('headers')} role="tab" onClick={() => setTab('headers')}>
@@ -155,29 +155,34 @@ const CollectionSettings = ({ collection }) => {
</div>
<div className={getTabClassname('auth')} role="tab" onClick={() => setTab('auth')}>
Auth
{auth !== 'none' && <ContentIndicator />}
{authMode !== 'none' && <StatusDot />}
</div>
<div className={getTabClassname('script')} role="tab" onClick={() => setTab('script')}>
Script
{hasScripts && <ContentIndicator />}
{hasScripts && <StatusDot />}
</div>
<div className={getTabClassname('tests')} role="tab" onClick={() => setTab('tests')}>
Tests
{hasTests && <ContentIndicator />}
{hasTests && <StatusDot />}
</div>
<div className={getTabClassname('presets')} role="tab" onClick={() => setTab('presets')}>
Presets
{hasPresets && <StatusDot />}
</div>
<div className={getTabClassname('proxy')} role="tab" onClick={() => setTab('proxy')}>
Proxy
{Object.keys(proxyConfig).length > 0 && <ContentIndicator />}
{Object.keys(proxyConfig).length > 0 && proxyEnabled && <StatusDot />}
</div>
<div className={getTabClassname('clientCert')} role="tab" onClick={() => setTab('clientCert')}>
Client Certificates
{clientCertConfig.length > 0 && <ContentIndicator />}
{clientCertConfig.length > 0 && <StatusDot />}
</div>
<div className={getTabClassname('protobuf')} role="tab" onClick={() => setTab('protobuf')}>
Protobuf
{protobufConfig.protoFiles && protobufConfig.protoFiles.length > 0 && <StatusDot />}
</div>
</div>
<section className="mt-4 h-full">{getTabPanel(tab)}</section>
<section className="mt-4 h-full overflow-auto">{getTabPanel(tab)}</section>
</StyledWrapper>
);
};

View File

@@ -0,0 +1,163 @@
import styled from 'styled-components';
const StyledWrapper = styled.div`
display: flex;
flex-direction: column;
height: 100%;
background: ${(props) => props.theme.console.contentBg};
overflow: hidden;
.debug-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 16px;
background: ${(props) => props.theme.console.headerBg};
border-bottom: 1px solid ${(props) => props.theme.console.border};
flex-shrink: 0;
}
.debug-title {
display: flex;
align-items: center;
gap: 8px;
color: ${(props) => props.theme.console.titleColor};
font-size: 13px;
font-weight: 500;
.error-count {
color: ${(props) => props.theme.console.countColor};
font-size: 12px;
font-weight: 400;
}
}
.debug-controls {
display: flex;
align-items: center;
gap: 8px;
}
.control-button {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
background: transparent;
border: 1px solid ${(props) => props.theme.console.border};
border-radius: 4px;
color: ${(props) => props.theme.console.buttonColor};
cursor: pointer;
transition: all 0.2s ease;
}
.debug-content {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
min-height: 0;
}
.debug-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
color: ${(props) => props.theme.console.emptyColor};
text-align: center;
gap: 8px;
padding: 40px 20px;
p {
margin: 0;
font-size: 14px;
font-weight: 500;
}
span {
font-size: 12px;
opacity: 0.7;
}
}
.errors-container {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
min-height: 0;
}
.errors-header {
display: grid;
grid-template-columns: 1fr 200px 120px;
gap: 12px;
padding: 8px 16px;
background: ${(props) => props.theme.console.headerBg};
border-bottom: 1px solid ${(props) => props.theme.console.border};
font-size: 11px;
font-weight: 600;
color: ${(props) => props.theme.console.titleColor};
text-transform: uppercase;
letter-spacing: 0.5px;
flex-shrink: 0;
}
.errors-list {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
min-height: 0;
}
.error-row {
display: grid;
grid-template-columns: 1fr 200px 120px;
gap: 12px;
padding: 8px 16px;
border-bottom: 1px solid ${(props) => props.theme.console.border};
cursor: pointer;
transition: background-color 0.1s ease;
font-size: 12px;
align-items: center;
&:hover {
background: ${(props) => props.theme.console.logHoverBg};
}
&.selected {
background: ${(props) => props.theme.console.buttonHoverBg};
border-left: 3px solid ${(props) => props.theme.console.checkboxColor};
}
}
.error-message {
color: ${(props) => props.theme.console.messageColor};
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: ui-monospace, 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
}
.error-location {
color: ${(props) => props.theme.console.messageColor};
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: ui-monospace, 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
font-size: 11px;
}
.error-time {
color: ${(props) => props.theme.console.timestampColor};
font-family: ui-monospace, 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
font-size: 11px;
text-align: right;
}
`;
export default StyledWrapper;

View File

@@ -0,0 +1,106 @@
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { IconBug } from '@tabler/icons';
import {
setSelectedError,
clearDebugErrors
} from 'providers/ReduxStore/slices/logs';
import StyledWrapper from './StyledWrapper';
const ErrorRow = ({ error, isSelected, onClick }) => {
const formatTime = (timestamp) => {
const date = new Date(timestamp);
return date.toLocaleTimeString('en-US', {
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
fractionalSecondDigits: 3
});
};
const getShortMessage = (message, maxLength = 80) => {
if (!message) return 'Unknown error';
return message.length > maxLength ? message.substring(0, maxLength) + '...' : message;
};
const getLocation = (error) => {
if (error.filename) {
const filename = error.filename.split('/').pop(); // Get just the filename
if (error.lineno && error.colno) {
return `${filename}:${error.lineno}:${error.colno}`;
} else if (error.lineno) {
return `${filename}:${error.lineno}`;
}
return filename;
}
return '-';
};
return (
<div
className={`error-row ${isSelected ? 'selected' : ''}`}
onClick={onClick}
>
<div className="error-message" title={error.message}>
{getShortMessage(error.message)}
</div>
<div className="error-location" title={error.filename}>
{getLocation(error)}
</div>
<div className="error-time">
{formatTime(error.timestamp)}
</div>
</div>
);
};
const DebugTab = () => {
const dispatch = useDispatch();
const { debugErrors, selectedError } = useSelector(state => state.logs);
const handleErrorClick = (error) => {
dispatch(setSelectedError(error));
};
const handleClearErrors = () => {
dispatch(clearDebugErrors());
};
return (
<StyledWrapper>
<div className="debug-content">
{debugErrors.length === 0 ? (
<div className="debug-empty">
<IconBug size={48} strokeWidth={1} />
<p>No errors</p>
<span>console.error() calls will appear here</span>
</div>
) : (
<div className="errors-container">
<div className="errors-header">
<div>Message</div>
<div>Location</div>
<div className="text-right">Time</div>
</div>
<div className="errors-list">
{debugErrors.map((error, index) => (
<ErrorRow
key={error.id}
error={error}
isSelected={selectedError?.id === error.id}
onClick={() => handleErrorClick(error)}
/>
))}
</div>
</div>
)}
</div>
</StyledWrapper>
);
};
export default DebugTab;

View File

@@ -0,0 +1,228 @@
import styled from 'styled-components';
const StyledWrapper = styled.div`
display: flex;
flex-direction: column;
height: 100%;
background: ${(props) => props.theme.console.contentBg};
border-left: 1px solid ${(props) => props.theme.console.border};
min-width: 400px;
max-width: 600px;
width: 40%;
overflow: hidden;
.panel-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 16px;
background: ${(props) => props.theme.console.headerBg};
border-bottom: 1px solid ${(props) => props.theme.console.border};
flex-shrink: 0;
}
.panel-title {
display: flex;
align-items: center;
gap: 8px;
color: ${(props) => props.theme.console.titleColor};
font-size: 13px;
font-weight: 500;
.error-time {
color: ${(props) => props.theme.console.countColor};
font-size: 11px;
font-weight: 400;
}
}
.close-button {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
background: transparent;
border: none;
border-radius: 4px;
color: ${(props) => props.theme.console.buttonColor};
cursor: pointer;
transition: all 0.2s ease;
&:hover {
background: ${(props) => props.theme.console.buttonHoverBg};
color: ${(props) => props.theme.console.buttonHoverColor};
}
}
.panel-tabs {
display: flex;
background: ${(props) => props.theme.console.headerBg};
border-bottom: 1px solid ${(props) => props.theme.console.border};
flex-shrink: 0;
}
.tab-button {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
background: transparent;
border: none;
border-bottom: 2px solid transparent;
color: ${(props) => props.theme.console.buttonColor};
cursor: pointer;
transition: all 0.2s ease;
font-size: 12px;
font-weight: 500;
&:hover {
background: ${(props) => props.theme.console.buttonHoverBg};
color: ${(props) => props.theme.console.buttonHoverColor};
}
&.active {
color: ${(props) => props.theme.console.checkboxColor};
border-bottom-color: ${(props) => props.theme.console.checkboxColor};
background: ${(props) => props.theme.console.contentBg};
}
}
.panel-content {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
background: ${(props) => props.theme.console.contentBg};
min-height: 0;
}
.tab-content {
padding: 16px;
height: 100%;
overflow-y: auto;
}
.section {
margin-bottom: 24px;
&:last-child {
margin-bottom: 0;
}
h4 {
margin: 0 0 12px 0;
font-size: 13px;
font-weight: 600;
color: ${(props) => props.theme.console.titleColor};
text-transform: uppercase;
letter-spacing: 0.5px;
}
}
.info-grid {
display: flex;
flex-direction: column;
gap: 12px;
}
.info-item {
display: flex;
flex-direction: column;
gap: 4px;
label {
font-size: 11px;
font-weight: 600;
color: ${(props) => props.theme.console.titleColor};
text-transform: uppercase;
letter-spacing: 0.5px;
}
span {
font-size: 12px;
color: ${(props) => props.theme.console.messageColor};
font-family: ui-monospace, 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
word-break: break-all;
line-height: 1.4;
}
}
.error-message-full {
color: ${(props) => props.theme.console.messageColor} !important;
background: ${(props) => props.theme.console.headerBg};
padding: 8px 12px;
border-radius: 4px;
border: 1px solid ${(props) => props.theme.console.border};
}
.file-path {
color: ${(props) => props.theme.console.checkboxColor} !important;
font-weight: 500 !important;
}
.report-section {
display: flex;
flex-direction: column;
gap: 12px;
p {
margin: 0;
font-size: 12px;
color: ${(props) => props.theme.console.messageColor};
line-height: 1.4;
}
}
.report-button {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: ${(props) => props.theme.console.buttonHoverBg};
border: 1px solid ${(props) => props.theme.console.border};
border-radius: 6px;
color: ${(props) => props.theme.console.buttonColor};
cursor: pointer;
transition: all 0.2s ease;
font-size: 12px;
font-weight: 500;
text-decoration: none;
align-self: flex-start;
&:hover {
background: ${(props) => props.theme.console.checkboxColor};
color: white;
border-color: ${(props) => props.theme.console.checkboxColor};
}
span {
font-family: inherit;
}
}
.stack-trace-container,
.arguments-container {
background: ${(props) => props.theme.console.headerBg};
border: 1px solid ${(props) => props.theme.console.border};
border-radius: 6px;
overflow: hidden;
}
.stack-trace,
.arguments {
margin: 0;
padding: 16px;
font-size: 11px;
line-height: 1.5;
color: ${(props) => props.theme.console.messageColor};
background: transparent;
font-family: ui-monospace, 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
white-space: pre-wrap;
word-break: break-word;
overflow-x: auto;
max-height: 400px;
overflow-y: auto;
}
`;
export default StyledWrapper;

Some files were not shown because too many files have changed in this diff Show More