mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-03 17:38:36 +00:00
Compare commits
1 Commits
feature/pl
...
feat/colle
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5713e19c23 |
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -1 +0,0 @@
|
||||
* @helloanoop @maintainer-bruno @lohit-bruno @naman-bruno
|
||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
github: helloanoop
|
||||
44
.github/ISSUE_TEMPLATE/BugReport.yaml
vendored
44
.github/ISSUE_TEMPLATE/BugReport.yaml
vendored
@@ -6,60 +6,26 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
|
||||
Before submitting, please make sure you've searched existing issues:
|
||||
👉 [Search existing issues](https://github.com/usebruno/bruno/issues?q=is%3Aissue)
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 'I have checked the following:'
|
||||
options:
|
||||
- label: "I have searched existing issues and found nothing related to my issue."
|
||||
- label: I use the newest version of bruno.
|
||||
required: true
|
||||
- label: I've searched existing issues and found nothing related to my issue.
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 'This bug is:'
|
||||
options:
|
||||
- label: making Bruno unusable for me
|
||||
required: false
|
||||
- label: slowing me down but I'm able to continue working
|
||||
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
|
||||
description: Please specify the version of Bruno you are using in which the issue occurs.
|
||||
placeholder: 1.38.1
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Operating System
|
||||
description: Information about the operating system the issue occurs on.
|
||||
placeholder: Windows 11 26100.3037 / macOS 15.1 (24B83) / Linux 6.13.1
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of the bug and how it's effecting your work along with steps to reproduce.
|
||||
description: A clear and concise description of the bug.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: .bru file to reproduce the bug
|
||||
description: Attach your .bru file here that can reproduce the problem.
|
||||
description: Attach your .bru file here that can reqroduce the problem.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshots/Live demo link
|
||||
|
||||
14
.github/ISSUE_TEMPLATE/FeatureRequest.yaml
vendored
14
.github/ISSUE_TEMPLATE/FeatureRequest.yaml
vendored
@@ -8,23 +8,13 @@ body:
|
||||
options:
|
||||
- label: I've searched existing issues and found nothing related to my issue.
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 'This feature'
|
||||
options:
|
||||
- label: blocks me from using Bruno
|
||||
required: false
|
||||
- label: would improve my quality of life in Bruno
|
||||
required: false
|
||||
- label: is something I've never seen an API client do before
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Suggest an idea for this project.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the feature you want to add, and how it would change your usage of Bruno
|
||||
label: Describe the feature you want to add
|
||||
description: A clear and concise description of the feature you want to be added.
|
||||
validations:
|
||||
required: true
|
||||
@@ -33,4 +23,4 @@ body:
|
||||
label: Mockups or Images of the feature
|
||||
description: Add some images to support your feature.
|
||||
validations:
|
||||
required: false
|
||||
required: true
|
||||
|
||||
31
.github/dependabot.yml
vendored
31
.github/dependabot.yml
vendored
@@ -1,31 +0,0 @@
|
||||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
- package-ecosystem: npm
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
groups:
|
||||
bruno-dependencies:
|
||||
patterns:
|
||||
- "*usebruno*"
|
||||
babel-dependencies:
|
||||
patterns:
|
||||
- "*babel*"
|
||||
fortawesome-dependencies:
|
||||
patterns:
|
||||
- "*fortawesome*"
|
||||
electron-dependencies:
|
||||
patterns:
|
||||
- "*electron*"
|
||||
rollup-dependencies:
|
||||
patterns:
|
||||
- "*rollup*"
|
||||
jest-dependencies:
|
||||
patterns:
|
||||
- "*jest*"
|
||||
9
.github/workflows/npm-bru-cli.yml
vendored
9
.github/workflows/npm-bru-cli.yml
vendored
@@ -20,13 +20,10 @@ permissions:
|
||||
jobs:
|
||||
test:
|
||||
name: CLI Tests
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
@@ -43,7 +40,7 @@ jobs:
|
||||
bru run --env Prod --output junit.xml --format junit
|
||||
|
||||
- name: Publish Test Report
|
||||
uses: dorny/test-reporter@v2
|
||||
uses: dorny/test-reporter@v1
|
||||
if: success() || failure()
|
||||
with:
|
||||
name: Test Report
|
||||
|
||||
53
.github/workflows/tests.yml
vendored
53
.github/workflows/tests.yml
vendored
@@ -10,8 +10,6 @@ jobs:
|
||||
name: Unit Tests
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
@@ -28,11 +26,6 @@ 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
|
||||
|
||||
- name: Lint Check
|
||||
run: npm run lint
|
||||
|
||||
# tests
|
||||
- name: Test Package bruno-js
|
||||
@@ -50,18 +43,12 @@ 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
|
||||
|
||||
cli-test:
|
||||
name: CLI Tests
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
checks: write
|
||||
pull-requests: write
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
@@ -78,8 +65,6 @@ 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
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
@@ -91,43 +76,5 @@ 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@v4
|
||||
- uses: actions/setup-node@v4
|
||||
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: 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
|
||||
|
||||
- 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
6
.gitignore
vendored
@@ -46,8 +46,4 @@ yarn-error.log*
|
||||
|
||||
#dev editor
|
||||
bruno.iml
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# Playwright
|
||||
/blob-report/
|
||||
.idea
|
||||
BIN
assets/images/sponsors/commit-company.png
Normal file
BIN
assets/images/sponsors/commit-company.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
BIN
assets/images/sponsors/samagata.png
Normal file
BIN
assets/images/sponsors/samagata.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
BIN
assets/images/sponsors/zuplo.png
Normal file
BIN
assets/images/sponsors/zuplo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
@@ -15,15 +15,14 @@
|
||||
| [正體中文](docs/contributing/contributing_zhtw.md)
|
||||
| [日本語](docs/contributing/contributing_ja.md)
|
||||
| [हिंदी](docs/contributing/contributing_hi.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 run Bruno on your computer.
|
||||
We are happy that you are looking to improve Bruno. Below are the guidelines to get started bringing up Bruno on your computer.
|
||||
|
||||
### Technology Stack
|
||||
|
||||
Bruno is built using React and Electron.
|
||||
Bruno is built using Next.js and React. We also use electron to ship a desktop version (that supports local collections)
|
||||
|
||||
Libraries we use
|
||||
|
||||
@@ -37,76 +36,38 @@ Libraries we use
|
||||
- Filesystem Watcher - chokidar
|
||||
- i18n - i18next
|
||||
|
||||
> [!IMPORTANT]
|
||||
> You would need [Node v22.x or the latest LTS version](https://nodejs.org/en/). We use npm workspaces in the project
|
||||
### 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
|
||||
|
||||
## Development
|
||||
|
||||
Bruno is a desktop app. Below are the instructions to run Bruno.
|
||||
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.
|
||||
|
||||
> Note: We use React for the frontend and rsbuild for build and dev server.
|
||||
|
||||
## Install Dependencies
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
# use nodejs 22 version
|
||||
# use nodejs 18 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
|
||||
|
||||
# bundle js sandbox libraries
|
||||
npm run sandbox:bundle-libraries --workspace=packages/bruno-js
|
||||
```
|
||||
##### Option 2
|
||||
|
||||
```bash
|
||||
# install dependencies and setup
|
||||
npm run setup
|
||||
```
|
||||
|
||||
#### Run the app
|
||||
|
||||
##### Option 1
|
||||
|
||||
```bash
|
||||
# run react app (terminal 1)
|
||||
# run next 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.
|
||||
@@ -124,32 +85,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
# run bruno-schema tests
|
||||
npm run test --workspace=packages/bruno-schema
|
||||
# bruno-schema
|
||||
npm 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
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Raising Pull Requests
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| **বাংলা**
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## আসুন ব্রুনোকে আরও ভালো করি, একসাথে!!
|
||||
|
||||
@@ -70,11 +86,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Testing (পরীক্ষা)
|
||||
|
||||
```bash
|
||||
# ব্রুনো-স্কিমা পরীক্ষা চালান
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# সমস্ত কর্মক্ষেত্রে পরীক্ষা চালান
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Raising Pull Request (পুল অনুরোধ উত্থাপন)
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| **简体中文**
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## 让我们一起改进 Bruno!
|
||||
|
||||
@@ -70,11 +86,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### 测试
|
||||
|
||||
```bash
|
||||
# 运行 bruno-schema 测试
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# 在所有工作区上运行测试
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### 提交 Pull Request
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| **Deutsch**
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## Lass uns Bruno noch besser machen, gemeinsam!!
|
||||
|
||||
@@ -21,7 +37,7 @@ Bibliotheken die wir benutzen
|
||||
|
||||
### Abhängigkeiten
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
### Lass uns coden
|
||||
|
||||
@@ -42,12 +58,12 @@ Bruno wird als Desktop-Anwendung entwickelt. Um die App zu starten, musst Du zue
|
||||
|
||||
### Abhängigkeiten
|
||||
|
||||
- NodeJS v22
|
||||
- NodeJS v18
|
||||
|
||||
### Lokales Entwickeln
|
||||
|
||||
```bash
|
||||
# use nodejs 22 version
|
||||
# use nodejs 18 version
|
||||
nvm use
|
||||
|
||||
# install deps
|
||||
@@ -83,9 +99,9 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Testen
|
||||
|
||||
```bash
|
||||
# Führen Sie Bruno-Schema-Tests aus
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# Führen Sie Tests für alle Arbeitsbereiche durch
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| **Español**
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## ¡Juntos, hagamos a Bruno mejor!
|
||||
|
||||
@@ -70,11 +86,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Pruebas
|
||||
|
||||
```bash
|
||||
# ejecutar pruebas de esquema bruno
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# ejecutar pruebas en todos los espacios de trabajo
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Crea un Pull Request
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| **Français**
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## Ensemble, améliorons Bruno !
|
||||
|
||||
@@ -73,11 +89,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Tests
|
||||
|
||||
```bash
|
||||
# exécuter des tests de schéma bruno
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# exécuter des tests sur tous les espaces de travail
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Ouvrir une Pull Request
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| **हिंदी**
|
||||
|
||||
## आइए मिलकर Bruno को बेहतर बनाएं !!
|
||||
|
||||
@@ -40,8 +56,6 @@ 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
|
||||
@@ -67,11 +81,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### परिक्षण
|
||||
|
||||
```bash
|
||||
# ब्रूनो-स्कीमा परीक्षण चलाएँ
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# सभी कार्यस्थानों पर परीक्षण चलाएँ
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### पुल अनुरोध प्रक्रिया
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| **Italiano**
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## Insieme, miglioriamo Bruno!
|
||||
|
||||
@@ -83,9 +99,9 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Tests
|
||||
|
||||
```bash
|
||||
# esegui i test dello schema bruno
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# esegui test su tutti gli spazi di lavoro
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| **日本語**
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## 一緒に Bruno をよりよいものにしていきましょう!!
|
||||
|
||||
@@ -40,8 +56,6 @@ 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
|
||||
@@ -67,11 +81,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### テストを動かすには
|
||||
|
||||
```bash
|
||||
# ブルーノスキーマのテストを実行します
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# すべてのワークスペースでテストを実行します
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### プルリクエストの手順
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| **한국어**
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## 함께 Bruno를 더 좋게 만들어요!!
|
||||
|
||||
@@ -40,8 +56,6 @@ 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
|
||||
@@ -68,11 +82,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### 테스팅
|
||||
|
||||
```bash
|
||||
# bruno-schema 테스트 실행
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# 모든 작업 공간에서 테스트 실행
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Pull Requests 요청
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
[English](../../contributing.md)
|
||||
|
||||
## Laten we Bruno samen beter maken !!
|
||||
|
||||
We zijn blij dat je Bruno wilt verbeteren. Hieronder staan de richtlijnen om Bruno op je computer op te zetten.
|
||||
|
||||
### Technologiestack
|
||||
|
||||
Bruno is gebouwd met Next.js en React. We gebruiken ook Electron om een desktopversie te leveren (die lokale collecties ondersteunt).
|
||||
|
||||
Bibliotheken die we gebruiken:
|
||||
|
||||
- CSS - Tailwind
|
||||
- Code Editors - Codemirror
|
||||
- State Management - Redux
|
||||
- Iconen - Tabler Icons
|
||||
- Formulieren - formik
|
||||
- Schema Validatie - Yup
|
||||
- Request Client - axios
|
||||
- Bestandsysteem Watcher - chokidar
|
||||
|
||||
### Afhankelijkheden
|
||||
|
||||
Je hebt [Node v18.x of de nieuwste LTS-versie](https://nodejs.org/en/) en npm 8.x nodig. We gebruiken npm workspaces in het project.
|
||||
|
||||
## Ontwikkeling
|
||||
|
||||
Bruno wordt ontwikkeld als een desktop-app. Je moet de app laden door de Next.js app in één terminal te draaien en daarna de Electron app in een andere terminal te draaien.
|
||||
|
||||
### Lokale Ontwikkeling
|
||||
|
||||
```bash
|
||||
# gebruik voorgeschreven node versie
|
||||
nvm use
|
||||
|
||||
# installeer afhankelijkheden
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# build pakketten
|
||||
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
|
||||
|
||||
# draai electron app (terminal 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### Problemen oplossen
|
||||
|
||||
Je kunt een `Unsupported platform`-fout tegenkomen wanneer je `npm install` uitvoert. Om dit te verhelpen, moet je `node_modules` en `package-lock.json` verwijderen en `npm install` uitvoeren. Dit zou alle benodigde afhankelijkheden moeten installeren om de app te draaien.
|
||||
|
||||
```shell
|
||||
# Verwijder node_modules in subdirectories
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# Verwijder package-lock in subdirectories
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### Testen
|
||||
|
||||
```bash
|
||||
# voer bruno-schema tests uit
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# voer tests uit over alle werkruimten
|
||||
npm test --workspaces --if-present
|
||||
```
|
||||
|
||||
### Pull Requests indienen
|
||||
|
||||
- Houd de PR's klein en gefocust op één ding
|
||||
- Volg het formaat voor het aanmaken van branches
|
||||
- feature/[feature naam]: Deze branch moet wijzigingen voor een specifieke functie bevatten
|
||||
- Voorbeeld: feature/dark-mode
|
||||
- bugfix/[bug naam]: Deze branch moet alleen bugfixes voor een specifieke bug bevatten
|
||||
- Voorbeeld: bugfix/bug-1
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| **Polski**
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## Wspólnie uczynijmy Bruno lepszym !!
|
||||
|
||||
@@ -71,11 +87,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Testowanie
|
||||
|
||||
```bash
|
||||
# uruchom testy bruno-schema
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# uruchom testy we wszystkich przestrzeniach roboczych
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Tworzenie Pull Request
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| **Português (BR)**
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## Vamos tornar o Bruno melhor, juntos!!
|
||||
|
||||
@@ -70,11 +86,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Testando
|
||||
|
||||
```bash
|
||||
# executar testes do bruno-schema
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# executar testes em todos os ambientes de trabalho
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Envio de Pull Request
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| **Română**
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## Haideţi să îmbunătățim Bruno, împreună!!
|
||||
|
||||
@@ -64,11 +80,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Testarea
|
||||
|
||||
```shell
|
||||
# executați teste bruno-schema
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# executați teste peste toate spațiile de lucru
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Crearea unui Pull Request
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| **Русский**
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## Давайте вместе сделаем Бруно лучше!!!
|
||||
|
||||
@@ -83,9 +99,9 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Тестирование
|
||||
|
||||
```bash
|
||||
# запустите тесты bruno-schema
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# запустите тесты во всех рабочих пространствах
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
@@ -42,8 +42,6 @@ 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
|
||||
@@ -69,11 +67,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Testovanie
|
||||
|
||||
````bash
|
||||
# spustiť bruno-schema testy
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# spustiť testy vo všetkých pracovných priestoroch
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Vyrobenie Pull Request
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| **Türkçe**
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## Bruno'yu birlikte daha iyi hale getirelim!!!
|
||||
|
||||
@@ -70,11 +86,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Test
|
||||
|
||||
```bash
|
||||
# bruno-schema testlerini çalıştır
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# tüm çalışma alanlarında testleri çalıştır
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Pull Request Oluşturma
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| **Українська**
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| [正體中文](./contributing_zhtw.md)
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## Давайте зробимо Bruno краще, разом !!
|
||||
|
||||
@@ -83,9 +99,9 @@ find . -type f -name "package-lock.json" -delete
|
||||
### Тестування
|
||||
|
||||
```bash
|
||||
# запустити тести bruno-schema
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# запустити тести у всіх робочих просторах
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
[English](../../contributing.md)
|
||||
| [Українська](./contributing_ua.md)
|
||||
| [Русский](./contributing_ru.md)
|
||||
| [Türkçe](./contributing_tr.md)
|
||||
| [Deutsch](./contributing_de.md)
|
||||
| [Français](./contributing_fr.md)
|
||||
| [Português (BR)](./contributing_pt_br.md)
|
||||
| [한국어](./contributing_kr.md)
|
||||
| [বাংলা](./contributing_bn.md)
|
||||
| [Español](./contributing_es.md)
|
||||
| [Italiano](./contributing_it.md)
|
||||
| [Română](./contributing_ro.md)
|
||||
| [Polski](./contributing_pl.md)
|
||||
| [简体中文](./contributing_cn.md)
|
||||
| **正體中文**
|
||||
| [日本語](./contributing_ja.md)
|
||||
| [हिंदी](./contributing_hi.md)
|
||||
|
||||
## 讓我們一起來讓 Bruno 變得更好!
|
||||
|
||||
@@ -70,11 +86,11 @@ find . -type f -name "package-lock.json" -delete
|
||||
### 測試
|
||||
|
||||
```bash
|
||||
# 執行布魯諾架構測試
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# 對所有工作區執行測試
|
||||
npm test --workspaces --if-present
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### 發送 Pull Request
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
[English](../../publishing.md)
|
||||
| [Türkçe](./publishing_tr.md)
|
||||
| [Deutsch](./publishing_de.md)
|
||||
| [Français](./publishing_fr.md)
|
||||
| [Português (BR)](./publishing_pt_br.md)
|
||||
| **বাংলা**
|
||||
| [Română](./publishing_ro.md)
|
||||
| [Polski](./publishing_pl.md)
|
||||
| [简体中文](./publishing_cn.md)
|
||||
| [正體中文](./publishing_zhtw.md)
|
||||
| [日本語](./publishing_ja.md)
|
||||
|
||||
### ব্রুনোকে নতুন প্যাকেজ ম্যানেজারে প্রকাশ করা
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
[English](../../publishing.md)
|
||||
| [Türkçe](./publishing_tr.md)
|
||||
| [Deutsch](./publishing_de.md)
|
||||
| [Français](./publishing_fr.md)
|
||||
| [Português (BR)](./publishing_pt_br.md)
|
||||
| [বাংলা](./publishing_bn.md)
|
||||
| [Română](./publishing_ro.md)
|
||||
| [Polski](./publishing_pl.md)
|
||||
| **简体中文**
|
||||
| [正體中文](./publishing_zhtw.md)
|
||||
| [日本語](./publishing_ja.md)
|
||||
|
||||
### 将 Bruno 发布到新的包管理器
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
[English](../../publishing.md)
|
||||
| [Türkçe](./publishing_tr.md)
|
||||
| **Deutsch**
|
||||
| [Français](./publishing_fr.md)
|
||||
| [Português (BR)](./publishing_pt_br.md)
|
||||
| [বাংলা](./publishing_bn.md)
|
||||
| [Română](./publishing_ro.md)
|
||||
| [Polski](./publishing_pl.md)
|
||||
| [简体中文](./publishing_cn.md)
|
||||
| [正體中文](./publishing_zhtw.md)
|
||||
| [日本語](./publishing_ja.md)
|
||||
|
||||
### Veröffentlichung von Bruno über neue Paket-Manager
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
[English](../../publishing.md)
|
||||
| [Türkçe](./publishing_tr.md)
|
||||
| [Deutsch](./publishing_de.md)
|
||||
| **Français**
|
||||
| [Português (BR)](./publishing_pt_br.md)
|
||||
| [বাংলা](./publishing_bn.md)
|
||||
| [Română](./publishing_ro.md)
|
||||
| [Polski](./publishing_pl.md)
|
||||
| [简体中文](./publishing_cn.md)
|
||||
| [正體中文](./publishing_zhtw.md)
|
||||
| [日本語](./publishing_ja.md)
|
||||
|
||||
### Publier Bruno dans un nouveau gestionnaire de paquets
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
[English](../../publishing.md)
|
||||
| [Türkçe](./publishing_tr.md)
|
||||
| [Deutsch](./publishing_de.md)
|
||||
| [Français](./publishing_fr.md)
|
||||
| [Português (BR)](./publishing_pt_br.md)
|
||||
| [বাংলা](./publishing_bn.md)
|
||||
| [Română](./publishing_ro.md)
|
||||
| [Polski](./publishing_pl.md)
|
||||
| [简体中文](./publishing_cn.md)
|
||||
| [正體中文](./publishing_zhtw.md)
|
||||
| **日本語**
|
||||
|
||||
### Bruno を新しいパッケージマネージャに公開する場合の注意
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
[English](../../publishing.md)
|
||||
|
||||
### Bruno publiceren naar een nieuwe pakketbeheerder
|
||||
|
||||
Hoewel onze code open source is en beschikbaar voor iedereen, verzoeken we je vriendelijk om contact met ons op te nemen voordat je publicatie overweegt op nieuwe pakketbeheerders. Als de maker van Bruno houd ik het handelsmerk `Bruno` voor dit project en wil ik het distributieproces beheren. Als je Bruno op een nieuwe pakketbeheerder wilt zien, dien dan een GitHub-issue in.
|
||||
|
||||
Hoewel de meerderheid van onze functies gratis en open source zijn (die REST en GraphQL API's dekken), streven we ernaar een harmonieuze balans te vinden tussen open-source principes en duurzaamheid - https://github.com/usebruno/bruno/discussions/269
|
||||
@@ -1,4 +1,14 @@
|
||||
[English](../../publishing.md)
|
||||
| [Türkçe](./publishing_tr.md)
|
||||
| [Deutsch](./publishing_de.md)
|
||||
| [Français](./publishing_fr.md)
|
||||
| [Português (BR)](./publishing_pt_br.md)
|
||||
| [বাংলা](./publishing_bn.md)
|
||||
| [Română](./publishing_ro.md)
|
||||
| **Polski**
|
||||
| [简体中文](./publishing_cn.md)
|
||||
| [正體中文](./publishing_zhtw.md)
|
||||
| [日本語](./publishing_ja.md)
|
||||
|
||||
### Publikowanie Bruno w nowym menedżerze pakietów
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
[English](../../publishing.md)
|
||||
| [Türkçe](./publishing_tr.md)
|
||||
| [Deutsch](./publishing_de.md)
|
||||
| [Français](./publishing_fr.md)
|
||||
| **Português (BR)**
|
||||
| [বাংলা](./publishing_bn.md)
|
||||
| [Română](./publishing_ro.md)
|
||||
| [Polski](./publishing_pl.md)
|
||||
| [简体中文](./publishing_cn.md)
|
||||
| [正體中文](./publishing_zhtw.md)
|
||||
| [日本語](./publishing_ja.md)
|
||||
|
||||
### Publicando Bruno em um novo gerenciador de pacotes
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
[English](../../publishing.md)
|
||||
| [Türkçe](./publishing_tr.md)
|
||||
| [Deutsch](./publishing_de.md)
|
||||
| [Français](./publishing_fr.md)
|
||||
| [Português (BR)](./publishing_pt_br.md)
|
||||
| [বাংলা](./publishing_bn.md)
|
||||
| **Română**
|
||||
| [Polski](./publishing_pl.md)
|
||||
| [简体中文](./publishing_cn.md)
|
||||
| [正體中文](./publishing_zhtw.md)
|
||||
| [日本語](./publishing_ja.md)
|
||||
|
||||
### Publicarea lui Bruno la un gestionar de pachete nou
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
[English](../../publishing.md)
|
||||
| **Türkçe**
|
||||
| [Deutsch](./publishing_de.md)
|
||||
| [Français](./publishing_fr.md)
|
||||
| [Português (BR)](./publishing_pt_br.md)
|
||||
| [বাংলা](./publishing_bn.md)
|
||||
| [Română](./publishing_ro.md)
|
||||
| [Polski](./publishing_pl.md)
|
||||
| [简体中文](./publishing_cn.md)
|
||||
| [正體中文](./publishing_zhtw.md)
|
||||
| [日本語](./publishing_ja.md)
|
||||
|
||||
### Bruno'yu yeni bir paket yöneticisine yayınlama
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
[English](../../publishing.md)
|
||||
| [Türkçe](./publishing_tr.md)
|
||||
| [Deutsch](./publishing_de.md)
|
||||
| [Français](./publishing_fr.md)
|
||||
| [Português (BR)](./publishing_pt_br.md)
|
||||
| [বাংলা](./publishing_bn.md)
|
||||
| [Română](./publishing_ro.md)
|
||||
| [Polski](./publishing_pl.md)
|
||||
| [简体中文](./publishing_cn.md)
|
||||
| **正體中文**
|
||||
| [日本語](./publishing_ja.md)
|
||||
|
||||
### 將 Bruno 發佈到新的套件管理器
|
||||
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
<br />
|
||||
<img src="../../assets/images/logo-transparent.png" width="80"/>
|
||||
|
||||
### Bruno - Open source IDE voor het verkennen en testen van API's.
|
||||
|
||||
[](https://badge.fury.io/gh/usebruno%bruno)
|
||||
[](https://github.com/usebruno/bruno/actions/workflows/tests.yml)
|
||||
[](https://github.com/usebruno/bruno/pulse)
|
||||
[](https://twitter.com/use_bruno)
|
||||
[](https://www.usebruno.com)
|
||||
[](https://www.usebruno.com/downloads)
|
||||
|
||||
[English](../../readme.md) | [Українська](docs/readme/readme_ua.md) | [Русский](docs/readme/readme_ru.md) | [Türkçe](docs/readme/readme_tr.md) | [Deutsch](docs/readme/readme_de.md) | ** Nederlands ** | [Français](docs/readme/readme_fr.md) | [Português (BR)](docs/readme/readme_pt_br.md) | [한국어](docs/readme/readme_kr.md) | [বাংলা](docs/readme/readme_bn.md) | [Español](docs/readme/readme_es.md) | [Italiano](docs/readme/readme_it.md) | [Română](docs/readme/readme_ro.md) | [Polski](docs/readme/readme_pl.md) | [简体中文](docs/readme/readme_cn.md) | [正體中文](docs/readme/readme_zhtw.md) | [العربية](docs/readme/readme_ar.md) | [日本語](docs/readme/readme_ja.md)
|
||||
|
||||
Bruno is een nieuwe en innovatieve API-client, gericht op het revolutioneren van de status quo die wordt vertegenwoordigd door Postman en vergelijkbare tools.
|
||||
|
||||
Bruno slaat je collecties direct op in een map op je bestandssysteem. We gebruiken een platte tekst opmaaktaal, Bru, om informatie over API-verzoeken op te slaan.
|
||||
|
||||
Je kunt Git of elke versiebeheertool naar keuze gebruiken om samen te werken aan je API-collecties.
|
||||
|
||||
Bruno is uitsluitend offline. Er zijn geen plannen om ooit cloud-synchronisatie aan Bruno toe te voegen. We waarderen je gegevensprivacy en geloven dat deze op je apparaat moet blijven. Lees onze langetermijnvisie [hier](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
[Download Bruno](https://www.usebruno.com/downloads)
|
||||
|
||||
📢 Bekijk onze recente presentatie op de India FOSS 3.0 Conference [hier](https://www.youtube.com/watch?v=7bSMFpbcPiY)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Golden Edition ✨
|
||||
|
||||
De meeste van onze functies zijn gratis en open source.
|
||||
We streven naar een harmonieuze balans tussen [open-source principes en duurzaamheid](https://github.com/usebruno/bruno/discussions/269).
|
||||
|
||||
Je kunt de [Golden Edition](https://www.usebruno.com/pricing) kopen voor een eenmalige betaling van **$19**! <br/>
|
||||
|
||||
### Installatie
|
||||
|
||||
Bruno is beschikbaar als binaire download [op onze website](https://www.usebruno.com/downloads) voor Mac, Windows en Linux.
|
||||
|
||||
Je kunt Bruno ook installeren via pakketbeheerders zoals Homebrew, Chocolatey, Scoop, Snap, Flatpak en Apt.
|
||||
|
||||
```sh
|
||||
# Op Mac via Homebrew
|
||||
brew install bruno
|
||||
|
||||
# Op Windows via Chocolatey
|
||||
choco install bruno
|
||||
|
||||
# Op Windows via Scoop
|
||||
scoop bucket add extras
|
||||
scoop install bruno
|
||||
|
||||
# Op Windows via winget
|
||||
winget install Bruno.Bruno
|
||||
|
||||
# Op Linux via Snap
|
||||
snap install bruno
|
||||
|
||||
# Op Linux via Flatpak
|
||||
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
|
||||
```
|
||||
|
||||
### Draai op meerdere platformen 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Samenwerken via Git 👩💻🧑💻
|
||||
|
||||
Of elk versiebeheersysteem naar keuze
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Sponsors
|
||||
|
||||
#### Gouden Sponsors
|
||||
|
||||
<img src="../../assets/images/sponsors/samagata.png" width="150"/>
|
||||
|
||||
#### Zilveren Sponsors
|
||||
|
||||
<img src="../../assets/images/sponsors/commit-company.png" width="70"/>
|
||||
|
||||
#### Bronzen Sponsors
|
||||
|
||||
<a href="https://zuplo.link/bruno">
|
||||
<img src="../../assets/images/sponsors/zuplo.png" width="120"/>
|
||||
</a>
|
||||
|
||||
### Belangrijke Links 📌
|
||||
|
||||
- [Onze Langetermijnvisie](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [Roadmap](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [Documentatie](https://docs.usebruno.com)
|
||||
- [Stack Overflow](https://stackoverflow.com/questions/tagged/bruno)
|
||||
- [Website](https://www.usebruno.com)
|
||||
- [Prijzen](https://www.usebruno.com/pricing)
|
||||
- [Download](https://www.usebruno.com/downloads)
|
||||
- [GitHub Sponsors](https://github.com/sponsors/helloanoop)
|
||||
|
||||
### Showcase 🎥
|
||||
|
||||
- [Getuigenissen](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Kenniscentrum](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Scriptmania](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### Ondersteuning ❤️
|
||||
|
||||
Als je Bruno leuk vindt en ons open-source werk wilt ondersteunen, overweeg dan om ons te sponsoren via [GitHub Sponsors](https://github.com/sponsors/helloanoop).
|
||||
|
||||
### Deel Getuigenissen 📣
|
||||
|
||||
Als Bruno je heeft geholpen op je werk en in je teams, deel dan je [getuigenissen op onze GitHub-discussie](https://github.com/usebruno/bruno/discussions/343).
|
||||
|
||||
|
||||
### Blijf in contact 🌐
|
||||
|
||||
[𝕏 (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)
|
||||
|
||||
### Handelsmerk
|
||||
|
||||
**Naam**
|
||||
|
||||
`Bruno` is een handelsmerk in bezit van [Anoop M D](https://www.helloanoop.com/).
|
||||
|
||||
**Logo**
|
||||
|
||||
Het logo is afkomstig van [OpenMoji](https://openmoji.org/library/emoji-1F436/). Licentie: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
### Bijdragen 👩💻🧑💻
|
||||
|
||||
Ik ben blij dat je Bruno wilt verbeteren. Bekijk de [bijdragegids](contributing.md).
|
||||
|
||||
Zelfs als je geen bijdragen via code kunt leveren, aarzel dan niet om bugs en functieverzoeken in te dienen die moeten worden geïmplementeerd om jouw gebruiksscenario op te lossen.
|
||||
|
||||
### Auteurs
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Licentie 📄
|
||||
|
||||
[MIT](../../license.md)
|
||||
@@ -29,13 +29,13 @@
|
||||
| [日本語](./readme_ja.md)
|
||||
| [ქართული](./readme_ka.md)
|
||||
|
||||
Bruno це новий та іноваційний API клієнт, націлений на революційну зміну статусy кво, запровадженого інструментами на кшталт Postman.
|
||||
Bruno це новий та іноваційний API клієнт, націлений на революційну зміну статус кво, запровадженого інструментами на кшталт Postman.
|
||||
|
||||
Bruno зберігає ваші колекції напряму у теці на вашому диску. Він використовує текстову мову розмітки Bru для збереження інформації про ваші API запити.
|
||||
|
||||
Ви можете використовувати git або будь-яку іншу систему контролю версій щоб спільно працювати над вашими колекціями API запитів.
|
||||
|
||||
Bruno є повністю автономним. Немає жодних планів додавати будь-які синхронізації через хмару, ніколи. Ми цінуємо приватність ваших даних, і вважаєм, що вони мають залишитись лише на вашому комп'ютері. Дізнатись більше про наше бачення у довготривалій перспективі можна [тут](https://github.com/usebruno/bruno/discussions/269)
|
||||
Bruno є повністю автономним. Немає жодних планів додавати будь-які синхронізації через хмару, ніколи. Ми цінуємо приватність ваших даних, і вважаєм, що вони мають залишитись лише на вашому комп'ютері. Взнати більше про наше бачення у довготривалій перспективі можна [тут](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
@@ -69,13 +69,13 @@ Bruno є повністю автономним. Немає жодних план
|
||||
|
||||
### Поділитись відгуками 📣
|
||||
|
||||
Якщо Bruno допоміг у роботі вам або вашій команді, будь ласка не забудьте поділитись вашими [відгуками у github дискусії](https://github.com/usebruno/bruno/discussions/343)
|
||||
Якщо Bruno допоміг вам у вашій роботі і вашим командам, будь ласка не забудьте поділитись вашими [відгуками у github дискусії](https://github.com/usebruno/bruno/discussions/343)
|
||||
|
||||
### Зробити свій внесок 👩💻🧑💻
|
||||
|
||||
Я радий що ви бажаєте покращити Bruno. Будь ласка переглянте [інструкцію по контрибуції](../contributing/contributing_ua.md)
|
||||
|
||||
Навіть якщо ви не можете зробити свій внесок пишучи код, будь ласка не соромтесь рапортувати про помилки і писати запити на новий функціонал, який потрібен вам у вашій роботі.
|
||||
Навіть якщо ви не можете зробити свій внесок пишучи програмний код, будь ласка не соромтесь рапортувати про помилки і писати запити на новий функціонал, який потрібен вам у вашій роботі.
|
||||
|
||||
### Автори
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import { test, expect } from '../../playwright';
|
||||
|
||||
test('Check if the logo on top left is visible', async ({ page }) => {
|
||||
await expect(page.getByRole('button', { name: 'bruno' })).toBeVisible();
|
||||
});
|
||||
@@ -1,31 +0,0 @@
|
||||
import { test, expect } from '../../playwright';
|
||||
|
||||
test('Create new collection and add a simple HTTP request', async ({ page, createTmpDir }) => {
|
||||
await page.getByLabel('Create Collection').click();
|
||||
await page.getByLabel('Name').click();
|
||||
await page.getByLabel('Name').fill('test-collection');
|
||||
await page.getByLabel('Name').press('Tab');
|
||||
await page.getByLabel('Location').fill(await createTmpDir('test-collection'));
|
||||
await page.getByRole('button', { name: 'Create', exact: true }).click();
|
||||
await page.getByText('test-collection').click();
|
||||
await page.getByLabel('Safe ModeBETA').check();
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
await page.locator('#create-new-tab').getByRole('img').click();
|
||||
await page.getByPlaceholder('Request Name').fill('r1');
|
||||
await page.getByPlaceholder('Request URL').click();
|
||||
await page.getByPlaceholder('Request URL').fill('http://localhost:8081');
|
||||
await page.getByRole('button', { name: 'Create' }).click();
|
||||
await page.locator('pre').filter({ hasText: 'http://localhost:' }).click();
|
||||
await page.locator('textarea').fill('/ping');
|
||||
await page.locator('#send-request').getByRole('img').nth(2).click();
|
||||
|
||||
await expect(page.getByRole('main')).toContainText('200 OK');
|
||||
|
||||
await page.getByRole('tab', { name: 'GET r1' }).locator('circle').click();
|
||||
await page.getByRole('button', { name: 'Save', exact: true }).click();
|
||||
await page.getByText('GETr1').click();
|
||||
await page.getByRole('button', { name: 'Clear response' }).click();
|
||||
await page.locator('body').press('ControlOrMeta+Enter');
|
||||
|
||||
await expect(page.getByRole('main')).toContainText('200 OK');
|
||||
});
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"maximized": true,
|
||||
"lastOpenedCollections": ["{{projectRoot}}/packages/bruno-tests/collection"]
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import { test, expect } from '../../playwright';
|
||||
|
||||
test.describe.parallel('Run Testbench Requests', () => {
|
||||
test('Run bruno-testbench in Developer Mode', async ({ pageWithUserData: page }) => {
|
||||
test.setTimeout(2 * 60 * 1000);
|
||||
|
||||
await page.getByText('bruno-testbench').click();
|
||||
await page.getByLabel('Developer Mode(use only if').check();
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
await page.locator('.environment-selector').nth(1).click();
|
||||
await page.locator('.dropdown-item').getByText('Prod').click();
|
||||
await page.locator('.collection-actions').hover();
|
||||
await page.locator('.collection-actions .icon').click();
|
||||
await page.getByText('Run', { exact: true }).click();
|
||||
await page.getByRole('button', { name: 'Run Collection' }).click();
|
||||
await page.getByRole('button', { name: 'Run Again' }).waitFor({ timeout: 2 * 60 * 1000 });
|
||||
|
||||
const result = await page.getByText('Total Requests: ').innerText();
|
||||
const [totalRequests, passed, failed, skipped] = result
|
||||
.match(/Total Requests: (\d+), Passed: (\d+), Failed: (\d+), Skipped: (\d+)/)
|
||||
.slice(1);
|
||||
|
||||
await expect(parseInt(failed)).toBe(0);
|
||||
await expect(parseInt(passed)).toBe(parseInt(totalRequests) - parseInt(skipped) - 1);
|
||||
});
|
||||
|
||||
test.fixme('Run bruno-testbench in Safe Mode', async ({ pageWithUserData: page }) => {
|
||||
test.setTimeout(2 * 60 * 1000);
|
||||
|
||||
await page.getByText('bruno-testbench').click();
|
||||
await page.getByLabel('Safe ModeBETA').check();
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
await page.locator('.environment-selector').nth(1).click();
|
||||
await page.locator('.dropdown-item').getByText('Prod').click();
|
||||
await page.locator('.collection-actions').hover();
|
||||
await page.locator('.collection-actions .icon').click();
|
||||
await page.getByText('Run', { exact: true }).click();
|
||||
await page.getByRole('button', { name: 'Run Collection' }).click();
|
||||
await page.getByRole('button', { name: 'Run Again' }).waitFor({ timeout: 2 * 60 * 1000 });
|
||||
|
||||
const result = await page.getByText('Total Requests: ').innerText();
|
||||
const [totalRequests, passed, failed, skipped] = result
|
||||
.match(/Total Requests: (\d+), Passed: (\d+), Failed: (\d+), Skipped: (\d+)/)
|
||||
.slice(1);
|
||||
|
||||
await expect(parseInt(failed)).toBe(0);
|
||||
await expect(parseInt(passed)).toBe(parseInt(totalRequests) - parseInt(skipped) - 1);
|
||||
});
|
||||
});
|
||||
@@ -1,27 +0,0 @@
|
||||
import { test, expect } from '../../playwright';
|
||||
|
||||
test('Should verify all support links with correct URL in preference > Support tab', async ({ page }) => {
|
||||
|
||||
// Open Preferences
|
||||
await page.getByLabel('Open Preferences').click();
|
||||
|
||||
// Verify Support tab
|
||||
await page.getByRole('tab', { name: 'Support' }).click();
|
||||
|
||||
const locator_twitter = page.getByRole('link', { name: 'Twitter' });
|
||||
expect(await locator_twitter.getAttribute('href')).toEqual('https://twitter.com/use_bruno');
|
||||
|
||||
const locator_github = page.getByRole('link', { name: 'GitHub', exact: true });
|
||||
expect(await locator_github.getAttribute('href')).toEqual('https://github.com/usebruno/bruno');
|
||||
|
||||
const locator_discord = page.getByRole('link', { name: 'Discord', exact: true });
|
||||
expect(await locator_discord.getAttribute('href')).toEqual('https://discord.com/invite/KgcZUncpjq');
|
||||
|
||||
const locator_reportissues = page.getByRole('link', { name: 'Report Issues', exact: true });
|
||||
expect(await locator_reportissues.getAttribute('href')).toEqual('https://github.com/usebruno/bruno/issues');
|
||||
|
||||
const locator_documentation = page.getByRole('link', { name: 'Documentation', exact: true });
|
||||
expect(await locator_documentation.getAttribute('href')).toEqual('https://docs.usebruno.com');
|
||||
|
||||
|
||||
});
|
||||
@@ -1,41 +0,0 @@
|
||||
// eslint.config.js
|
||||
const { defineConfig } = require("eslint/config");
|
||||
const globals = require("globals");
|
||||
|
||||
module.exports = defineConfig([
|
||||
{
|
||||
files: ["packages/bruno-app/**/*.{js,jsx,ts}"],
|
||||
ignores: ["**/*.config.js"],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.jest,
|
||||
global: false,
|
||||
require: false,
|
||||
Buffer: false,
|
||||
process: false
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"no-undef": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["packages/bruno-electron/**/*.{js}"],
|
||||
ignores: ["**/*.config.js"],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
...globals.jest,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"no-undef": "error",
|
||||
},
|
||||
}
|
||||
]);
|
||||
25339
package-lock.json
generated
25339
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@@ -6,48 +6,36 @@
|
||||
"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-requests"
|
||||
"packages/bruno-graphql-docs"
|
||||
],
|
||||
"homepage": "https://usebruno.com",
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^7.6.0",
|
||||
"@jest/globals": "^29.2.0",
|
||||
"@playwright/test": "^1.51.1",
|
||||
"@playwright/test": "^1.27.1",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^22.14.1",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint": "^9.26.0",
|
||||
"fs-extra": "^11.1.1",
|
||||
"globals": "^16.1.0",
|
||||
"husky": "^8.0.3",
|
||||
"jest": "^29.2.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"playwright": "^1.51.1",
|
||||
"pretty-quick": "^3.1.3",
|
||||
"randomstring": "^1.2.2",
|
||||
"rimraf": "^6.0.1",
|
||||
"ts-jest": "^29.2.6"
|
||||
"ts-jest": "^29.0.5"
|
||||
},
|
||||
"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\"",
|
||||
"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-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",
|
||||
@@ -57,18 +45,16 @@
|
||||
"build:electron:deb": "./scripts/build-electron.sh deb",
|
||||
"build:electron:rpm": "./scripts/build-electron.sh rpm",
|
||||
"build:electron:snap": "./scripts/build-electron.sh snap",
|
||||
"watch:common": "npm run watch --workspace=packages/bruno-common",
|
||||
"test:codegen": "node playwright/codegen.ts",
|
||||
"test:e2e": "playwright test",
|
||||
"test:e2e": "npx playwright test",
|
||||
"test:report": "npx playwright show-report",
|
||||
"test:prettier:web": "npm run test:prettier --workspace=packages/bruno-app",
|
||||
"lint": "node --max_old_space_size=4096 $(npx which eslint)"
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"overrides": {
|
||||
"rollup": "3.29.5",
|
||||
"electron-store": {
|
||||
"conf": {
|
||||
"json-schema-typed": "8.0.1"
|
||||
}
|
||||
}
|
||||
"rollup":"3.29.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"json-bigint": "^1.0.0",
|
||||
"lossless-json": "^4.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env"],
|
||||
"presets": ["next/babel"],
|
||||
"plugins": [["styled-components", { "ssr": true }]]
|
||||
}
|
||||
4
packages/bruno-app/.gitignore
vendored
4
packages/bruno-app/.gitignore
vendored
@@ -31,6 +31,4 @@ yarn-error.log*
|
||||
|
||||
# next.js
|
||||
.next/
|
||||
dist/
|
||||
|
||||
.env
|
||||
out/
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
module.exports = {
|
||||
rootDir: '.',
|
||||
moduleNameMapper: {
|
||||
'^assets/(.*)$': '<rootDir>/src/assets/$1',
|
||||
'^components/(.*)$': '<rootDir>/src/components/$1',
|
||||
'^hooks/(.*)$': '<rootDir>/src/hooks/$1',
|
||||
'^themes/(.*)$': '<rootDir>/src/themes/$1',
|
||||
'^api/(.*)$': '<rootDir>/src/api/$1',
|
||||
'^pageComponents/(.*)$': '<rootDir>/src/pageComponents/$1',
|
||||
'^providers/(.*)$': '<rootDir>/src/providers/$1',
|
||||
'^utils/(.*)$': '<rootDir>/src/utils/$1'
|
||||
},
|
||||
clearMocks: true,
|
||||
moduleDirectories: ['node_modules', 'src'],
|
||||
testEnvironment: 'node'
|
||||
};
|
||||
15
packages/bruno-app/next.config.js
Normal file
15
packages/bruno-app/next.config.js
Normal file
@@ -0,0 +1,15 @@
|
||||
module.exports = {
|
||||
reactStrictMode: false,
|
||||
publicRuntimeConfig: {
|
||||
CI: process.env.CI,
|
||||
PLAYWRIGHT: process.env.PLAYWRIGHT,
|
||||
ENV: process.env.ENV
|
||||
},
|
||||
webpack: (config, { isServer }) => {
|
||||
// Fixes npm packages that depend on `fs` module
|
||||
if (!isServer) {
|
||||
config.resolve.fallback.fs = false;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
};
|
||||
@@ -1,78 +1,78 @@
|
||||
{
|
||||
"name": "@usebruno/app",
|
||||
"version": "2.0.0",
|
||||
"version": "0.3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "rsbuild dev",
|
||||
"build": "rsbuild build -m production",
|
||||
"preview": "rsbuild preview",
|
||||
"dev": "cross-env ENV=dev next dev -p 3000",
|
||||
"build": "next build && next export",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"test": "jest",
|
||||
"test:prettier": "prettier --check \"./src/**/*.{js,jsx,json,ts,tsx}\"",
|
||||
"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",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||
"@fortawesome/react-fontawesome": "^0.1.16",
|
||||
"@reduxjs/toolkit": "^1.8.0",
|
||||
"@tabler/icons": "^1.46.0",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"@usebruno/common": "0.1.0",
|
||||
"@usebruno/graphql-docs": "0.1.0",
|
||||
"@usebruno/schema": "0.7.0",
|
||||
"axios": "^1.5.1",
|
||||
"classnames": "^2.3.1",
|
||||
"codemirror": "5.65.2",
|
||||
"codemirror-graphql": "2.1.1",
|
||||
"cookie": "0.7.1",
|
||||
"dompurify": "^3.2.4",
|
||||
"codemirror-graphql": "1.2.5",
|
||||
"cookie": "^0.6.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"file": "^0.2.2",
|
||||
"file-dialog": "^0.0.8",
|
||||
"file-saver": "^2.0.5",
|
||||
"formik": "^2.2.9",
|
||||
"github-markdown-css": "^5.2.0",
|
||||
"graphiql": "3.7.1",
|
||||
"graphiql": "^1.5.9",
|
||||
"graphql": "^16.6.0",
|
||||
"graphql-request": "^3.7.0",
|
||||
"httpsnippet": "^3.0.9",
|
||||
"i18next": "24.1.2",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"httpsnippet": "^3.0.6",
|
||||
"i18next": "^23.14.0",
|
||||
"idb": "^7.0.0",
|
||||
"immer": "^9.0.15",
|
||||
"jsesc": "^3.0.2",
|
||||
"jshint": "^2.13.6",
|
||||
"json5": "^2.2.3",
|
||||
"jsonc-parser": "^3.2.1",
|
||||
"jsonpath-plus": "^10.3.0",
|
||||
"jsonlint": "^1.6.3",
|
||||
"jsonpath-plus": "^7.2.0",
|
||||
"know-your-http-well": "^0.5.0",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-it": "^13.0.2",
|
||||
"markdown-it-replace-link": "^1.2.0",
|
||||
"moment": "^2.30.1",
|
||||
"moment-timezone": "^0.5.47",
|
||||
"mousetrap": "^1.6.5",
|
||||
"nanoid": "3.3.8",
|
||||
"nanoid": "3.3.4",
|
||||
"next": "12.3.3",
|
||||
"path": "^0.12.7",
|
||||
"pdfjs-dist": "4.4.168",
|
||||
"pdfjs-dist": "^3.11.174",
|
||||
"platform": "^1.3.6",
|
||||
"posthog-node": "4.2.1",
|
||||
"posthog-node": "^2.1.0",
|
||||
"prettier": "^2.7.1",
|
||||
"qs": "^6.11.0",
|
||||
"query-string": "^7.0.1",
|
||||
"react": "19.0.0",
|
||||
"react": "18.2.0",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dom": "19.0.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-github-btn": "^1.4.0",
|
||||
"react-hot-toast": "^2.4.0",
|
||||
"react-i18next": "^15.0.1",
|
||||
"react-inspector": "^6.0.2",
|
||||
"react-pdf": "9.1.1",
|
||||
"react-player": "^2.16.0",
|
||||
"react-redux": "^7.2.9",
|
||||
"react-pdf": "^7.5.1",
|
||||
"react-redux": "^7.2.6",
|
||||
"react-tooltip": "^5.5.2",
|
||||
"sass": "^1.46.0",
|
||||
"semver": "^7.7.1",
|
||||
"strip-json-comments": "^5.0.1",
|
||||
"styled-components": "^5.3.3",
|
||||
"system": "^2.0.1",
|
||||
@@ -82,21 +82,20 @@
|
||||
"yup": "^0.32.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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",
|
||||
"autoprefixer": "10.4.20",
|
||||
"babel-plugin-react-compiler": "19.0.0-beta-a7bf2bd-20241110",
|
||||
"@babel/core": "^7.16.0",
|
||||
"@babel/plugin-transform-spread": "^7.16.7",
|
||||
"@babel/preset-env": "^7.16.4",
|
||||
"@babel/preset-react": "^7.16.0",
|
||||
"@babel/runtime": "^7.16.3",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"babel-loader": "^8.2.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "7.1.2",
|
||||
"css-loader": "^6.5.1",
|
||||
"file-loader": "^6.2.0",
|
||||
"html-loader": "^3.0.1",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"mini-css-extract-plugin": "^2.4.5",
|
||||
"postcss": "8.4.47",
|
||||
"postcss": "^8.4.35",
|
||||
"style-loader": "^3.3.1",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"webpack": "^5.64.4",
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import { defineConfig } from '@rsbuild/core';
|
||||
import { pluginReact } from '@rsbuild/plugin-react';
|
||||
import { pluginBabel } from '@rsbuild/plugin-babel';
|
||||
import { pluginStyledComponents } from '@rsbuild/plugin-styled-components';
|
||||
import { pluginSass } from '@rsbuild/plugin-sass';
|
||||
import { pluginNodePolyfill } from '@rsbuild/plugin-node-polyfill'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
pluginNodePolyfill(),
|
||||
pluginReact(),
|
||||
pluginStyledComponents(),
|
||||
pluginSass(),
|
||||
pluginBabel({
|
||||
include: /\.(?:js|jsx|tsx)$/,
|
||||
babelLoaderOptions(opts) {
|
||||
opts.plugins?.unshift('babel-plugin-react-compiler');
|
||||
}
|
||||
})
|
||||
],
|
||||
source: {
|
||||
tsconfigPath: './jsconfig.json', // Specifies the path to the JavaScript/TypeScript configuration file,
|
||||
},
|
||||
html: {
|
||||
title: 'Bruno'
|
||||
},
|
||||
tools: {
|
||||
rspack: {
|
||||
module: {
|
||||
parser: {
|
||||
javascript: {
|
||||
// This loads the JavaScript contents from a library along with the main JavaScript bundle.
|
||||
dynamicImportMode: "eager",
|
||||
},
|
||||
},
|
||||
},
|
||||
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'
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
@@ -1,62 +0,0 @@
|
||||
import React, { createContext, useContext, useState } from 'react';
|
||||
import { IconChevronDown } from '@tabler/icons';
|
||||
import { AccordionItem, AccordionHeader, AccordionContent } from './styledWrapper';
|
||||
|
||||
const AccordionContext = createContext();
|
||||
|
||||
const Accordion = ({ children, defaultIndex }) => {
|
||||
const [openIndex, setOpenIndex] = useState(defaultIndex);
|
||||
|
||||
const toggleItem = (index) => {
|
||||
setOpenIndex(openIndex === index ? null : index);
|
||||
};
|
||||
|
||||
return (
|
||||
<AccordionContext.Provider value={{ openIndex, toggleItem }}>
|
||||
<div>{children}</div>
|
||||
</AccordionContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const Item = ({ index, children, ...props }) => {
|
||||
return (
|
||||
<AccordionItem {...props}>
|
||||
{React.Children.map(children, (child) => React.cloneElement(child, { index }))}
|
||||
</AccordionItem>
|
||||
);
|
||||
};
|
||||
|
||||
export const Header = ({ index, children, ...props }) => {
|
||||
const { openIndex, toggleItem } = useContext(AccordionContext);
|
||||
const isOpen = openIndex === index;
|
||||
|
||||
return (
|
||||
<AccordionHeader onClick={() => toggleItem(index)} {...props} className={isOpen ? 'open' : ''}>
|
||||
<div className="w-full">{children}</div>
|
||||
|
||||
<IconChevronDown
|
||||
className="w-5 h-5 ml-auto"
|
||||
style={{
|
||||
transform: `rotate(${isOpen ? '180deg' : '0deg'})`,
|
||||
transition: 'transform 0.3s ease-in-out'
|
||||
}}
|
||||
/>
|
||||
</AccordionHeader>
|
||||
);
|
||||
};
|
||||
|
||||
const Content = ({ index, children, ...props }) => {
|
||||
const { openIndex } = useContext(AccordionContext);
|
||||
const isOpen = openIndex === index;
|
||||
|
||||
return (
|
||||
<AccordionContent isOpen={isOpen} {...props}>
|
||||
{children}
|
||||
</AccordionContent>
|
||||
);
|
||||
};
|
||||
|
||||
Accordion.Item = Item;
|
||||
Accordion.Header = Header;
|
||||
Accordion.Content = Content;
|
||||
export default Accordion;
|
||||
@@ -1,28 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const AccordionItem = styled.div`
|
||||
border: 1px solid ${(props) => props.theme.input.border};
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 1rem;
|
||||
`;
|
||||
|
||||
const AccordionHeader = styled.button`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
padding: 0.75rem 1rem;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
|
||||
&.open, &:hover {
|
||||
background-color: ${(props) => props.theme.plainGrid.hoverBg};
|
||||
}
|
||||
`;
|
||||
|
||||
const AccordionContent = styled.div`
|
||||
padding: ${(props) => (props.isOpen ? '1rem' : '0')};
|
||||
max-height: ${(props) => (props.isOpen ? 'auto' : '0')};
|
||||
`;
|
||||
|
||||
export { AccordionItem, AccordionHeader, AccordionContent };
|
||||
@@ -8,17 +8,6 @@ const StyledWrapper = styled.div`
|
||||
font-size: ${(props) => (props.fontSize ? `${props.fontSize}px` : 'inherit')};
|
||||
line-break: anywhere;
|
||||
flex: 1 1 0;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
/* Removes the glow outline around the folded json */
|
||||
.CodeMirror-foldmarker {
|
||||
text-shadow: none;
|
||||
color: ${(props) => props.theme.textLink};
|
||||
background: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-overlayscroll-horizontal div,
|
||||
@@ -28,16 +17,6 @@ const StyledWrapper = styled.div`
|
||||
|
||||
.CodeMirror-dialog {
|
||||
overflow: visible;
|
||||
position: relative;
|
||||
top: unset;
|
||||
left: unset;
|
||||
|
||||
input {
|
||||
background: transparent;
|
||||
border: 1px solid #d3d6db;
|
||||
outline: none;
|
||||
border-radius: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
#search-results-count {
|
||||
@@ -90,25 +69,6 @@ const StyledWrapper = styled.div`
|
||||
.cm-variable-invalid {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.CodeMirror-search-hint {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.cm-s-default span.cm-property {
|
||||
color: #1f61a0 !important;
|
||||
}
|
||||
|
||||
.cm-s-default span.cm-variable {
|
||||
color: #397d13 !important;
|
||||
}
|
||||
|
||||
//matching bracket fix
|
||||
.CodeMirror-matchingbracket {
|
||||
background: #5cc0b48c !important;
|
||||
text-decoration:unset;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { isEqual, escapeRegExp } from 'lodash';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { getEnvironmentVariables } from 'utils/collections';
|
||||
import { defineCodeMirrorBrunoVariablesMode } from 'utils/common/codemirror';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import * as jsonlint from '@prantlf/jsonlint';
|
||||
import jsonlint from 'jsonlint';
|
||||
import { JSHINT } from 'jshint';
|
||||
import stripJsonComments from 'strip-json-comments';
|
||||
import { getAllVariables } from 'utils/collections';
|
||||
|
||||
let CodeMirror;
|
||||
const SERVER_RENDERED = typeof window === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
|
||||
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
|
||||
const TAB_SIZE = 2;
|
||||
|
||||
if (!SERVER_RENDERED) {
|
||||
@@ -31,11 +31,9 @@ if (!SERVER_RENDERED) {
|
||||
'res.body',
|
||||
'res.responseTime',
|
||||
'res.getStatus()',
|
||||
'res.getStatusText()',
|
||||
'res.getHeader(name)',
|
||||
'res.getHeaders()',
|
||||
'res.getBody()',
|
||||
'res.setBody(data)',
|
||||
'res.getResponseTime()',
|
||||
'req',
|
||||
'req.url',
|
||||
@@ -57,38 +55,21 @@ if (!SERVER_RENDERED) {
|
||||
'req.setMaxRedirects(maxRedirects)',
|
||||
'req.getTimeout()',
|
||||
'req.setTimeout(timeout)',
|
||||
'req.getExecutionMode()',
|
||||
'req.getName()',
|
||||
'bru',
|
||||
'bru.cwd()',
|
||||
'bru.getEnvName()',
|
||||
'bru.getEnvName(key)',
|
||||
'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.getCollectionName()',
|
||||
'bru.getGlobalEnvVar(key)',
|
||||
'bru.setGlobalEnvVar(key, value)',
|
||||
'bru.runner',
|
||||
'bru.runner.setNextRequest(requestName)',
|
||||
'bru.runner.skipRequest()',
|
||||
'bru.runner.stopExecution()',
|
||||
'bru.interpolate(str)'
|
||||
'bru.sleep(ms)'
|
||||
];
|
||||
CodeMirror.registerHelper('hint', 'brunoJS', (editor, options) => {
|
||||
const cursor = editor.getCursor();
|
||||
@@ -110,7 +91,7 @@ if (!SERVER_RENDERED) {
|
||||
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.push(curWordBru.includes('.') ? h.split('.')[1] : h);
|
||||
}
|
||||
});
|
||||
result.list?.sort();
|
||||
@@ -179,21 +160,11 @@ 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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
cm.execCommand('findPersistent');
|
||||
this._bindSearchHandler();
|
||||
this._appendSearchResultsCount();
|
||||
@@ -212,19 +183,31 @@ export default class CodeEditor extends React.Component {
|
||||
'Cmd-Y': 'foldAll',
|
||||
'Ctrl-I': 'unfoldAll',
|
||||
'Cmd-I': 'unfoldAll',
|
||||
'Ctrl-/': () => {
|
||||
if (['application/ld+json', 'application/json'].includes(this.props.mode)) {
|
||||
this.editor.toggleComment({ lineComment: '//', blockComment: '/*' });
|
||||
} else {
|
||||
this.editor.toggleComment();
|
||||
}
|
||||
},
|
||||
'Cmd-/': () => {
|
||||
if (['application/ld+json', 'application/json'].includes(this.props.mode)) {
|
||||
this.editor.toggleComment({ lineComment: '//', blockComment: '/*' });
|
||||
} else {
|
||||
this.editor.toggleComment();
|
||||
}
|
||||
'Cmd-/': (cm) => {
|
||||
// comment/uncomment every selected line(s)
|
||||
const selections = cm.listSelections();
|
||||
selections.forEach((range) => {
|
||||
for (let i = range.from().line; i <= range.to().line; i++) {
|
||||
const selectedLine = cm.getLine(i);
|
||||
// if commented line, remove comment
|
||||
if (selectedLine.trim().startsWith('//')) {
|
||||
cm.replaceRange(
|
||||
selectedLine.replace(/^(\s*)\/\/\s?/, '$1'),
|
||||
{ line: i, ch: 0 },
|
||||
{ line: i, ch: selectedLine.length }
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// otherwise add comment
|
||||
cm.replaceRange(
|
||||
selectedLine.search(/\S|$/) >= TAB_SIZE
|
||||
? ' '.repeat(TAB_SIZE) + '// ' + selectedLine.trim()
|
||||
: '// ' + selectedLine,
|
||||
{ line: i, ch: 0 },
|
||||
{ line: i, ch: selectedLine.length }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
foldOptions: {
|
||||
@@ -262,20 +245,17 @@ export default class CodeEditor extends React.Component {
|
||||
return found;
|
||||
}
|
||||
let jsonlint = window.jsonlint.parser || window.jsonlint;
|
||||
jsonlint.parseError = function (str, hash) {
|
||||
let loc = hash.loc;
|
||||
found.push({
|
||||
from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),
|
||||
to: CodeMirror.Pos(loc.last_line - 1, loc.last_column),
|
||||
message: str
|
||||
});
|
||||
};
|
||||
try {
|
||||
jsonlint.parse(stripJsonComments(text.replace(/(?<!"[^":{]*){{[^}]*}}(?![^"},]*")/g, '1')));
|
||||
} catch (error) {
|
||||
const { message, location } = error;
|
||||
const line = location?.start?.line;
|
||||
const column = location?.start?.column;
|
||||
if (line && column) {
|
||||
found.push({
|
||||
from: CodeMirror.Pos(line - 1, column),
|
||||
to: CodeMirror.Pos(line - 1, column),
|
||||
message
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
return found;
|
||||
});
|
||||
if (editor) {
|
||||
@@ -292,9 +272,9 @@ export default class CodeEditor extends React.Component {
|
||||
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
|
||||
//Qualify if autocomplete will be shown
|
||||
if (
|
||||
/^(?!Shift|Tab|Enter|Escape|ArrowUp|ArrowDown|ArrowLeft|ArrowRight|Meta|Alt|Home|End\s)\w*/.test(event.key) &&
|
||||
/^(?!Shift|Tab|Enter|Escape|ArrowUp|ArrowDown|ArrowLeft|ArrowRight|\s)\w*/.test(event.key) &&
|
||||
curWord.length > 0 &&
|
||||
!/\/\/|\/\*|.*{{|`[^$]*{|`[^{]*$/.test(currentLine.slice(0, end)) &&
|
||||
/(?<!\d)[a-zA-Z\._]$/.test(curWord)
|
||||
@@ -323,7 +303,7 @@ export default class CodeEditor extends React.Component {
|
||||
}
|
||||
|
||||
if (this.editor) {
|
||||
let variables = getAllVariables(this.props.collection, this.props.item);
|
||||
let variables = getEnvironmentVariables(this.props.collection);
|
||||
if (!isEqual(variables, this.variables)) {
|
||||
this.addOverlay();
|
||||
}
|
||||
@@ -350,7 +330,7 @@ export default class CodeEditor extends React.Component {
|
||||
}
|
||||
return (
|
||||
<StyledWrapper
|
||||
className="h-full w-full flex flex-col relative graphiql-container"
|
||||
className="h-full w-full flex flex-col relative"
|
||||
aria-label="Code Editor"
|
||||
font={this.props.font}
|
||||
fontSize={this.props.fontSize}
|
||||
@@ -363,10 +343,10 @@ export default class CodeEditor extends React.Component {
|
||||
|
||||
addOverlay = () => {
|
||||
const mode = this.props.mode || 'application/ld+json';
|
||||
let variables = getAllVariables(this.props.collection, this.props.item);
|
||||
let variables = getEnvironmentVariables(this.props.collection);
|
||||
this.variables = variables;
|
||||
|
||||
defineCodeMirrorBrunoVariablesMode(variables, mode, false, this.props.enableVariableHighlighting);
|
||||
defineCodeMirrorBrunoVariablesMode(variables, mode);
|
||||
this.editor.setOption('mode', 'brunovariables');
|
||||
};
|
||||
|
||||
@@ -380,10 +360,6 @@ 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
|
||||
*/
|
||||
@@ -430,8 +406,7 @@ export default class CodeEditor extends React.Component {
|
||||
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 text = new RegExp(searchInput.value, 'gi');
|
||||
const matches = this.editor.getValue().match(text);
|
||||
count = matches ? matches.length : 0;
|
||||
}
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
import React, { useRef, forwardRef, useEffect } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import get from 'lodash/get';
|
||||
import { IconCaretDown } from '@tabler/icons';
|
||||
import Dropdown from 'components/Dropdown';
|
||||
import { useTheme } from 'providers/Theme';
|
||||
import SingleLineEditor from 'components/SingleLineEditor';
|
||||
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { humanizeRequestAPIKeyPlacement } from 'utils/collections';
|
||||
|
||||
const ApiKeyAuth = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
const dropdownTippyRef = useRef();
|
||||
const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
|
||||
|
||||
const apikeyAuth = get(collection, 'root.request.auth.apikey', {});
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
const Icon = forwardRef((props, ref) => {
|
||||
return (
|
||||
<div ref={ref} className="flex items-center justify-end auth-type-label select-none">
|
||||
{humanizeRequestAPIKeyPlacement(apikeyAuth?.placement)}
|
||||
<IconCaretDown className="caret ml-1 mr-1" size={14} strokeWidth={2} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const handleAuthChange = (property, value) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'apikey',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
...apikeyAuth,
|
||||
[property]: value
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
!apikeyAuth?.placement &&
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'apikey',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
placement: 'header'
|
||||
}
|
||||
})
|
||||
);
|
||||
}, [apikeyAuth]);
|
||||
|
||||
return (
|
||||
<StyledWrapper className="mt-2 w-full">
|
||||
<label className="block font-medium mb-2">Key</label>
|
||||
<div className="single-line-editor-wrapper mb-2">
|
||||
<SingleLineEditor
|
||||
value={apikeyAuth.key || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleAuthChange('key', val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="block font-medium mb-2">Value</label>
|
||||
<div className="single-line-editor-wrapper mb-2">
|
||||
<SingleLineEditor
|
||||
value={apikeyAuth.value || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleAuthChange('value', val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="block font-medium mb-2">Add To</label>
|
||||
<div className="inline-flex items-center cursor-pointer auth-placement-selector w-fit">
|
||||
<Dropdown onCreate={onDropdownCreate} icon={<Icon />} placement="bottom-end">
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
dropdownTippyRef.current.hide();
|
||||
handleAuthChange('placement', 'header');
|
||||
}}
|
||||
>
|
||||
Header
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
dropdownTippyRef.current.hide();
|
||||
handleAuthChange('placement', 'queryparams');
|
||||
}}
|
||||
>
|
||||
Query Params
|
||||
</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ApiKeyAuth;
|
||||
@@ -52,15 +52,6 @@ const AuthMode = ({ collection }) => {
|
||||
>
|
||||
Basic Auth
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
dropdownTippyRef.current.hide();
|
||||
onModeChange('wsse');
|
||||
}}
|
||||
>
|
||||
WSSE Auth
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
@@ -79,15 +70,6 @@ const AuthMode = ({ collection }) => {
|
||||
>
|
||||
Digest Auth
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
dropdownTippyRef.current.hide();
|
||||
onModeChange('ntlm');
|
||||
}}
|
||||
>
|
||||
NTLM Auth
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
@@ -95,16 +77,7 @@ const AuthMode = ({ collection }) => {
|
||||
onModeChange('oauth2');
|
||||
}}
|
||||
>
|
||||
OAuth 2.0
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
dropdownTippyRef.current.hide();
|
||||
onModeChange('apikey');
|
||||
}}
|
||||
>
|
||||
API Key
|
||||
Oauth2
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
|
||||
@@ -1,110 +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 { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const NTLMAuth = ({ collection }) => {
|
||||
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
|
||||
const ntlmAuth = get(collection, 'root.request.auth.ntlm', {});
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
|
||||
const handleUsernameChange = (username) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'ntlm',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
username: username,
|
||||
password: ntlmAuth.password,
|
||||
domain: ntlmAuth.domain
|
||||
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handlePasswordChange = (password) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'ntlm',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
username: ntlmAuth.username,
|
||||
password: password,
|
||||
domain: ntlmAuth.domain
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleDomainChange = (domain) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'ntlm',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
username: ntlmAuth.username,
|
||||
password: ntlmAuth.password,
|
||||
domain: domain
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<StyledWrapper className="mt-2 w-full">
|
||||
<label className="block font-medium mb-2">Username</label>
|
||||
<div className="single-line-editor-wrapper mb-2">
|
||||
<SingleLineEditor
|
||||
value={ntlmAuth.username || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleUsernameChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="block font-medium mb-2">Password</label>
|
||||
<div className="single-line-editor-wrapper">
|
||||
<SingleLineEditor
|
||||
value={ntlmAuth.password || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handlePasswordChange(val)}
|
||||
collection={collection}
|
||||
isSecret={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="block font-medium mb-2">Domain</label>
|
||||
<div className="single-line-editor-wrapper">
|
||||
<SingleLineEditor
|
||||
value={ntlmAuth.domain || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleDomainChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default NTLMAuth;
|
||||
@@ -4,7 +4,6 @@ const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.single-line-editor-wrapper {
|
||||
max-width: 400px;
|
||||
padding: 0.15rem 0.4rem;
|
||||
@@ -0,0 +1,120 @@
|
||||
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;
|
||||
@@ -0,0 +1,33 @@
|
||||
const inputsConfig = [
|
||||
{
|
||||
key: 'callbackUrl',
|
||||
label: 'Callback URL'
|
||||
},
|
||||
{
|
||||
key: 'authorizationUrl',
|
||||
label: 'Authorization URL'
|
||||
},
|
||||
{
|
||||
key: 'accessTokenUrl',
|
||||
label: 'Access Token URL'
|
||||
},
|
||||
{
|
||||
key: 'clientId',
|
||||
label: 'Client ID'
|
||||
},
|
||||
{
|
||||
key: 'clientSecret',
|
||||
label: 'Client Secret',
|
||||
isSecret: true
|
||||
},
|
||||
{
|
||||
key: 'scope',
|
||||
label: 'Scope'
|
||||
},
|
||||
{
|
||||
key: 'state',
|
||||
label: 'State'
|
||||
}
|
||||
];
|
||||
|
||||
export { inputsConfig };
|
||||
@@ -4,7 +4,6 @@ const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.single-line-editor-wrapper {
|
||||
max-width: 400px;
|
||||
padding: 0.15rem 0.4rem;
|
||||
@@ -0,0 +1,70 @@
|
||||
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;
|
||||
@@ -0,0 +1,21 @@
|
||||
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 };
|
||||
@@ -1,18 +1,9 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
font-size: 0.8125rem;
|
||||
|
||||
.single-line-editor-wrapper {
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
border: solid 1px ${(props) => props.theme.input.border};
|
||||
background-color: ${(props) => props.theme.input.bg};
|
||||
}
|
||||
|
||||
.auth-placement-selector {
|
||||
.grant-type-mode-selector {
|
||||
padding: 0.5rem 0px;
|
||||
border-radius: 3px;
|
||||
border: solid 1px ${(props) => props.theme.input.border};
|
||||
@@ -35,7 +26,7 @@ const Wrapper = styled.div`
|
||||
}
|
||||
}
|
||||
|
||||
.auth-type-label {
|
||||
.grant-type-label {
|
||||
width: fit-content;
|
||||
color: ${(props) => props.theme.colors.text.yellow};
|
||||
justify-content: space-between;
|
||||
@@ -45,12 +36,19 @@ const Wrapper = styled.div`
|
||||
.dropdown-item {
|
||||
padding: 0.2rem 0.6rem !important;
|
||||
}
|
||||
|
||||
.label-item {
|
||||
padding: 0.2rem 0.6rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
.caret {
|
||||
color: rgb(140, 140, 140);
|
||||
fill: rgb(140 140 140);
|
||||
}
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
@@ -0,0 +1,98 @@
|
||||
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;
|
||||
@@ -4,7 +4,6 @@ const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.single-line-editor-wrapper {
|
||||
max-width: 400px;
|
||||
padding: 0.15rem 0.4rem;
|
||||
@@ -0,0 +1,72 @@
|
||||
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;
|
||||
@@ -0,0 +1,29 @@
|
||||
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 };
|
||||
@@ -1,33 +1,21 @@
|
||||
import React from 'react';
|
||||
import get from 'lodash/get';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
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 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', {});
|
||||
import GrantTypeSelector from './GrantTypeSelector/index';
|
||||
import OAuth2PasswordCredentials from './PasswordCredentials/index';
|
||||
import OAuth2AuthorizationCode from './AuthorizationCode/index';
|
||||
import OAuth2ClientCredentials from './ClientCredentials/index';
|
||||
|
||||
const grantTypeComponentMap = (grantType, collection) => {
|
||||
switch (grantType) {
|
||||
case 'password':
|
||||
return <OAuth2PasswordCredentials save={save} request={request} updateAuth={updateCollectionAuth} collection={collection} />;
|
||||
return <OAuth2PasswordCredentials collection={collection} />;
|
||||
break;
|
||||
case 'authorization_code':
|
||||
return <OAuth2AuthorizationCode save={save} request={request} updateAuth={updateCollectionAuth} collection={collection} />;
|
||||
return <OAuth2AuthorizationCode collection={collection} />;
|
||||
break;
|
||||
case 'client_credentials':
|
||||
return <OAuth2ClientCredentials save={save} request={request} updateAuth={updateCollectionAuth} collection={collection} />;
|
||||
return <OAuth2ClientCredentials collection={collection} />;
|
||||
break;
|
||||
default:
|
||||
return <div>TBD</div>;
|
||||
@@ -36,12 +24,12 @@ const GrantTypeComponentMap = ({collection }) => {
|
||||
};
|
||||
|
||||
const OAuth2 = ({ collection }) => {
|
||||
let request = collection.draft ? get(collection, 'draft.request', {}) : get(collection, 'root.request', {});
|
||||
const oAuth = get(collection, 'root.request.auth.oauth2', {});
|
||||
|
||||
return (
|
||||
<StyledWrapper className="mt-2 w-full">
|
||||
<GrantTypeSelector request={request} updateAuth={updateCollectionAuth} collection={collection} />
|
||||
<GrantTypeComponentMap collection={collection} />
|
||||
<GrantTypeSelector collection={collection} />
|
||||
{grantTypeComponentMap(oAuth?.grantType, collection)}
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
max-width: 800px;
|
||||
`;
|
||||
const Wrapper = styled.div``;
|
||||
|
||||
export default Wrapper;
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.single-line-editor-wrapper {
|
||||
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;
|
||||
@@ -1,71 +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 { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const WsseAuth = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
|
||||
const wsseAuth = get(collection, 'root.request.auth.wsse', {});
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
const handleUserChange = (username) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'wsse',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
username,
|
||||
password: wsseAuth.password
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handlePasswordChange = (password) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'wsse',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
username: wsseAuth.username,
|
||||
password
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="mt-2 w-full">
|
||||
<label className="block font-medium mb-2">Username</label>
|
||||
<div className="single-line-editor-wrapper mb-2">
|
||||
<SingleLineEditor
|
||||
value={wsseAuth.username || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleUserChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="block font-medium mb-2">Password</label>
|
||||
<div className="single-line-editor-wrapper">
|
||||
<SingleLineEditor
|
||||
value={wsseAuth.password || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handlePasswordChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default WsseAuth;
|
||||
@@ -6,13 +6,9 @@ import AwsV4Auth from './AwsV4Auth';
|
||||
import BearerAuth from './BearerAuth';
|
||||
import BasicAuth from './BasicAuth';
|
||||
import DigestAuth from './DigestAuth';
|
||||
import WsseAuth from './WsseAuth';
|
||||
import ApiKeyAuth from './ApiKeyAuth/';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import OAuth2 from './OAuth2';
|
||||
import NTLMAuth from './NTLMAuth';
|
||||
|
||||
|
||||
const Auth = ({ collection }) => {
|
||||
const authMode = get(collection, 'root.request.auth.mode');
|
||||
@@ -34,18 +30,9 @@ const Auth = ({ collection }) => {
|
||||
case 'digest': {
|
||||
return <DigestAuth collection={collection} />;
|
||||
}
|
||||
case 'ntlm': {
|
||||
return <NTLMAuth collection={collection} />;
|
||||
}
|
||||
case 'oauth2': {
|
||||
return <OAuth2 collection={collection} />;
|
||||
}
|
||||
case 'wsse': {
|
||||
return <WsseAuth collection={collection} />;
|
||||
}
|
||||
case 'apikey': {
|
||||
return <ApiKeyAuth collection={collection} />;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@ import { useState } from 'react';
|
||||
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { useRef } from 'react';
|
||||
import path from 'utils/common/path';
|
||||
import path from 'path';
|
||||
import slash from 'utils/common/slash';
|
||||
import { isWindowsOS } from 'utils/common/platform';
|
||||
|
||||
const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
|
||||
const certFilePathInputRef = useRef();
|
||||
@@ -25,10 +27,7 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
|
||||
passphrase: ''
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
domain: Yup.string()
|
||||
.required()
|
||||
.trim()
|
||||
.test('not-empty-after-trim', 'Domain is required', value => value && value.trim().length > 0),
|
||||
domain: Yup.string().required(),
|
||||
type: Yup.string().required().oneOf(['cert', 'pfx']),
|
||||
certFilePath: Yup.string().when('type', {
|
||||
is: (type) => type == 'cert',
|
||||
@@ -48,7 +47,7 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
|
||||
let relevantValues = {};
|
||||
if (values.type === 'cert') {
|
||||
relevantValues = {
|
||||
domain: values.domain?.trim(),
|
||||
domain: values.domain,
|
||||
type: values.type,
|
||||
certFilePath: values.certFilePath,
|
||||
keyFilePath: values.keyFilePath,
|
||||
@@ -56,7 +55,7 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
|
||||
};
|
||||
} else {
|
||||
relevantValues = {
|
||||
domain: values.domain?.trim(),
|
||||
domain: values.domain,
|
||||
type: values.type,
|
||||
pfxFilePath: values.pfxFilePath,
|
||||
passphrase: values.passphrase
|
||||
@@ -69,9 +68,13 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
|
||||
});
|
||||
|
||||
const getFile = (e) => {
|
||||
const filePath = window?.ipcRenderer?.getFilePath(e?.files?.[0]);
|
||||
if (filePath) {
|
||||
let relativePath = path.relative(root, filePath);
|
||||
if (e.files?.[0]?.path) {
|
||||
let relativePath;
|
||||
if (isWindowsOS()) {
|
||||
relativePath = slash(path.win32.relative(root, e.files[0].path));
|
||||
} else {
|
||||
relativePath = path.posix.relative(root, e.files[0].path);
|
||||
}
|
||||
formik.setFieldValue(e.name, relativePath);
|
||||
}
|
||||
};
|
||||
@@ -105,23 +108,23 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
|
||||
<ul className="mt-4">
|
||||
{!clientCertConfig.length
|
||||
? 'No client certificates added'
|
||||
: clientCertConfig.map((clientCert, index) => (
|
||||
<li key={`client-cert-${index}`} className="flex items-center available-certificates p-2 rounded-lg mb-2">
|
||||
<div className="flex items-center w-full justify-between">
|
||||
<div className="flex w-full items-center">
|
||||
<IconWorld className="mr-2" size={18} strokeWidth={1.5} />
|
||||
{clientCert.domain}
|
||||
: clientCertConfig.map((clientCert) => (
|
||||
<li key={uuid()} className="flex items-center available-certificates p-2 rounded-lg mb-2">
|
||||
<div className="flex items-center w-full justify-between">
|
||||
<div className="flex w-full items-center">
|
||||
<IconWorld className="mr-2" size={18} strokeWidth={1.5} />
|
||||
{clientCert.domain}
|
||||
</div>
|
||||
<div className="flex w-full items-center">
|
||||
<IconCertificate className="mr-2 flex-shrink-0" size={18} strokeWidth={1.5} />
|
||||
{clientCert.type === 'cert' ? clientCert.certFilePath : clientCert.pfxFilePath}
|
||||
</div>
|
||||
<button onClick={() => onRemove(clientCert)} className="remove-certificate ml-2">
|
||||
<IconTrash size={18} strokeWidth={1.5} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex w-full items-center">
|
||||
<IconCertificate className="mr-2 flex-shrink-0" size={18} strokeWidth={1.5} />
|
||||
{clientCert.type === 'cert' ? clientCert.certFilePath : clientCert.pfxFilePath}
|
||||
</div>
|
||||
<button onClick={() => onRemove(clientCert)} className="remove-certificate ml-2">
|
||||
<IconTrash size={18} strokeWidth={1.5} />
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<h1 className="font-semibold mt-8 mb-2">Add Client Certificate</h1>
|
||||
@@ -130,20 +133,15 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
|
||||
<label className="settings-label" htmlFor="domain">
|
||||
Domain
|
||||
</label>
|
||||
<div className="relative flex items-center">
|
||||
<div className="absolute left-0 pl-2 text-gray-400 pointer-events-none flex items-center h-full">
|
||||
https://
|
||||
</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>
|
||||
<input
|
||||
id="domain"
|
||||
type="text"
|
||||
name="domain"
|
||||
placeholder="*.example.org"
|
||||
className="block textbox non-passphrase-input"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.domain || ''}
|
||||
/>
|
||||
{formik.touched.domain && formik.errors.domain ? (
|
||||
<div className="ml-1 text-red-500">{formik.errors.domain}</div>
|
||||
) : null}
|
||||
@@ -199,9 +197,9 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<div
|
||||
className="my-[3px] overflow-hidden text-ellipsis whitespace-nowrap max-w-[300px]"
|
||||
title={path.basename(formik.values.certFilePath)}
|
||||
title={path.basename(slash(formik.values.certFilePath))}
|
||||
>
|
||||
{path.basename(formik.values.certFilePath)}
|
||||
{path.basename(slash(formik.values.certFilePath))}
|
||||
</div>
|
||||
<IconTrash
|
||||
size={18}
|
||||
@@ -239,9 +237,9 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<div
|
||||
className="my-[3px] overflow-hidden text-ellipsis whitespace-nowrap max-w-[300px]"
|
||||
title={path.basename(formik.values.keyFilePath)}
|
||||
title={path.basename(slash(formik.values.keyFilePath))}
|
||||
>
|
||||
{path.basename(formik.values.keyFilePath)}
|
||||
{path.basename(slash(formik.values.keyFilePath))}
|
||||
</div>
|
||||
<IconTrash
|
||||
size={18}
|
||||
@@ -282,9 +280,9 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => {
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<div
|
||||
className="my-[3px] overflow-hidden text-ellipsis whitespace-nowrap max-w-[300px]"
|
||||
title={path.basename(formik.values.pfxFilePath)}
|
||||
title={path.basename(slash(formik.values.pfxFilePath))}
|
||||
>
|
||||
{path.basename(formik.values.pfxFilePath)}
|
||||
{path.basename(slash(formik.values.pfxFilePath))}
|
||||
</div>
|
||||
<IconTrash
|
||||
size={18}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
div.CodeMirror {
|
||||
/* todo: find a better way */
|
||||
height: calc(100vh - 240px);
|
||||
|
||||
.CodeMirror-scroll {
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
}
|
||||
.editing-mode {
|
||||
cursor: pointer;
|
||||
color: ${(props) => props.theme.colors.text.yellow};
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/acti
|
||||
import Markdown from 'components/MarkDown';
|
||||
import CodeEditor from 'components/CodeEditor';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { IconEdit, IconX, IconFileText } from '@tabler/icons';
|
||||
|
||||
const Docs = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
@@ -30,50 +29,19 @@ const Docs = ({ collection }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const handleDiscardChanges = () => {
|
||||
dispatch(
|
||||
updateCollectionDocs({
|
||||
collectionUid: collection.uid,
|
||||
docs: docs
|
||||
})
|
||||
);
|
||||
toggleViewMode();
|
||||
}
|
||||
|
||||
const onSave = () => {
|
||||
dispatch(saveCollectionRoot(collection.uid));
|
||||
toggleViewMode();
|
||||
}
|
||||
const onSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
return (
|
||||
<StyledWrapper className="mt-1 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} />
|
||||
Documentation
|
||||
</div>
|
||||
<div className='flex flex-row gap-2 items-center justify-center'>
|
||||
{isEditing ? (
|
||||
<>
|
||||
<div className="editing-mode" role="tab" onClick={handleDiscardChanges}>
|
||||
<IconX className="cursor-pointer" size={20} strokeWidth={1.5} />
|
||||
</div>
|
||||
<button type="submit" className="submit btn btn-sm btn-secondary" onClick={onSave}>
|
||||
Save
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<div className="editing-mode" role="tab" onClick={toggleViewMode}>
|
||||
<IconEdit className="cursor-pointer" size={20} strokeWidth={1.5} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<StyledWrapper className="mt-1 h-full w-full relative">
|
||||
<div className="editing-mode mb-2" role="tab" onClick={toggleViewMode}>
|
||||
{isEditing ? 'Preview' : 'Edit'}
|
||||
</div>
|
||||
|
||||
{isEditing ? (
|
||||
<CodeEditor
|
||||
collection={collection}
|
||||
theme={displayedTheme}
|
||||
value={docs}
|
||||
value={docs || ''}
|
||||
onEdit={onEdit}
|
||||
onSave={onSave}
|
||||
mode="application/text"
|
||||
@@ -81,44 +49,10 @@ const Docs = ({ collection }) => {
|
||||
fontSize={get(preferences, 'font.codeFontSize')}
|
||||
/>
|
||||
) : (
|
||||
<div className='h-full overflow-auto pl-1'>
|
||||
<div className='h-[1px] min-h-[500px]'>
|
||||
{
|
||||
docs?.length > 0 ?
|
||||
<Markdown collectionPath={collection.pathname} onDoubleClick={toggleViewMode} content={docs} />
|
||||
:
|
||||
<Markdown collectionPath={collection.pathname} onDoubleClick={toggleViewMode} content={documentationPlaceholder} />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<Markdown collectionPath={collection.pathname} onDoubleClick={toggleViewMode} content={docs} />
|
||||
)}
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Docs;
|
||||
|
||||
|
||||
const documentationPlaceholder = `
|
||||
Welcome to your collection documentation! This space is designed to help you document your API collection effectively.
|
||||
|
||||
## Overview
|
||||
Use this section to provide a high-level overview of your collection. You can describe:
|
||||
- The purpose of these API endpoints
|
||||
- Key features and functionalities
|
||||
- Target audience or users
|
||||
|
||||
## Best Practices
|
||||
- Keep documentation up to date
|
||||
- Include request/response examples
|
||||
- Document error scenarios
|
||||
- Add relevant links and references
|
||||
|
||||
## Markdown Support
|
||||
This documentation supports Markdown formatting! You can use:
|
||||
- **Bold** and *italic* text
|
||||
- \`code blocks\` and syntax highlighting
|
||||
- Tables and lists
|
||||
- [Links](https://usebruno.com)
|
||||
- And more!
|
||||
`;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
max-width: 800px;
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
button.btn-create-environment {
|
||||
&:hover {
|
||||
span {
|
||||
text-decoration: underline;
|
||||
table {
|
||||
td {
|
||||
&:first-child {
|
||||
width: 120px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { getTotalRequestCountInCollection } from 'utils/collections/';
|
||||
|
||||
const Info = ({ collection }) => {
|
||||
const totalRequestsInCollection = getTotalRequestCountInCollection(collection);
|
||||
|
||||
return (
|
||||
<StyledWrapper className="w-full flex flex-col h-full">
|
||||
<div className="text-xs mb-4 text-muted">General information about the collection.</div>
|
||||
<table className="w-full border-collapse">
|
||||
<tbody>
|
||||
<tr className="">
|
||||
<td className="py-2 px-2 text-right">Name :</td>
|
||||
<td className="py-2 px-2">{collection.name}</td>
|
||||
</tr>
|
||||
<tr className="">
|
||||
<td className="py-2 px-2 text-right">Location :</td>
|
||||
<td className="py-2 px-2 break-all">{collection.pathname}</td>
|
||||
</tr>
|
||||
<tr className="">
|
||||
<td className="py-2 px-2 text-right">Ignored files :</td>
|
||||
<td className="py-2 px-2 break-all">{collection.brunoConfig?.ignore?.map((x) => `'${x}'`).join(', ')}</td>
|
||||
</tr>
|
||||
<tr className="">
|
||||
<td className="py-2 px-2 text-right">Environments :</td>
|
||||
<td className="py-2 px-2">{collection.environments?.length || 0}</td>
|
||||
</tr>
|
||||
<tr className="">
|
||||
<td className="py-2 px-2 text-right">Requests :</td>
|
||||
<td className="py-2 px-2">{totalRequestsInCollection}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Info;
|
||||
@@ -1,82 +0,0 @@
|
||||
import React from "react";
|
||||
import { getTotalRequestCountInCollection } from 'utils/collections/';
|
||||
import { IconFolder, IconWorld, IconApi, IconShare } from '@tabler/icons';
|
||||
import { areItemsLoading, getItemsLoadStats } from "utils/collections/index";
|
||||
import { useState } from "react";
|
||||
import ShareCollection from "components/ShareCollection/index";
|
||||
|
||||
const Info = ({ collection }) => {
|
||||
const totalRequestsInCollection = getTotalRequestCountInCollection(collection);
|
||||
|
||||
const isCollectionLoading = areItemsLoading(collection);
|
||||
const { loading: itemsLoadingCount, total: totalItems } = getItemsLoadStats(collection);
|
||||
const [showShareCollectionModal, toggleShowShareCollectionModal] = useState(false);
|
||||
|
||||
const handleToggleShowShareCollectionModal = (value) => (e) => {
|
||||
toggleShowShareCollectionModal(value);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full flex flex-col h-fit">
|
||||
<div className="rounded-lg py-6">
|
||||
<div className="grid gap-6">
|
||||
{/* Location Row */}
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 p-3 bg-blue-50 dark:bg-blue-900/20 rounded-lg">
|
||||
<IconFolder className="w-5 h-5 text-blue-500" stroke={1.5} />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<div className="font-semibold text-sm">Location</div>
|
||||
<div className="mt-1 text-sm text-muted break-all">
|
||||
{collection.pathname}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Environments Row */}
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 p-3 bg-green-50 dark:bg-green-900/20 rounded-lg">
|
||||
<IconWorld className="w-5 h-5 text-green-500" stroke={1.5} />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<div className="font-semibold text-sm">Environments</div>
|
||||
<div className="mt-1 text-sm text-muted">
|
||||
{collection.environments?.length || 0} environment{collection.environments?.length !== 1 ? 's' : ''} configured
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Requests Row */}
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0 p-3 bg-purple-50 dark:bg-purple-900/20 rounded-lg">
|
||||
<IconApi className="w-5 h-5 text-purple-500" stroke={1.5} />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<div className="font-semibold text-sm">Requests</div>
|
||||
<div className="mt-1 text-sm text-muted font-mono">
|
||||
{
|
||||
isCollectionLoading? `${totalItems - itemsLoadingCount} out of ${totalItems} requests in the collection loaded` : `${totalRequestsInCollection} request${totalRequestsInCollection !== 1 ? 's' : ''} in collection`
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start group cursor-pointer" onClick={handleToggleShowShareCollectionModal(true)}>
|
||||
<div className="flex-shrink-0 p-3 bg-indigo-50 dark:bg-indigo-900/20 rounded-lg">
|
||||
<IconShare className="w-5 h-5 text-indigo-500" stroke={1.5} />
|
||||
</div>
|
||||
<div className="ml-4 h-full flex flex-col justify-start">
|
||||
<div className="font-semibold text-sm h-fit my-auto">Share</div>
|
||||
<div className="mt-1 text-sm group-hover:underline text-link">
|
||||
Share Collection
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{showShareCollectionModal && <ShareCollection collectionUid={collection.uid} onClose={handleToggleShowShareCollectionModal(false)} />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Info;
|
||||
@@ -1,25 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
&.card {
|
||||
background-color: ${(props) => props.theme.requestTabPanel.card.bg};
|
||||
|
||||
.title {
|
||||
border-top: 1px solid ${(props) => props.theme.requestTabPanel.cardTable.border};
|
||||
border-left: 1px solid ${(props) => props.theme.requestTabPanel.cardTable.border};
|
||||
border-right: 1px solid ${(props) => props.theme.requestTabPanel.cardTable.border};
|
||||
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
|
||||
.table {
|
||||
thead {
|
||||
background-color: ${(props) => props.theme.requestTabPanel.cardTable.table.thead.bg};
|
||||
color: ${(props) => props.theme.requestTabPanel.cardTable.table.thead.color};
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
@@ -1,80 +0,0 @@
|
||||
import React from 'react';
|
||||
import { flattenItems } from "utils/collections";
|
||||
import { IconAlertTriangle } from '@tabler/icons';
|
||||
import StyledWrapper from "./StyledWrapper";
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { isItemARequest, itemIsOpenedInTabs } from 'utils/tabs/index';
|
||||
import { getDefaultRequestPaneTab } from 'utils/collections/index';
|
||||
import { addTab, focusTab } from 'providers/ReduxStore/slices/tabs';
|
||||
import { hideHomePage } from 'providers/ReduxStore/slices/app';
|
||||
|
||||
const RequestsNotLoaded = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const tabs = useSelector((state) => state.tabs.tabs);
|
||||
const flattenedItems = flattenItems(collection.items);
|
||||
const itemsFailedLoading = flattenedItems?.filter(item => item?.partial && !item?.loading);
|
||||
|
||||
if (!itemsFailedLoading?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleRequestClick = (item) => e => {
|
||||
e.preventDefault();
|
||||
if (isItemARequest(item)) {
|
||||
dispatch(hideHomePage());
|
||||
if (itemIsOpenedInTabs(item, tabs)) {
|
||||
dispatch(
|
||||
focusTab({
|
||||
uid: item.uid
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
dispatch(
|
||||
addTab({
|
||||
uid: item.uid,
|
||||
collectionUid: collection.uid,
|
||||
requestPaneTab: getDefaultRequestPaneTab(item)
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledWrapper className="w-full card my-2">
|
||||
<div className="flex items-center gap-2 px-3 py-2 title bg-yellow-50 dark:bg-yellow-900/20">
|
||||
<IconAlertTriangle size={16} className="text-yellow-500" />
|
||||
<span className="font-medium">Following requests were not loaded</span>
|
||||
</div>
|
||||
<table className="w-full border-collapse">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="py-2 px-3 text-left font-medium">
|
||||
Pathname
|
||||
</th>
|
||||
<th className="py-2 px-3 text-left font-medium">
|
||||
Size
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{flattenedItems?.map((item, index) => (
|
||||
item?.partial && !item?.loading ? (
|
||||
<tr key={index} className='cursor-pointer' onClick={handleRequestClick(item)}>
|
||||
<td className="py-1.5 px-3">
|
||||
{item?.pathname?.split(`${collection?.pathname}/`)?.[1]}
|
||||
</td>
|
||||
<td className="py-1.5 px-3">
|
||||
{item?.size?.toFixed?.(2)} MB
|
||||
</td>
|
||||
</tr>
|
||||
) : null
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default RequestsNotLoaded;
|
||||
@@ -1,25 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
.partial {
|
||||
color: ${(props) => props.theme.colors.text.yellow};
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.loading {
|
||||
color: ${(props) => props.theme.colors.text.muted};
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.completed {
|
||||
color: ${(props) => props.theme.colors.text.green};
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.failed {
|
||||
color: ${(props) => props.theme.colors.text.danger};
|
||||
opacity: 0.8;
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
@@ -1,27 +0,0 @@
|
||||
import StyledWrapper from "./StyledWrapper";
|
||||
import Docs from "../Docs";
|
||||
import Info from "./Info";
|
||||
import { IconBox } from '@tabler/icons';
|
||||
import RequestsNotLoaded from "./RequestsNotLoaded";
|
||||
|
||||
const Overview = ({ collection }) => {
|
||||
return (
|
||||
<div className="h-full">
|
||||
<div className="grid grid-cols-5 gap-4 h-full">
|
||||
<div className="col-span-2">
|
||||
<div className="text-xl font-semibold flex items-center gap-2">
|
||||
<IconBox size={24} stroke={1.5} />
|
||||
{collection?.name}
|
||||
</div>
|
||||
<Info collection={collection} />
|
||||
<RequestsNotLoaded collection={collection} />
|
||||
</div>
|
||||
<div className="col-span-3">
|
||||
<Docs collection={collection} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Overview;
|
||||
@@ -1,8 +1,6 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
max-width: 800px;
|
||||
|
||||
.settings-label {
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
@@ -104,15 +104,18 @@ const ProxySettings = ({ proxyConfig, onUpdate }) => {
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label flex items-center" htmlFor="enabled">
|
||||
Config
|
||||
<InfoTip infotipId="request-var">
|
||||
<InfoTip
|
||||
text={`
|
||||
<div>
|
||||
<ul>
|
||||
<li><span style={{width: "50px", display: "inline-block"}}>global</span> - use global proxy config</li>
|
||||
<li><span style={{width: "50px", display: "inline-block"}}>enabled</span> - use collection proxy config</li>
|
||||
<li><span style={{width: "50px", display: "inline-block"}}>disable</span> - disable proxy</li>
|
||||
<li><span style="width: 50px;display:inline-block;">global</span> - use global proxy config</li>
|
||||
<li><span style="width: 50px;display:inline-block;">enabled</span> - use collection proxy config</li>
|
||||
<li><span style="width: 50px;display:inline-block;">disable</span> - disable proxy</li>
|
||||
</ul>
|
||||
</div>
|
||||
</InfoTip>
|
||||
`}
|
||||
infotipId="request-var"
|
||||
/>
|
||||
</label>
|
||||
<div className="flex items-center">
|
||||
<label className="flex items-center">
|
||||
@@ -333,4 +336,4 @@ const ProxySettings = ({ proxyConfig, onUpdate }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default ProxySettings;
|
||||
export default ProxySettings;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
max-width: 800px;
|
||||
|
||||
div.CodeMirror {
|
||||
height: inherit;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
max-width: 800px;
|
||||
|
||||
div.tabs {
|
||||
div.tab {
|
||||
padding: 6px 0px;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
max-width: 800px;
|
||||
`;
|
||||
const StyledWrapper = styled.div``;
|
||||
|
||||
export default StyledWrapper;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
max-width: 800px;
|
||||
|
||||
div.title {
|
||||
color: var(--color-tab-inactive);
|
||||
}
|
||||
|
||||
@@ -83,13 +83,14 @@ const VarsTable = ({ collection, vars, varType }) => {
|
||||
<td>
|
||||
<div className="flex items-center">
|
||||
<span>Value</span>
|
||||
<InfoTip text="You can write any valid JS Template Literal here" infotipId="request-var" />
|
||||
</div>
|
||||
</td>
|
||||
) : (
|
||||
<td>
|
||||
<div className="flex items-center">
|
||||
<span>Expr</span>
|
||||
<InfoTip content="You can write any valid JS Template Literal here" infotipId="request-var" />
|
||||
<InfoTip text="You can write any valid JS Template Literal here" infotipId="request-var" />
|
||||
</div>
|
||||
</td>
|
||||
)}
|
||||
|
||||
@@ -12,19 +12,11 @@ import Headers from './Headers';
|
||||
import Auth from './Auth';
|
||||
import Script from './Script';
|
||||
import Test from './Tests';
|
||||
import Docs from './Docs';
|
||||
import Presets from './Presets';
|
||||
import Info from './Info';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import Vars from './Vars/index';
|
||||
import DotIcon from 'components/Icons/Dot';
|
||||
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();
|
||||
@@ -38,22 +30,9 @@ const CollectionSettings = ({ collection }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const root = collection?.root;
|
||||
const hasScripts = root?.request?.script?.res || root?.request?.script?.req;
|
||||
const hasTests = root?.request?.tests;
|
||||
const hasDocs = root?.docs;
|
||||
|
||||
const headers = get(collection, 'root.request.headers', []);
|
||||
const activeHeadersCount = headers.filter((header) => header.enabled).length;
|
||||
|
||||
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 authMode = get(collection, 'root.request.auth', {}).mode || 'none';
|
||||
|
||||
const proxyConfig = get(collection, 'brunoConfig.proxy', {});
|
||||
const clientCertConfig = get(collection, 'brunoConfig.clientCertificates.certs', []);
|
||||
|
||||
const clientCertConfig = get(collection, 'brunoConfig.clientCertificates.certs', []);
|
||||
|
||||
const onProxySettingsUpdate = (config) => {
|
||||
const brunoConfig = cloneDeep(collection.brunoConfig);
|
||||
@@ -96,9 +75,6 @@ const CollectionSettings = ({ collection }) => {
|
||||
|
||||
const getTabPanel = (tab) => {
|
||||
switch (tab) {
|
||||
case 'overview': {
|
||||
return <Overview collection={collection} />;
|
||||
}
|
||||
case 'headers': {
|
||||
return <Headers collection={collection} />;
|
||||
}
|
||||
@@ -130,6 +106,12 @@ const CollectionSettings = ({ collection }) => {
|
||||
/>
|
||||
);
|
||||
}
|
||||
case 'docs': {
|
||||
return <Docs collection={collection} />;
|
||||
}
|
||||
case 'info': {
|
||||
return <Info collection={collection} />;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -142,39 +124,35 @@ const CollectionSettings = ({ collection }) => {
|
||||
return (
|
||||
<StyledWrapper className="flex flex-col h-full relative px-4 py-4">
|
||||
<div className="flex flex-wrap items-center tabs" role="tablist">
|
||||
<div className={getTabClassname('overview')} role="tab" onClick={() => setTab('overview')}>
|
||||
Overview
|
||||
</div>
|
||||
<div className={getTabClassname('headers')} role="tab" onClick={() => setTab('headers')}>
|
||||
Headers
|
||||
{activeHeadersCount > 0 && <sup className="ml-1 font-medium">{activeHeadersCount}</sup>}
|
||||
</div>
|
||||
<div className={getTabClassname('vars')} role="tab" onClick={() => setTab('vars')}>
|
||||
Vars
|
||||
{activeVarsCount > 0 && <sup className="ml-1 font-medium">{activeVarsCount}</sup>}
|
||||
</div>
|
||||
<div className={getTabClassname('auth')} role="tab" onClick={() => setTab('auth')}>
|
||||
Auth
|
||||
{authMode !== 'none' && <ContentIndicator />}
|
||||
</div>
|
||||
<div className={getTabClassname('script')} role="tab" onClick={() => setTab('script')}>
|
||||
Script
|
||||
{hasScripts && <ContentIndicator />}
|
||||
</div>
|
||||
<div className={getTabClassname('tests')} role="tab" onClick={() => setTab('tests')}>
|
||||
Tests
|
||||
{hasTests && <ContentIndicator />}
|
||||
</div>
|
||||
<div className={getTabClassname('presets')} role="tab" onClick={() => setTab('presets')}>
|
||||
Presets
|
||||
</div>
|
||||
<div className={getTabClassname('proxy')} role="tab" onClick={() => setTab('proxy')}>
|
||||
Proxy
|
||||
{Object.keys(proxyConfig).length > 0 && <ContentIndicator />}
|
||||
</div>
|
||||
<div className={getTabClassname('clientCert')} role="tab" onClick={() => setTab('clientCert')}>
|
||||
Client Certificates
|
||||
{clientCertConfig.length > 0 && <ContentIndicator />}
|
||||
</div>
|
||||
<div className={getTabClassname('docs')} role="tab" onClick={() => setTab('docs')}>
|
||||
Docs
|
||||
</div>
|
||||
<div className={getTabClassname('info')} role="tab" onClick={() => setTab('info')}>
|
||||
Info
|
||||
</div>
|
||||
</div>
|
||||
<section className="mt-4 h-full">{getTabPanel(tab)}</section>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user