mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-04 01:48:33 +00:00
Compare commits
372 Commits
v1.3.2
...
feat/path-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e71e605ea | ||
|
|
e149c8dc9a | ||
|
|
411289daa8 | ||
|
|
60cf012cbe | ||
|
|
392cc80db2 | ||
|
|
d7c0f489f6 | ||
|
|
2569a1389d | ||
|
|
fe5816eb9a | ||
|
|
23704a0800 | ||
|
|
c17e4effe7 | ||
|
|
16861c9889 | ||
|
|
87404132ae | ||
|
|
7019a77ec6 | ||
|
|
ad9169d78a | ||
|
|
54e99cbbd7 | ||
|
|
eb9862b8f5 | ||
|
|
7a3cc4e040 | ||
|
|
60cb9da83e | ||
|
|
28e4159c21 | ||
|
|
59ffb0166f | ||
|
|
e8ec74107d | ||
|
|
d027d90ed5 | ||
|
|
7bbc4727be | ||
|
|
386a8df151 | ||
|
|
2ed35108d7 | ||
|
|
a0860febee | ||
|
|
bc70bba0b6 | ||
|
|
d0a1621734 | ||
|
|
dce792accd | ||
|
|
535d6e0389 | ||
|
|
ac610f9ea3 | ||
|
|
12263a71b6 | ||
|
|
4e95fd548d | ||
|
|
23674fffbc | ||
|
|
eddac73341 | ||
|
|
b5a1c80496 | ||
|
|
24e58168e0 | ||
|
|
31137ef466 | ||
|
|
92dcc06051 | ||
|
|
f3fe0ee736 | ||
|
|
00c0e418a9 | ||
|
|
2ae71b0ec0 | ||
|
|
0333a41eea | ||
|
|
1f786871b8 | ||
|
|
9ee6f9a8cc | ||
|
|
6c8c87fe28 | ||
|
|
c9e40cbc94 | ||
|
|
4f7c295b88 | ||
|
|
acca7984a4 | ||
|
|
0cce14b4d5 | ||
|
|
179c30b15b | ||
|
|
5a31daf84a | ||
|
|
920c490548 | ||
|
|
484f6ef0c1 | ||
|
|
e7ff0ba5a8 | ||
|
|
615ed0c584 | ||
|
|
0173d8812d | ||
|
|
65dbf9c8ba | ||
|
|
67df18e6e0 | ||
|
|
aa5fee01c3 | ||
|
|
84128052c0 | ||
|
|
fbee23329d | ||
|
|
5b2ca0ea03 | ||
|
|
cf08118458 | ||
|
|
17dac6be67 | ||
|
|
64b90b4cc3 | ||
|
|
2c83e98502 | ||
|
|
ce5dd41267 | ||
|
|
1349a79750 | ||
|
|
c20beab0a0 | ||
|
|
5539cc1a2d | ||
|
|
d20de4da0a | ||
|
|
50e3943fb1 | ||
|
|
c357d3da4b | ||
|
|
9b89f33103 | ||
|
|
0f69c30a86 | ||
|
|
753ca4341f | ||
|
|
e278116356 | ||
|
|
ae3c76a6c1 | ||
|
|
0b2b16abcc | ||
|
|
8503752e09 | ||
|
|
9b7cdb2d48 | ||
|
|
7741a3e4ee | ||
|
|
82c600a0e6 | ||
|
|
f8ba781340 | ||
|
|
f96f763f14 | ||
|
|
a546457e0f | ||
|
|
2b0ad29b93 | ||
|
|
cdbb15f33e | ||
|
|
14911b4def | ||
|
|
410eecc884 | ||
|
|
2cd0e065bd | ||
|
|
d0c7c872c9 | ||
|
|
63684afbff | ||
|
|
13eef748e1 | ||
|
|
dbe41e7f59 | ||
|
|
c00bfb0ce4 | ||
|
|
09aefffc47 | ||
|
|
6629d5a2c8 | ||
|
|
3ee76067fb | ||
|
|
e6090a4d59 | ||
|
|
c257603e17 | ||
|
|
ee441d2ab6 | ||
|
|
6a2754d4fb | ||
|
|
b0f4491cd2 | ||
|
|
1fca217046 | ||
|
|
5ec2475f31 | ||
|
|
f1b80ba0ff | ||
|
|
475b585fdd | ||
|
|
95b59b06e8 | ||
|
|
6a05321109 | ||
|
|
86ddd2b9b0 | ||
|
|
80142dbfcd | ||
|
|
3683d4c1df | ||
|
|
3ef8135173 | ||
|
|
e7dacde46a | ||
|
|
5f35d71b8b | ||
|
|
e2d1f52993 | ||
|
|
cc02794ce9 | ||
|
|
858536e13d | ||
|
|
9d3df0a86a | ||
|
|
0e85b302b8 | ||
|
|
3b51621580 | ||
|
|
18e7301550 | ||
|
|
96bcc7074a | ||
|
|
f64e13a71f | ||
|
|
01360d1522 | ||
|
|
6729d718cf | ||
|
|
17abc19770 | ||
|
|
13cb71eaef | ||
|
|
b375620875 | ||
|
|
1cf8a2f3f1 | ||
|
|
7c416a99ef | ||
|
|
389a383b99 | ||
|
|
d1a8f59c79 | ||
|
|
d477cfc7e1 | ||
|
|
e66e26d115 | ||
|
|
7a635810b1 | ||
|
|
dde6695a43 | ||
|
|
9f81e6dc73 | ||
|
|
3c2cbe63c4 | ||
|
|
a4b13d5c2a | ||
|
|
064281d438 | ||
|
|
43c873422f | ||
|
|
c7c762185e | ||
|
|
09c496e516 | ||
|
|
117726a01f | ||
|
|
e2d754702a | ||
|
|
fee3416c85 | ||
|
|
a756c49285 | ||
|
|
b6abc665a5 | ||
|
|
bd002ca316 | ||
|
|
5fece08f4b | ||
|
|
36b7fbe584 | ||
|
|
8cb6060558 | ||
|
|
50228d2f50 | ||
|
|
ea5993fa76 | ||
|
|
485b2f48bc | ||
|
|
f8eac3469f | ||
|
|
2877a88a8a | ||
|
|
b9d50fbba0 | ||
|
|
942a895ae0 | ||
|
|
eab50f01d7 | ||
|
|
8287126deb | ||
|
|
d05a86252b | ||
|
|
1f4171d22a | ||
|
|
7c314d0fed | ||
|
|
3c87c1df69 | ||
|
|
64487ad923 | ||
|
|
808af3c19a | ||
|
|
7cf5f0d612 | ||
|
|
a69f7ab2a8 | ||
|
|
966718ca66 | ||
|
|
659e22cabf | ||
|
|
aedcaac2bb | ||
|
|
1900bddd37 | ||
|
|
33d5d78e85 | ||
|
|
12b9a02f7e | ||
|
|
7c6a043188 | ||
|
|
a904672555 | ||
|
|
123bf198a3 | ||
|
|
cb95b5f36a | ||
|
|
09e7ea0d4d | ||
|
|
634f9ca4a2 | ||
|
|
a97adbb97e | ||
|
|
4d8c377143 | ||
|
|
7b6c72c63b | ||
|
|
72fde80577 | ||
|
|
c666adc0ba | ||
|
|
ea7d141d10 | ||
|
|
73c0d058c5 | ||
|
|
c39b8ff282 | ||
|
|
e258e7f5ab | ||
|
|
c48cb56709 | ||
|
|
59b9208d89 | ||
|
|
cfbac39ba8 | ||
|
|
28d781a52d | ||
|
|
3843cf8ee3 | ||
|
|
34ede8a33f | ||
|
|
0e24efbd88 | ||
|
|
555387598a | ||
|
|
0dd8154d8b | ||
|
|
467e63d6fa | ||
|
|
d999366a16 | ||
|
|
acc646a05d | ||
|
|
969c44023f | ||
|
|
abeccbb182 | ||
|
|
c0b5136359 | ||
|
|
d31147961d | ||
|
|
a077d65a3e | ||
|
|
c3f6318d69 | ||
|
|
58dfdd8157 | ||
|
|
4917f24b7c | ||
|
|
00e11e3177 | ||
|
|
54d4a74355 | ||
|
|
65b76b7281 | ||
|
|
ad1b0950bc | ||
|
|
775809f59e | ||
|
|
7ba9b839da | ||
|
|
c5986896d1 | ||
|
|
f5a1213e0f | ||
|
|
de96076de7 | ||
|
|
8ada457bfc | ||
|
|
a7253f1579 | ||
|
|
a0beefa9bc | ||
|
|
1bc2c8d0a6 | ||
|
|
80806fef30 | ||
|
|
2a6bfabc30 | ||
|
|
f2a187d5fe | ||
|
|
aed1b41da6 | ||
|
|
d8354dca14 | ||
|
|
e375ffbed1 | ||
|
|
7de5bbbdf6 | ||
|
|
dbb5e912eb | ||
|
|
4e34aba1ca | ||
|
|
b5fccef417 | ||
|
|
db9aeec498 | ||
|
|
3e627522b7 | ||
|
|
85f24eec77 | ||
|
|
bdfcd78f3a | ||
|
|
fce164001b | ||
|
|
814d31e638 | ||
|
|
51d4dbd69b | ||
|
|
05cab18e18 | ||
|
|
fcc3a1e944 | ||
|
|
45395754bf | ||
|
|
0db6103b69 | ||
|
|
2608ec035e | ||
|
|
d0c25d46c9 | ||
|
|
d62982d52d | ||
|
|
2810c6758d | ||
|
|
3967859c51 | ||
|
|
ef5df9e114 | ||
|
|
75e19574ac | ||
|
|
b15ad5ca71 | ||
|
|
0bd3ba493f | ||
|
|
d2d1994546 | ||
|
|
e4ae0c0357 | ||
|
|
52cec963a3 | ||
|
|
f797c5d06b | ||
|
|
65879c8994 | ||
|
|
2e544183db | ||
|
|
ceccddf7f1 | ||
|
|
c1f5da1280 | ||
|
|
63aa3ded1c | ||
|
|
26c7d4f532 | ||
|
|
b7b4453278 | ||
|
|
49a51d6028 | ||
|
|
abb24c93c5 | ||
|
|
5ba2c98e1d | ||
|
|
bc01188c98 | ||
|
|
1754ea9f59 | ||
|
|
2aa073c69a | ||
|
|
48ec87ec8c | ||
|
|
35b6f7bb0a | ||
|
|
fff0293600 | ||
|
|
41d0698a87 | ||
|
|
f7ea8c93a6 | ||
|
|
83c9629820 | ||
|
|
d6f6032c6f | ||
|
|
e49999bb56 | ||
|
|
8b92055413 | ||
|
|
5ca7f6b7ad | ||
|
|
83f5763e01 | ||
|
|
4a5196c8f5 | ||
|
|
eba065aa7e | ||
|
|
10dc1d95b0 | ||
|
|
00c7b40593 | ||
|
|
b0ee137277 | ||
|
|
887c65b0d8 | ||
|
|
84905ed80f | ||
|
|
1f4ab3b5bd | ||
|
|
da983599ab | ||
|
|
fe11e45703 | ||
|
|
a08fd7eb52 | ||
|
|
d268b4786a | ||
|
|
4b76bf85f4 | ||
|
|
ed6f91533b | ||
|
|
7899b04c40 | ||
|
|
cdddf8af76 | ||
|
|
9e44c4a95f | ||
|
|
3982f9c3c3 | ||
|
|
46dda28c3a | ||
|
|
9f6890b769 | ||
|
|
eb340d4ace | ||
|
|
66f917ecec | ||
|
|
e3865d4710 | ||
|
|
983fb2c4fd | ||
|
|
cb6513c580 | ||
|
|
b8451d01ca | ||
|
|
a15a4e4a2d | ||
|
|
cada4f201a | ||
|
|
93661bd0d2 | ||
|
|
454e0e5260 | ||
|
|
647a819051 | ||
|
|
99c2dd9030 | ||
|
|
ab37e53346 | ||
|
|
8ace37848b | ||
|
|
447f40053d | ||
|
|
de530a889c | ||
|
|
882341c35b | ||
|
|
174f99f9fb | ||
|
|
2103ab20bf | ||
|
|
f0e22cb5df | ||
|
|
ee2295aec1 | ||
|
|
2d16e07747 | ||
|
|
a839d311dc | ||
|
|
82bafd5268 | ||
|
|
fc09697404 | ||
|
|
ee2d7a187a | ||
|
|
f8ff305cf4 | ||
|
|
c2c2ef6e2b | ||
|
|
aa18f17fb9 | ||
|
|
baeeeb2bb0 | ||
|
|
fff3e6d88a | ||
|
|
7953863b9d | ||
|
|
10183319c4 | ||
|
|
89c5fc2f03 | ||
|
|
8ddec6bf0c | ||
|
|
d257db27b8 | ||
|
|
08935c64bb | ||
|
|
8e1d04f5c1 | ||
|
|
da3bd95add | ||
|
|
cc89e34b4c | ||
|
|
56a456a9b6 | ||
|
|
eaa448306b | ||
|
|
9f8dba0fb2 | ||
|
|
784f63ca5b | ||
|
|
77cdc2179d | ||
|
|
d749e4b848 | ||
|
|
bb729b5793 | ||
|
|
a60f351736 | ||
|
|
0d0c4166c1 | ||
|
|
567744c2ce | ||
|
|
cb47b7be5f | ||
|
|
3061507284 | ||
|
|
d3bec5631e | ||
|
|
98b45a2fd4 | ||
|
|
1c83f5c885 | ||
|
|
1ee6b5f974 | ||
|
|
8130de23ff | ||
|
|
8183ce03c5 | ||
|
|
129d659628 | ||
|
|
db0de68987 | ||
|
|
631e436079 | ||
|
|
dc32d7246c | ||
|
|
76a26b634d | ||
|
|
820e3033ea | ||
|
|
d76253ea04 | ||
|
|
4a1d45f458 | ||
|
|
3374db1ac8 | ||
|
|
d4c0207545 |
34
.github/ISSUE_TEMPLATE/BugReport.yaml
vendored
Normal file
34
.github/ISSUE_TEMPLATE/BugReport.yaml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Bug Report
|
||||
description: File a bug report
|
||||
labels: ['bug']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 'I have checked the following:'
|
||||
options:
|
||||
- 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: textarea
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
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 reqroduce the problem.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshots/Live demo link
|
||||
description: Add some screenshots to help explain the problem.
|
||||
validations:
|
||||
required: true
|
||||
26
.github/ISSUE_TEMPLATE/FeatureRequest.yaml
vendored
Normal file
26
.github/ISSUE_TEMPLATE/FeatureRequest.yaml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Feature Request
|
||||
description: Suggest an idea for this project.
|
||||
labels: ['enhancement']
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 'I have checked the following:'
|
||||
options:
|
||||
- label: I've searched existing issues and found nothing related to my issue.
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Suggest an idea for this project.
|
||||
- type: textarea
|
||||
attributes:
|
||||
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
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Mockups or Images of the feature
|
||||
description: Add some images to support your feature.
|
||||
validations:
|
||||
required: true
|
||||
8
.github/ISSUE_TEMPLATE/config.yaml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Discussions
|
||||
url: https://github.com/usebruno/bruno/discussions
|
||||
about: You can ask general questions or give feedback here.
|
||||
- name: Discord Server
|
||||
url: https://discord.com/invite/KgcZUncpjq
|
||||
about: Join our Discord community to chat about Bruno.
|
||||
12
.github/workflows/bump-homebrew-cask.yml
vendored
12
.github/workflows/bump-homebrew-cask.yml
vendored
@@ -1,12 +0,0 @@
|
||||
name: Bump Homebrew Cask
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
bump:
|
||||
runs-on: macos-10.15
|
||||
steps:
|
||||
- name: Bump Homebrew Cask
|
||||
run: brew bump-cask-pr bruno --version "${GITHUB_REF_NAME#v}"
|
||||
48
.github/workflows/npm-bru-cli.yml
vendored
Normal file
48
.github/workflows/npm-bru-cli.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Bru CLI Tests (npm)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build:
|
||||
description: 'Test Bru CLI (npm)'
|
||||
required: true
|
||||
default: 'true'
|
||||
|
||||
# Assign permissions for unit tests to be reported.
|
||||
# See https://github.com/dorny/test-reporter/issues/168
|
||||
permissions:
|
||||
statuses: write
|
||||
checks: write
|
||||
contents: write
|
||||
pull-requests: write
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: CLI Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
- name: Install Bru CLI from NPM
|
||||
run: npm install -g @usebruno/cli
|
||||
|
||||
- name: Display Bru CLI Version
|
||||
run: bru --version
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd packages/bruno-tests/collection
|
||||
npm install
|
||||
bru run --env Prod --output junit.xml --format junit
|
||||
|
||||
- name: Publish Test Report
|
||||
uses: dorny/test-reporter@v1
|
||||
if: success() || failure()
|
||||
with:
|
||||
name: Test Report
|
||||
path: packages/bruno-tests/collection/junit.xml
|
||||
reporter: java-junit
|
||||
27
.github/workflows/playwright.yml
vendored
27
.github/workflows/playwright.yml
vendored
@@ -1,27 +0,0 @@
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Install dependencies
|
||||
run: npm i --legacy-peer-deps
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps
|
||||
- name: Run Playwright tests
|
||||
run: npm run test:e2e
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
50
.github/workflows/release-snap.yml
vendored
50
.github/workflows/release-snap.yml
vendored
@@ -1,50 +0,0 @@
|
||||
name: Publish to Snapcraft
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build:
|
||||
description: 'Build and publish to Snapcraft'
|
||||
required: true
|
||||
default: 'true'
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Check package-lock.json
|
||||
run: npm ci
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install --legacy-peer-deps
|
||||
|
||||
- name: Build Electron app
|
||||
run: |
|
||||
npm run build:bruno-query
|
||||
npm run build:graphql-docs
|
||||
npm run build:web
|
||||
npm run build:electron:snap
|
||||
|
||||
- name: Install Snapcraft
|
||||
run: |
|
||||
sudo snap install snapcraft --classic
|
||||
continue-on-error: true
|
||||
|
||||
- name: Configure Snapcraft
|
||||
run: snapcraft whoami
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_API_KEY }}
|
||||
|
||||
- name: Publish to Snapcraft
|
||||
run: |
|
||||
snapcraft upload --release=stable packages/bruno-electron/out/*.snap
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_API_KEY }}
|
||||
85
.github/workflows/tests.yml
vendored
Normal file
85
.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
name: Tests
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
unit-test:
|
||||
name: Unit Tests
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install dependencies
|
||||
run: npm ci --legacy-peer-deps
|
||||
|
||||
# build libraries
|
||||
- name: Build libraries
|
||||
run: |
|
||||
npm run build --workspace=packages/bruno-common
|
||||
npm run build --workspace=packages/bruno-query
|
||||
|
||||
# test
|
||||
- name: Test Package bruno-query
|
||||
run: npm run test --workspace=packages/bruno-query
|
||||
- name: Test Package bruno-lang
|
||||
run: npm run test --workspace=packages/bruno-lang
|
||||
- name: Test Package bruno-schema
|
||||
run: npm run test --workspace=packages/bruno-schema
|
||||
- name: Test Package bruno-app
|
||||
run: npm run test --workspace=packages/bruno-app
|
||||
- name: Test Package bruno-js
|
||||
run: npm run test --workspace=packages/bruno-js
|
||||
- name: Test Package bruno-common
|
||||
run: npm run test --workspace=packages/bruno-common
|
||||
- name: Test Package bruno-cli
|
||||
run: npm run test --workspace=packages/bruno-cli
|
||||
- name: Test Package bruno-electron
|
||||
run: npm run test --workspace=packages/bruno-electron
|
||||
|
||||
cli-test:
|
||||
name: CLI Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --legacy-peer-deps
|
||||
|
||||
- name: Build Libraries
|
||||
run: |
|
||||
npm run build --workspace=packages/bruno-query
|
||||
npm run build --workspace=packages/bruno-common
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd packages/bruno-tests/collection
|
||||
npm install
|
||||
node ../../bruno-cli/bin/bru.js run --env Prod --output junit.xml --format junit
|
||||
|
||||
- name: Publish Test Report
|
||||
uses: EnricoMi/publish-unit-test-result-action@v2
|
||||
if: always()
|
||||
with:
|
||||
files: packages/bruno-tests/collection/junit.xml
|
||||
comment_mode: always
|
||||
prettier:
|
||||
name: Prettier
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install dependencies
|
||||
run: npm ci --legacy-peer-deps
|
||||
- name: Run Prettier
|
||||
run: npm run test:prettier:web
|
||||
45
.github/workflows/unit-tests.yml
vendored
45
.github/workflows/unit-tests.yml
vendored
@@ -1,45 +0,0 @@
|
||||
name: Unit Tests
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
jobs:
|
||||
tests:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install dependencies
|
||||
run: npm ci --legacy-peer-deps
|
||||
- name: Test Package bruno-query
|
||||
run: npm run test --workspace=packages/bruno-query
|
||||
- name: Build Package bruno-query
|
||||
run: npm run build --workspace=packages/bruno-query
|
||||
- name: Test Package bruno-lang
|
||||
run: npm run test --workspace=packages/bruno-lang
|
||||
- name: Test Package bruno-schema
|
||||
run: npm run test --workspace=packages/bruno-schema
|
||||
- name: Test Package bruno-app
|
||||
run: npm run test --workspace=packages/bruno-app
|
||||
- name: Test Package bruno-js
|
||||
run: npm run test --workspace=packages/bruno-js
|
||||
- name: Test Package bruno-cli
|
||||
run: npm run test --workspace=packages/bruno-cli
|
||||
- name: Test Package bruno-electron
|
||||
run: npm run test --workspace=packages/bruno-electron --passWithNoTests
|
||||
|
||||
prettier:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Install dependencies
|
||||
run: npm ci --legacy-peer-deps
|
||||
- name: Run Prettier
|
||||
run: npm run test:prettier:web
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,11 +1,14 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
bun.lockb
|
||||
node_modules
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
.pnp
|
||||
.pnp.js
|
||||
bun.lockb
|
||||
bun.lock
|
||||
|
||||
# testing
|
||||
coverage
|
||||
|
||||
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 |
@@ -1,8 +1,9 @@
|
||||
**English** | [Українська](docs/contributing/contributing_ua.md) | [Русский](docs/contributing/contributing_ru.md) | [Türkçe](docs/contributing/contributing_tr.md) | [Deutsch](docs/contributing/contributing_de.md) | [Français](docs/contributing/contributing_fr.md) | [Português (BR)](docs/contributing/contributing_pt_br.md) | [বাংলা](docs/contributing/contributing_bn.md) | [Español](docs/contributing/contributing_es.md) | [Română](docs/contributing/contributing_ro.md) | [Polski](docs/contributing/contributing_pl.md)
|
||||
| [简体中文](docs/contributing/contributing_cn.md) | [正體中文](docs/contributing/contributing_zhtw.md)
|
||||
|
||||
## Let's make bruno better, together !!
|
||||
## Let's make Bruno better, together !!
|
||||
|
||||
We are happy that you are looking to improve bruno. Below are the guidelines to get started bringing up bruno on your computer.
|
||||
We are happy that you are looking to improve Bruno. Below are the guidelines to get started bringing up Bruno on your computer.
|
||||
|
||||
### Technology Stack
|
||||
|
||||
@@ -27,10 +28,6 @@ You would need [Node v18.x or the latest LTS version](https://nodejs.org/en/) an
|
||||
|
||||
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.
|
||||
|
||||
### Dependencies
|
||||
|
||||
- NodeJS v18
|
||||
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
@@ -40,11 +37,10 @@ nvm use
|
||||
# install deps
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# build graphql docs
|
||||
# build packages
|
||||
npm run build:graphql-docs
|
||||
|
||||
# build bruno query
|
||||
npm run build:bruno-query
|
||||
npm run build:bruno-common
|
||||
|
||||
# run next app (terminal 1)
|
||||
npm run dev:web
|
||||
@@ -77,7 +73,7 @@ npm test --workspace=packages/bruno-schema
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Raising Pull Request
|
||||
### Raising Pull Requests
|
||||
|
||||
- Please keep the PR's small and focused on one thing
|
||||
- Please follow the format of creating branches
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[English](/contributing.md) | [Українська](/contributing_ua.md) | [Русский](/contributing_ru.md) | [Türkçe](/contributing_tr.md) | [Deutsch](docs/contributing/contributing_de.md) | [Français](/contributing_fr.md) | **বাংলা**
|
||||
[English](/contributing.md) | [Українська](/contributing_ua.md) | [Русский](/contributing_ru.md) | [Türkçe](/contributing_tr.md) | [Deutsch](docs/contributing/contributing_de.md) | [Français](/contributing_fr.md) | **বাংলা** | [简体中文](docs/contributing/contributing_cn.md) | [正體中文](docs/contributing/contributing_zhtw.md)
|
||||
|
||||
## আসুন ব্রুনোকে আরও ভালো করি, একসাথে!!
|
||||
|
||||
|
||||
87
docs/contributing/contributing_cn.md
Normal file
87
docs/contributing/contributing_cn.md
Normal file
@@ -0,0 +1,87 @@
|
||||
[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) | [Română](./contributing_ro.md) | [Polski](./contributing_pl.md) | **简体中文** | [正體中文](docs/contributing/contributing_zhtw.md)
|
||||
|
||||
## 让我们一起改进 Bruno!
|
||||
|
||||
很高兴看到您考虑改进 Bruno。以下是获取 Bruno 并在您的电脑上运行它的规则和指南。
|
||||
|
||||
### 使用的技术
|
||||
|
||||
Bruno 基于 NextJs 和 React 构建。我们使用 Electron 来封装桌面版本。
|
||||
|
||||
我们使用的库包括:
|
||||
|
||||
- CSS - Tailwind
|
||||
- 代码编辑器 - Codemirror
|
||||
- 状态管理 - Redux
|
||||
- 图标 - Tabler Icons
|
||||
- 表单 - formik
|
||||
- 模式验证 - Yup
|
||||
- 请求客户端 - axios
|
||||
- 文件系统监视器 - chokidar
|
||||
|
||||
### 依赖项
|
||||
|
||||
您需要 [Node v18.x 或最新的 LTS 版本](https://nodejs.org/en/) 和 npm 8.x。我们在这个项目中也使用 npm 工作区(_npm workspaces_)。
|
||||
|
||||
## 开发
|
||||
|
||||
Bruno 是作为一个 _client lourd(重客户端)_ 应用程序开发的。您需要在一个终端中启动 nextjs 来加载应用程序,然后在另一个终端中启动 Electron 应用程序。
|
||||
|
||||
### 依赖项
|
||||
|
||||
- NodeJS v18
|
||||
|
||||
### 本地开发
|
||||
|
||||
```bash
|
||||
# 使用 node 版本 18
|
||||
nvm use
|
||||
|
||||
# 安装依赖项
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# 构建 graphql 文档
|
||||
npm run build:graphql-docs
|
||||
|
||||
# 构建 bruno 查询
|
||||
npm run build:bruno-query
|
||||
|
||||
# 启动 next(终端 1)
|
||||
npm run dev:web
|
||||
|
||||
# 启动重客户端(终端 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### 故障排除
|
||||
|
||||
在运行 npm install 时,您可能会遇到 Unsupported platform 错误。为了解决这个问题,请删除 node_modules 目录和 package-lock.json 文件,然后再次运行 npm install。这应该会安装运行应用程序所需的所有包。
|
||||
|
||||
```shell
|
||||
# 删除子目录中的 node_modules 目录
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# 删除子目录中的 package-lock.json 文件
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### 测试
|
||||
|
||||
```bash
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### 提交 Pull Request
|
||||
|
||||
- 请保持 PR 精简并专注于单一目标
|
||||
- 请遵循分支命名格式:
|
||||
- feature/[feature name]:该分支应包含特定功能
|
||||
- 例如:feature/dark-mode
|
||||
- bugfix/[bug name]:该分支应仅包含特定 bug 的修复
|
||||
- 例如:bugfix/bug-1
|
||||
@@ -1,4 +1,4 @@
|
||||
[English](/contributing.md) | [Українська](/contributing_ua.md) | [Русский](/contributing_ru.md) | [Türkçe](/contributing_tr.md) | **Deutsch** | [Français](/contributing_fr.md) | [বাংলা](docs/contributing/contributing_bn.md)
|
||||
[English](/contributing.md) | [Українська](/contributing_ua.md) | [Русский](/contributing_ru.md) | [Türkçe](/contributing_tr.md) | **Deutsch** | [Français](/contributing_fr.md) | [বাংলা](docs/contributing/contributing_bn.md) | [简体中文](docs/contributing/contributing_cn.md) | [正體中文](docs/contributing/contributing_zhtw.md)
|
||||
|
||||
## Lass uns Bruno noch besser machen, gemeinsam !!
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[English](/contributing.md) | [Українська](/contributing_ua.md) | [Русский](/contributing_ru.md) | [Türkçe](/contributing_tr.md) | [Deutsch](/contributing_de.md) | **Français** | [বাংলা](docs/contributing/contributing_bn.md)
|
||||
[English](/contributing.md) | [Українська](docs/contributing/contributing_ua.md) | [Русский](docs/contributing/contributing_ru.md) | [Türkçe](docs/contributing/contributing_tr.md) | [Deutsch](docs/contributing/contributing_de.md) | **Français** | [Português (BR)](docs/contributing/contributing_pt_br.md) | [বাংলা](docs/contributing/contributing_bn.md) | [Español](docs/contributing/contributing_es.md) | [Română](docs/contributing/contributing_ro.md) | [Polski](docs/contributing/contributing_pl.md) | [简体中文](docs/contributing/contributing_cn.md) | [正體中文](docs/contributing/contributing_zhtw.md)
|
||||
|
||||
## Ensemble, améliorons Bruno !
|
||||
|
||||
@@ -23,19 +23,6 @@ Les librairies que nous utilisons :
|
||||
|
||||
Vous aurez besoin de [Node v18.x ou la dernière version LTS](https://nodejs.org/en/) et npm 8.x. Nous utilisons aussi les espaces de travail npm (_npm workspaces_) dans ce projet.
|
||||
|
||||
### Commençons à coder
|
||||
|
||||
Veuillez vous référer à la [documentation de développement](docs/development_fr.md) pour les instructions de démarrage de l'environnement de développement local.
|
||||
|
||||
### Ouvrir une Pull Request
|
||||
|
||||
- Merci de conserver les PR minimes et focalisées sur un seul objectif
|
||||
- Merci de suivre le format de nom des branches :
|
||||
- feature/[feature name]: Cette branche doit contenir une fonctionnalité spécifique
|
||||
- Exemple: feature/dark-mode
|
||||
- bugfix/[bug name]: Cette branche doit contenir seulement une solution pour un bug spécifique
|
||||
- Exemple: bugfix/bug-1
|
||||
|
||||
## Développement
|
||||
|
||||
Bruno est développé comme une application _client lourd_. Vous devrez charger l'application en démarrant nextjs dans un premier terminal, puis démarre l'application Electron dans un second.
|
||||
@@ -68,7 +55,7 @@ npm run dev:electron
|
||||
|
||||
### Dépannage
|
||||
|
||||
Vous pourriez rencontrer une erreur `Unsupported platform` durant le lancement de `npm install`. Pour résoudre cela, veuillez supprimer le répertoire `node_modules` ainsi que le fichier `package-lock.json` et lancez à nouveau `npm install`. Cela devrait isntaller tous les paquets nécessaires pour lancer l'application.
|
||||
Vous pourriez rencontrer une erreur `Unsupported platform` durant le lancement de `npm install`. Pour résoudre cela, veuillez supprimer le répertoire `node_modules` ainsi que le fichier `package-lock.json` et lancez à nouveau `npm install`. Cela devrait installer tous les paquets nécessaires pour lancer l'application.
|
||||
|
||||
```shell
|
||||
# Efface les répertoires node_modules dans les sous-répertoires
|
||||
@@ -89,3 +76,12 @@ npm test --workspace=packages/bruno-schema
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Ouvrir une Pull Request
|
||||
|
||||
- Merci de conserver les PR minimes et focalisées sur un seul objectif
|
||||
- Merci de suivre le format de nom des branches :
|
||||
- feature/[feature name]: Cette branche doit contenir une fonctionnalité spécifique
|
||||
- Exemple : feature/dark-mode
|
||||
- bugfix/[bug name]: Cette branche doit contenir seulement une solution pour un bug spécifique
|
||||
- Exemple : bugfix/bug-1
|
||||
|
||||
84
docs/contributing/contributing_kr.md
Normal file
84
docs/contributing/contributing_kr.md
Normal file
@@ -0,0 +1,84 @@
|
||||
[English](/contributing.md) | [Українська](docs/contributing/contributing_ua.md) | [Русский](docs/contributing/contributing_ru.md) | [Türkçe](docs/contributing/contributing_tr.md) | [Deutsch](docs/contributing/contributing_de.md) | [Français](docs/contributing/contributing_fr.md) | [Português (BR)](docs/contributing/contributing_pt_br.md) | [বাংলা](docs/contributing/contributing_bn.md) | [Español](docs/contributing/contributing_es.md) | [Română](docs/contributing/contributing_ro.md) | [Polski](docs/contributing/contributing_pl.md)
|
||||
| [简体中文](docs/contributing/contributing_cn.md) | [正體中文](docs/contributing/contributing_zhtw.md) | **한국어**
|
||||
|
||||
## 함께 Bruno를 더 좋게 만들어요!!
|
||||
|
||||
우리는 여러분이 Bruno를 발전시키기 위해 노력해주셔서 기쁩니다. 다음은 여러분의 컴퓨터에서 Bruno를 불러오는 가이드라인입니다.
|
||||
|
||||
### 기술 스택
|
||||
|
||||
Bruno는 Next.js와 React로 구축되었습니다. 또한, (로컬 컬렉션을 지원하는) 데스크톱 버전을 제공하기 위해 electron을 사용합니다.
|
||||
|
||||
우리가 사용하는 라이브러리
|
||||
|
||||
- CSS - Tailwind
|
||||
- Code Editors - Codemirror
|
||||
- State Management - Redux
|
||||
- Icons - Tabler Icons
|
||||
- Forms - formik
|
||||
- Schema Validation - Yup
|
||||
- Request Client - axios
|
||||
- Filesystem Watcher - chokidar
|
||||
|
||||
### 의존성
|
||||
|
||||
[Node v18.x 혹은 최신 LTS version](https://nodejs.org/en/)과 npm 8.x 버전이 필요합니다. 우리는 이 프로젝트에서 npm workspaces를 사용합니다.
|
||||
|
||||
## 개발
|
||||
|
||||
Bruno는 데스크톱 앱으로 개발되고 있습니다. 한 터미널에서 Next.js를 실행하여 앱을 로드한 다음 다른 터미널에서 electron 앱을 실행해야합니다.
|
||||
|
||||
### 로컬 개발
|
||||
|
||||
```bash
|
||||
# nodejs 18 버전 사용
|
||||
nvm use
|
||||
|
||||
# 의존성 설치
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# packages 빌드
|
||||
npm run build:graphql-docs
|
||||
npm run build:bruno-query
|
||||
npm run build:bruno-common
|
||||
|
||||
# next 앱 실행 (1번 터미널)
|
||||
npm run dev:web
|
||||
|
||||
# electron 앱 실행 (2번 터미널)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### 트러블 슈팅
|
||||
|
||||
`npm install`을 실행할 때, `Unsupported platform` 에러를 마주칠 수 있습니다. 이것을 고치기 위해서는 `node_modules`와 `package-lock.json`을 삭제하고 `npm install`을 실행해야 합니다.
|
||||
그러면 앱을 실행하기 위해 필요한 패키지들이 모두 설치됩니다.
|
||||
|
||||
```shell
|
||||
# 하위 디렉토리에 있는 node_modules 삭제
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# 하위 디렉토리에 있는 package-lock 삭제
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### 테스팅
|
||||
|
||||
```bash
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Pull Requests 요청
|
||||
|
||||
- PR을 작게 유지하고 한가지에 집중해주세요.
|
||||
- 브랜치를 생성하는 형식을 따라주세요.
|
||||
- feature/[feature name]: 이 브랜치는 특정 기능에 대한 변경사항이 포함되어야합니다.
|
||||
- 예시: feature/dark-mode
|
||||
- bugfix/[bug name]: 이 브랜치는 특정 버그에 대한 버그 수정만 포함되어야합니다.
|
||||
- 예시: bugfix/bug-1
|
||||
@@ -1,4 +1,4 @@
|
||||
[English](/contributing.md) | [Українська](docs/contributing/contributing_ua.md) | [Русский](docs/contributing/contributing_ru.md) | [Türkçe](docs/contributing/contributing_tr.md) | [Deutsch](docs/contributing/contributing_de.md) | [Français](docs/contributing/contributing_fr.md) | [Português (BR)](docs/contributing/contributing_pt_br.md) | [বাংলা](docs/contributing/contributing_bn.md) | [Español](docs/contributing/contributing_es.md) | [Română](docs/contributing/contributing_ro.md) | **Polski**
|
||||
[English](/contributing.md) | [Українська](docs/contributing/contributing_ua.md) | [Русский](docs/contributing/contributing_ru.md) | [Türkçe](docs/contributing/contributing_tr.md) | [Deutsch](docs/contributing/contributing_de.md) | [Français](docs/contributing/contributing_fr.md) | [Português (BR)](docs/contributing/contributing_pt_br.md) | [বাংলা](docs/contributing/contributing_bn.md) | [Español](docs/contributing/contributing_es.md) | [Română](docs/contributing/contributing_ro.md) | **Polski** | [简体中文](docs/contributing/contributing_cn.md) | [正體中文](docs/contributing/contributing_zhtw.md)
|
||||
|
||||
## Wspólnie uczynijmy Bruno lepszym !!
|
||||
|
||||
@@ -33,7 +33,7 @@ Bruno jest rozwijane jako aplikacja desktopowa. Musisz załadować aplikację, u
|
||||
|
||||
### Lokalny Rozwój
|
||||
|
||||
```bash
|
||||
````bash
|
||||
# użyj wersji nodejs 18
|
||||
nvm use
|
||||
|
||||
@@ -66,7 +66,7 @@ done
|
||||
# Usuń package-lock w podkatalogach
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
|
||||
```
|
||||
````
|
||||
|
||||
### Testowanie
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[English](/contributing.md) | [Українська](/docs/contributing/contributing_ua.md) | [Русский](/docs/contributing/contributing_ru.md) | [Türkçe](/docs/contributing/contributing_tr.md) | [Deutsch](/docs/contributing/contributing_de.md) | [Français](/docs/contributing/contributing_fr.md) | [Português (BR)](/docs/contributing/contributing_pt_br.md) | [বাংলা](/docs/contributing/contributing_bn.md) | [Español](/docs/contributing/contributing_es.md) | [Italiano](/docs/contributing/contributing_it.md) | **Română**
|
||||
[English](/contributing.md) | [Українська](/docs/contributing/contributing_ua.md) | [Русский](/docs/contributing/contributing_ru.md) | [Türkçe](/docs/contributing/contributing_tr.md) | [Deutsch](/docs/contributing/contributing_de.md) | [Français](/docs/contributing/contributing_fr.md) | [Português (BR)](/docs/contributing/contributing_pt_br.md) | [বাংলা](/docs/contributing/contributing_bn.md) | [Español](/docs/contributing/contributing_es.md) | [Italiano](/docs/contributing/contributing_it.md) | **Română** | [简体中文](docs/contributing/contributing_cn.md) | [正體中文](docs/contributing/contributing_zhtw.md)
|
||||
|
||||
## Haideţi să îmbunătățim Bruno, împreună!!
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[English](/contributing.md) | [Українська](/contributing_ua.md) | **Русский** | [Türkçe](/contributing_tr.md) | [Deutsch](/contributing_de.md) | [Français](/contributing_fr.md) | [বাংলা](docs/contributing/contributing_bn.md)
|
||||
[English](/contributing.md) | [Українська](/contributing_ua.md) | **Русский** | [Türkçe](/contributing_tr.md) | [Deutsch](/contributing_de.md) | [Français](/contributing_fr.md) | [বাংলা](docs/contributing/contributing_bn.md) | [简体中文](docs/contributing/contributing_cn.md) | [正體中文](docs/contributing/contributing_zhtw.md)
|
||||
|
||||
## Давайте вместе сделаем Бруно лучше!!!
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
[English](/readme.md) | [Українська](/contributing_ua.md) | [Русский](/contributing_ru.md) | **Türkçe** | [Deutsch](/contributing_de.md) | [Français](/contributing_fr.md) | [বাংলা](docs/contributing/contributing_bn.md)
|
||||
[English](../../contributing.md) | [Українська](docs/contributing/contributing_ua.md) | [Русский](docs/contributing/contributing_ru.md) | **Türkçe** | [Deutsch](docs/contributing/contributing_de.md) | [Français](docs/contributing/contributing_fr.md) | [Português (BR)](docs/contributing/contributing_pt_br.md) | [বাংলা](docs/contributing/contributing_bn.md) | [Español](docs/contributing/contributing_es.md) | [Română](docs/contributing/contributing_ro.md) | [Polski](docs/contributing/contributing_pl.md)
|
||||
| [简体中文](docs/contributing/contributing_cn.md) | [正體中文](docs/contributing/contributing_zhtw.md)
|
||||
|
||||
## Bruno'yu birlikte daha iyi hale getirelim !!
|
||||
## Bruno'yu birlikte daha iyi hale getirelim!!!
|
||||
|
||||
Bruno'yu geliştirmek istemenizden mutluluk duyuyorum. Aşağıda, bruno'yu bilgisayarınıza getirmeye başlamak için yönergeler bulunmaktadır.
|
||||
bruno'yu geliştirmek istemenizden mutluluk duyuyoruz. Aşağıda, bruno'yu bilgisayarınıza getirmeye başlamak için yönergeler bulunmaktadır.
|
||||
|
||||
### Kullanılan Teknolojiler
|
||||
|
||||
@@ -13,7 +14,7 @@ Kullandığımız kütüphaneler
|
||||
- CSS - Tailwind
|
||||
- Kod Düzenleyiciler - Codemirror
|
||||
- Durum Yönetimi - Redux
|
||||
- Iconlar - Tabler Simgeleri
|
||||
- Iconlar - Tabler Icons
|
||||
- Formlar - formik
|
||||
- Şema Doğrulama - Yup
|
||||
- İstek İstemcisi - axios
|
||||
@@ -23,9 +24,59 @@ Kullandığımız kütüphaneler
|
||||
|
||||
[Node v18.x veya en son LTS sürümüne](https://nodejs.org/en/) ve npm 8.x'e ihtiyacınız olacaktır. Projede npm çalışma alanlarını kullanıyoruz
|
||||
|
||||
### Kodlamaya başlayalım
|
||||
## Gelişim
|
||||
|
||||
Yerel geliştirme ortamının çalıştırılmasına ilişkin talimatlar için lütfen [development.md](docs/development.md) adresine başvurun.
|
||||
Bruno bir masaüstü uygulaması olarak geliştirilmektedir. Next.js uygulamasını bir terminalde çalıştırarak uygulamayı yüklemeniz ve ardından electron uygulamasını başka bir terminalde çalıştırmanız gerekir.
|
||||
|
||||
### Bağımlılıklar
|
||||
|
||||
- NodeJS v18
|
||||
|
||||
### Yerel Geliştirme
|
||||
|
||||
```bash
|
||||
# nodejs 18 sürümünü kullan
|
||||
nvm use
|
||||
|
||||
# deps yükleyin
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# graphql dokümanlarını oluştur
|
||||
npm run build:graphql-docs
|
||||
|
||||
# bruno sorgusu oluştur
|
||||
npm run build:bruno-query
|
||||
|
||||
# sonraki uygulamayı çalıştır (terminal 1)
|
||||
npm run dev:web
|
||||
|
||||
# electron uygulamasını çalıştır (terminal 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### Sorun Giderme
|
||||
|
||||
`npm install`'ı çalıştırdığınızda `Unsupported platform` hatası ile karşılaşabilirsiniz. Bunu düzeltmek için `node_modules` ve `package-lock.json` dosyalarını silmeniz ve `npm install` dosyasını çalıştırmanız gerekecektir. Bu, uygulamayı çalıştırmak için gereken tüm gerekli paketleri yüklemelidir.
|
||||
|
||||
```shell
|
||||
# Alt dizinlerdeki node_modules öğelerini silme
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# Alt dizinlerdeki paket kilidini silme
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### Test
|
||||
|
||||
```bash
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Pull Request Oluşturma
|
||||
|
||||
@@ -33,5 +84,5 @@ Yerel geliştirme ortamının çalıştırılmasına ilişkin talimatlar için l
|
||||
- Lütfen şube oluşturma formatını takip edin
|
||||
- feature/[özellik adı]: Bu dal belirli bir özellik için değişiklikler içermelidir
|
||||
- Örnek: feature/dark-mode
|
||||
- bugfix/[hata adı]: Bu dal yalnızca belirli bir hata için hata düzeltmelerini içermelidir
|
||||
- bugfix/[hata adı]: Bu dal yalnızca belirli bir hata için hata düzeltmeleri içermelidir
|
||||
- Örnek bugfix/bug-1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[English](/contributing.md) | **Українська** | [Русский](/contributing_ru.md) | [Türkçe](/contributing_tr.md) | [Deutsch](/contributing_de.md) | [Français](/contributing_fr.md) | [বাংলা](docs/contributing/contributing_bn.md)
|
||||
[English](/contributing.md) | **Українська** | [Русский](/contributing_ru.md) | [Türkçe](/contributing_tr.md) | [Deutsch](/contributing_de.md) | [Français](/contributing_fr.md) | [বাংলা](docs/contributing/contributing_bn.md) | [简体中文](docs/contributing/contributing_cn.md) | [正體中文](docs/contributing/contributing_zhtw.md)
|
||||
|
||||
## Давайте зробимо Bruno краще, разом !!
|
||||
|
||||
|
||||
87
docs/contributing/contributing_zhtw.md
Normal file
87
docs/contributing/contributing_zhtw.md
Normal file
@@ -0,0 +1,87 @@
|
||||
[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) | [Română](./contributing_ro.md) | [Polski](./contributing_pl.md) | [简体中文](./contributing_cn.md) | **正體中文**
|
||||
|
||||
## 讓我們一起來讓 Bruno 變得更好!
|
||||
|
||||
我們很高興您希望一同改善 Bruno。以下是在您的電腦上開始運行 Bruno 的規則及指南。
|
||||
|
||||
### 技術細節
|
||||
|
||||
Bruno 使用 Next.js 和 React 構建。我們使用 Electron 來封裝及發佈桌面版本。
|
||||
|
||||
我們使用的函式庫:
|
||||
|
||||
- CSS - Tailwind
|
||||
- 程式碼編輯器 - Codemirror
|
||||
- 狀態管理 - Redux
|
||||
- Icons - Tabler Icons
|
||||
- 表單 - formik
|
||||
- 結構驗證- Yup
|
||||
- 請求用戶端 - axios
|
||||
- 檔案系統監測 - chokidar
|
||||
|
||||
### 依賴關係
|
||||
|
||||
您需要使用 [Node v18.x 或最新的 LTS 版本](https://nodejs.org/en/) 和 npm 8.x。我們在這個專案中使用 npm 工作區(_npm workspaces_)。
|
||||
|
||||
## 開發
|
||||
|
||||
Bruno 正以桌面應用程式的形式開發。您需要在一個終端機中執行 Next.js 來載入應用程式,然後在另一個終端機中執行 electron 應用程式。
|
||||
|
||||
### 開發依賴
|
||||
|
||||
- NodeJS v18
|
||||
|
||||
### 本地開發
|
||||
|
||||
```bash
|
||||
# 使用 nodejs 第 18 版
|
||||
nvm use
|
||||
|
||||
# 安裝相依套件(使用--legacy-peer-deps 解決套件相依性問題)
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# 建立 graphql 文件
|
||||
npm run build:graphql-docs
|
||||
|
||||
# 建立 bruno 查詢
|
||||
npm run build:bruno-query
|
||||
|
||||
# 執行 next 應用程式(終端機 1)
|
||||
npm run dev:web
|
||||
|
||||
# 執行 electron 應用程式(終端機 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### 故障排除
|
||||
|
||||
在執行 `npm install` 時,您可能會遇到 `Unsupported platform` 的錯誤訊息。爲了解決這個問題,您需要刪除 `node_modules` 資料夾和 `package-lock.json` 檔案,然後再執行一次 `npm install`。這應該能重新安裝應用程式所需的套件。
|
||||
|
||||
```shell
|
||||
# 刪除子資料夾中的 node_modules 資料夾
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# 刪除子資料夾中的 package-lock.json 檔案
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### 測試
|
||||
|
||||
```bash
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### 發送 Pull Request
|
||||
|
||||
- 請保持 PR 精簡並專注於一個目標
|
||||
- 請遵循建立分支的格式:
|
||||
- feature/[feature name]:該分支應包含特定功能的更改
|
||||
- 範例:feature/dark-mode
|
||||
- bugfix/[bug name]:該分支應僅包含特定 bug 的修復
|
||||
- 範例:bugfix/bug-1
|
||||
7
docs/publishing/publishing_bn.md
Normal file
7
docs/publishing/publishing_bn.md
Normal file
@@ -0,0 +1,7 @@
|
||||
[English](/publishing.md) | [Português (BR)](docs/publishing/publishing_pt_br.md) | [Română](docs/publishing/publishing_ro.md) | [Türkçe](/docs/publishing/publishing_tr.md) | [Polski](docs/publishing/publishing_pl.md) | **বাংলা** | [Français](docs/publishing/publishing_fr.md) | [简体中文](docs/publishing/publishing_cn.md) | [正體中文](docs/publishing/publishing_zhtw.md)
|
||||
|
||||
### ব্রুনোকে নতুন প্যাকেজ ম্যানেজারে প্রকাশ করা
|
||||
|
||||
যদিও আমাদের কোড ওপেন সোর্স এবং সবার ব্যবহারের জন্য উপলব্ধ, তবে আমরা নতুন প্যাকেজ ম্যানেজারে প্রকাশনা বিবেচনা করার আগে আমাদের সাথে যোগাযোগ করার জন্য অনুরোধ করি। ব্রুনোর স্রষ্টা হিসাবে, আমি এই প্রকল্পের জন্য `Bruno` ট্রেডমার্ক ধারণ করি এবং এর বিতরণ পরিচালনা করতে চাই। যদি আপনি একটি নতুন প্যাকেজ ম্যানেজারে ব্রুনো দেখতে চান, দয়া করে একটি GitHub ইস্যু তুলুন।
|
||||
|
||||
যদিও আমাদের বেশিরভাগ বৈশিষ্ট্য বিনামূল্যে এবং ওপেন সোর্স (যা REST এবং GraphQL API গুলিকে কভার করে), আমরা ওপেন-সোর্স নীতি এবং স্থায়িত্বের মধ্যে একটি সুসঙ্গত ভারসাম্য বজায় রাখার জন্য চেষ্টা করি - https://github.com/usebruno/bruno/discussions/269
|
||||
7
docs/publishing/publishing_cn.md
Normal file
7
docs/publishing/publishing_cn.md
Normal file
@@ -0,0 +1,7 @@
|
||||
[English](/publishing.md) | [Português (BR)](docs/publishing/publishing_pt_br.md) | [Română](docs/publishing/publishing_ro.md) | [Polski](docs/publishing/publishing_pl.md) | [বাংলা](docs/publishing/publishing_bn.md) | [Français](docs/publishing/publishing_fr.md) | **简体中文** | [正體中文](docs/publishing/publishing_zhtw.md)
|
||||
|
||||
### 将 Bruno 发布到新的包管理器
|
||||
|
||||
虽然我们的代码是开源的,每个人都可以使用,但我们恳请您在考虑在新的包管理器上发布之前与我们联系。作为 Bruno 的创建者,我拥有这个项目的 Bruno 商标并希望管理其发行。如果您希望看到它使用新的包管理器,请提交一个 GitHub issue。
|
||||
|
||||
虽然我们的大部分功能都是免费与开源的 (涵盖 REST 和 GraphQL APIs) ,但我们努力在开源原则和可持续性之间取得和谐的平衡 - https://github.com/usebruno/bruno/discussions/269
|
||||
7
docs/publishing/publishing_fr.md
Normal file
7
docs/publishing/publishing_fr.md
Normal file
@@ -0,0 +1,7 @@
|
||||
[English](/publishing.md) | [Português (BR)](docs/publishing/publishing_pt_br.md) | [Română](docs/publishing/publishing_ro.md) | [Türkçe](/docs/publishing/publishing_tr.md) | [Polski](docs/publishing/publishing_pl.md) | [বাংলা](docs/publishing/publishing_bn.md) | **Français** | [简体中文](docs/publishing/publishing_cn.md) | [正體中文](docs/publishing/publishing_zhtw.md)
|
||||
|
||||
### Publier Bruno dans un nouveau gestionnaire de paquets
|
||||
|
||||
Bien que notre code soit open source et disponible pour tout le monde, nous vous remercions de nous contacter avant de considérer sa publication sur un nouveau gestionnaire de paquets. En tant que créateur de Bruno, je détiens la marque `Bruno` pour ce projet et j'aimerais gérer moi-même sa distribution. Si vous voyez Bruno sur un nouveau gestionnaire de paquets, merci de créer une _issue_ GitHub.
|
||||
|
||||
Bien que la majorité de nos fonctionnalités soient gratuites et open source (ce qui couvre les APIs REST et GraphQL), nous nous efforçons de trouver un équilibre harmonieux entre les principes de l'open source et la pérennité - https://github.com/usebruno/bruno/discussions/269
|
||||
@@ -1,4 +1,4 @@
|
||||
[English](/publishing.md) | [Português (BR)](docs/publishing/publishing_pt_br.md) | [Română](docs/publishing/publishing_ro.md) | **Polski**
|
||||
[English](/publishing.md) | [Português (BR)](docs/publishing/publishing_pt_br.md) | [Română](docs/publishing/publishing_ro.md) | [Türkçe](/docs/publishing/publishing_tr.md) | **Polski** | [বাংলা](docs/publishing/publishing_bn.md) | [Français](docs/publishing/publishing_fr.md) | [简体中文](docs/publishing/publishing_cn.md) | [正體中文](docs/publishing/publishing_zhtw.md)
|
||||
|
||||
### Publikowanie Bruno w nowym menedżerze pakietów
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
[English](/publishing.md) | **Português (BR)** | [Română](docs/publishing/publishing_ro.md) | [Türkçe](/docs/publishing/publishing_tr.md) | [Polski](docs/publishing/publishing_pl.md) | [বাংলা](docs/publishing/publishing_bn.md) | [Français](docs/publishing/publishing_fr.md) | [简体中文](docs/publishing/publishing_cn.md) | [正體中文](docs/publishing/publishing_zhtw.md)
|
||||
|
||||
### Publicando Bruno em um novo gerenciador de pacotes
|
||||
|
||||
Embora nosso código seja de código aberto e esteja disponível para todos usarem, pedimos gentilmente que entre em contato conosco antes de considerar a publicação em novos gerenciadores de pacotes. Como o criador da ferramenta, mantenho a marca registrada `Bruno` para este projeto e gostaria de gerenciar sua distribuição. Se deseja ver o Bruno em um novo gerenciador de pacotes, por favor, solicite através de uma issue no GitHub.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[English](/publishing.md) | [Português (BR)](/docs/publishing/publishing_pt_br.md) | **Română**
|
||||
[English](/publishing.md) | [Português (BR)](/docs/publishing/publishing_pt_br.md) | **Română** | [Türkçe](/docs/publishing/publishing_tr.md) | [Polski](docs/publishing/publishing_pl.md) | [বাংলা](/docs/publishing/publishing_bn.md) | [Français](docs/publishing/publishing_fr.md) | [简体中文](docs/publishing/publishing_cn.md) | [正體中文](docs/publishing/publishing_zhtw.md)
|
||||
|
||||
### Publicarea lui Bruno la un gestionar de pachete nou
|
||||
|
||||
|
||||
8
docs/publishing/publishing_tr.md
Normal file
8
docs/publishing/publishing_tr.md
Normal file
@@ -0,0 +1,8 @@
|
||||
[English](../../publishing.md) | [Português (BR)](docs/publishing/publishing_pt_br.md) | [Română](docs/publishing/publishing_ro.md) | **Türkçe** | [Polski](docs/publishing/publishing_pl.md) | [বাংলা](docs/publishing/publishing_bn.md) | [Français](docs/publishing/publishing_fr.md) | [简体中文](docs/publishing/publishing_cn.md) | [正體中文](docs/publishing/publishing_zhtw.md)
|
||||
|
||||
### Bruno'yu yeni bir paket yöneticisine yayınlama
|
||||
|
||||
Kodumuz açık kaynak kodlu ve herkesin kullanımına açık olsa da, yeni paket yöneticilerinde yayınlamayı düşünmeden önce bize ulaşmanızı rica ediyoruz. Bruno'nun yaratıcısı olarak, bu proje için `Bruno` ticari markasına sahibim ve dağıtımını yönetmek istiyorum. Bruno'yu yeni bir paket yöneticisinde görmek istiyorsanız, lütfen bir GitHub sorunu oluşturun.
|
||||
|
||||
Özelliklerimizin çoğu ücretsiz ve açık kaynak olsa da (REST ve GraphQL Apis'i kapsar),
|
||||
açık kaynak ilkeleri ile sürdürülebilirlik arasında uyumlu bir denge kurmaya çalışıyoruz - https://github.com/usebruno/bruno/discussions/269
|
||||
7
docs/publishing/publishing_zhtw.md
Normal file
7
docs/publishing/publishing_zhtw.md
Normal file
@@ -0,0 +1,7 @@
|
||||
[English](/publishing.md) | [Português (BR)](docs/publishing/publishing_pt_br.md) | [Română](docs/publishing/publishing_ro.md) | [Polski](docs/publishing/publishing_pl.md) | [বাংলা](docs/publishing/publishing_bn.md) | [Français](docs/publishing/publishing_fr.md) | **正體中文** | [简体中文](docs/publishing/publishing_cn.md)
|
||||
|
||||
### 將 Bruno 發佈到新的套件管理器
|
||||
|
||||
雖然我們的程式碼是開源的並且可供所有人使用,但我們懇請您在考慮在新的套件管理器上發布之前與我們聯繫。作為 Bruno 的創建者,我擁有這個專案的 Bruno 商標並希望管理其發行。如果您希望看到 Bruno 使用新的套件管理器,請提出一個 GitHub issue。
|
||||
|
||||
雖然我們的大部分功能都是免費和開源(涵蓋 REST 和 GraphQL APIs),但我們努力在開源的原則和永續性之間,取得和諧的平衡 - https://github.com/usebruno/bruno/discussions/269
|
||||
139
docs/readme/readme_ar.md
Normal file
139
docs/readme/readme_ar.md
Normal file
@@ -0,0 +1,139 @@
|
||||
<br />
|
||||
<img src="assets/images/logo-transparent.png" width="80"/>
|
||||
|
||||
### برونو - بيئة تطوير مفتوحة المصدر لاستكشاف واختبار واجهات برمجة التطبيقات (APIs).
|
||||
|
||||
[](https://badge.fury.io/gh/usebruno%bruno)
|
||||
[](https://github.com/usebruno/bruno/workflows/unit-tests.yml)
|
||||
[](https://github.com/usebruno/bruno/pulse)
|
||||
[](https://twitter.com/use_bruno)
|
||||
[](https://www.usebruno.com)
|
||||
[](https://www.usebruno.com/downloads)
|
||||
|
||||
**English** | [Українська](docs/readme/readme_ua.md) | [Русский](docs/readme/readme_ru.md) | [Türkçe](docs/readme/readme_tr.md) | [Deutsch](docs/readme/readme_de.md) | [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)
|
||||
|
||||
برونو هو عميل API جديد ومبتكر، يهدف إلى ثورة الحالة الحالية التي يمثلها برنامج Postman وأدوات مماثلة هناك.
|
||||
|
||||
يقوم برونو بتخزين مجموعاتك مباشرة في مجلد على نظام الملفات الخاص بك. نحن نستخدم لغة ترميز النص العادية، Bru، لحفظ معلومات حول طلبات واجهة برمجة التطبيقات (API).
|
||||
|
||||
يمكنك استخدام Git أو أي نظام تحكم في الإصدار الذي تفضله للتعاون على مجموعات API الخاصة بك.
|
||||
|
||||
برونو هو خاص بالاستخدام دون اتصال بالإنترنت. ليس هناك خطط لإضافة مزامنة السحابة إلى برونو أبدًا. نحن نقدر خصوصية بياناتك ونعتقد أنه يجب أن تظل على جهازك. اقرأ رؤيتنا على المدى الطويل [هنا](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
📢 شاهد حديثنا الأخير في مؤتمر India FOSS 3.0 [هنا](https://www.youtube.com/watch?v=7bSMFpbcPiY)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### الطبعة الذهبية ✨
|
||||
|
||||
غالبية ميزاتنا مجانية ومفتوحة المصدر.
|
||||
نحن نسعى لتحقيق توازن متناغم بين [مبادئ الشفافية والاستدامة](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
طلبات الشراء لـ [الطبعة الذهبية](https://www.usebruno.com/pricing) ستطلق قريبًا بسعر ~~$19~~ **$9** ! <br/>
|
||||
[اشترك هنا](https://usebruno.ck.page/4c65576bd4) لتصلك إشعارات عند الإطلاق.
|
||||
|
||||
### التثبيت
|
||||
|
||||
برونو متاح كتنزيل ثنائي [على موقعنا على الويب](https://www.usebruno.com/downloads) لأنظمة التشغيل Mac و Windows و Linux.
|
||||
|
||||
يمكنك أيضًا تثبيت برونو عبر مديري الحزم مثل Homebrew و Chocolatey و Scoop و Snap و Flatpak و Apt.
|
||||
|
||||
```sh
|
||||
# على نظام Mac عبر Homebrew
|
||||
brew install bruno
|
||||
|
||||
# على نظام Windows عبر Chocolatey
|
||||
choco install bruno
|
||||
|
||||
# على نظام Windows عبر Scoop
|
||||
scoop bucket add extras
|
||||
scoop install bruno
|
||||
|
||||
# على نظام Linux عبر Snap
|
||||
snap install bruno
|
||||
|
||||
# على نظام Linux عبر Flatpak
|
||||
flatpak install com.usebruno.Bruno
|
||||
|
||||
# على نظام Linux عبر Apt
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266
|
||||
|
||||
echo "deb [signed-by=/etc/apt/keyrings/bruno.gpg] http://debian.usebruno.com/ bruno stable" | sudo tee /etc/apt/sources.list.d/bruno.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt
|
||||
```
|
||||
### التشغيل عبر منصات متعددة 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### التعاون عبر Git 👩💻🧑💻
|
||||
|
||||
أو أي نظام تحكم في الإصدار الذي تفضله
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### الروابط المهمة 📌
|
||||
|
||||
- [رؤيتنا على المدى الطويل](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [خارطة الطريق](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [التوثيق](https://docs.usebruno.com)
|
||||
- [Stack Overflow](https://stackoverflow.com/questions/tagged/bruno)
|
||||
- [الموقع الإلكتروني](https://www.usebruno.com)
|
||||
- [التسعير](https://www.usebruno.com/pricing)
|
||||
- [التنزيل](https://www.usebruno.com/downloads)
|
||||
- [Github Sponsors](https://github.com/sponsors/helloanoop).
|
||||
|
||||
### عروض 🎥
|
||||
|
||||
- [الشهادات](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [مركز المعرفة](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Scriptmania](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### الدعم ❤️
|
||||
|
||||
إذا كنت تحب برونو وترغب في دعم عملنا مفتوح المصدر، فكر في رعايتنا عبر [Github Sponsors](https://github.com/sponsors/helloanoop).
|
||||
|
||||
### شارك الشهادات 📣
|
||||
|
||||
إذا كان برونو قد ساعدك في العمل وفرقك، فلا تنسى مشاركة [شهاداتك في مناقشتنا على GitHub](https://github.com/usebruno/bruno/discussions/343)
|
||||
|
||||
### نشر إلى مديري الحزم الجديدة
|
||||
|
||||
يرجى الرجوع [هنا](publishing.md) لمزيد من المعلومات.
|
||||
|
||||
### تواصل معنا 🌐
|
||||
|
||||
[𝕏 (تويتر)](https://twitter.com/use_bruno) <br />
|
||||
[الموقع الإلكتروني](https://www.usebruno.com) <br />
|
||||
[ديسكورد](https://discord.com/invite/KgcZUncpjq) <br />
|
||||
[لينكدإن](https://www.linkedin.com/company/usebruno)
|
||||
|
||||
### علامة تجارية
|
||||
|
||||
**الاسم**
|
||||
|
||||
`برونو` هو علامة تجارية تمتلكها [أنوب إم دي](https://www.helloanoop.com/)
|
||||
|
||||
**الشعار**
|
||||
|
||||
الشعار من [OpenMoji](https://openmoji.org/library/emoji-1F436/). الترخيص: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
### المساهمة 👩💻🧑💻
|
||||
|
||||
يسعدني أنك تتطلع لتحسين برونو. يرجى الاطلاع على [دليل المساهمة](contributing.md)
|
||||
|
||||
حتى إذا لم تكن قادرًا على التساهم بشكل مباشر من خلال الشيفرة، فلا تتردد في الإبلاغ عن الأخطاء وطلب الميزات التي يجب تنفيذها لحل حالتك.
|
||||
|
||||
### الكتّاب
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### الرخصة 📄
|
||||
|
||||
[MIT](license.md)
|
||||
@@ -10,7 +10,7 @@
|
||||
[](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) | [Français](docs/readme/readme_fr.md) | **বাংলা**
|
||||
[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) | [Français](docs/readme/readme_fr.md) | [Português (BR)](docs/readme/readme_pt_br.md) | [한국어](docs/readme/readme_kr.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)
|
||||
|
||||
ব্রুনো হল একটি নতুন এবং উদ্ভাবনী API ক্লায়েন্ট, যার লক্ষ্য পোস্টম্যান এবং অনুরূপ সরঞ্জাম দ্বারা প্রতিনিধিত্ব করা স্থিতাবস্থায় বিপ্লব ঘটানো।
|
||||
|
||||
@@ -85,7 +85,7 @@ sudo apt install bruno
|
||||
|
||||
### নতুন প্যাকেজ পরিচালকদের কাছে প্রকাশ করা হচ্ছে
|
||||
|
||||
আরও তথ্যের জন্য অনুগ্রহ করে [এখানে](publishing.md) দেখুন।
|
||||
আরও তথ্যের জন্য অনুগ্রহ করে [এখানে](../publishing/publishing_bn.md) দেখুন।
|
||||
|
||||
### অবদান 👩💻🧑💻
|
||||
|
||||
|
||||
129
docs/readme/readme_cn.md
Normal file
129
docs/readme/readme_cn.md
Normal file
@@ -0,0 +1,129 @@
|
||||
<br />
|
||||
<img src="../../assets/images/logo-transparent.png" width="80"/>
|
||||
|
||||
### Bruno - 开源 IDE,用于探索和测试 API。
|
||||
|
||||
[](https://badge.fury.io/gh/usebruno%bruno)
|
||||
[](https://github.com/usebruno/bruno/workflows/unit-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) | [Українська](./readme_ua.md) | [Русский](./readme_ru.md) | [Türkçe](./readme_tr.md) | [Deutsch](./readme_de.md) | [Français](./readme_fr.md) | [Português (BR)](./readme_pt_br.md) | [한국어](./readme_kr.md) | [বাংলা](./readme_bn.md) | [Español](./readme_es.md) | [Italiano](./readme_it.md) | [Română](./readme_ro.md) | [Polski](./readme_pl.md) | **简体中文** | [正體中文](docs/readme/readme_zhtw.md)
|
||||
|
||||
Bruno 是一款全新且创新的 API 客户端,旨在颠覆 Postman 和其他类似工具。
|
||||
|
||||
Bruno 直接在您的电脑文件夹中存储您的 API 信息。我们使用纯文本标记语言 Bru 来保存有关 API 的信息。
|
||||
|
||||
您可以使用 Git 或您选择的任何版本控制系统来对您的 API 信息进行版本控制和协作。
|
||||
|
||||
Bruno 仅限离线使用。我们计划永不向 Bruno 添加云同步功能。我们重视您的数据隐私,并认为它应该留在您的设备上。阅读我们的长期愿景 [点击查看](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
📢 观看我们在印度 FOSS 3.0 会议上的最新演讲 [点击查看](https://www.youtube.com/watch?v=7bSMFpbcPiY)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### 安装
|
||||
|
||||
Bruno 可以在我们的 [网站上下载](https://www.usebruno.com/downloads) Mac、Windows 和 Linux 的可执行文件。
|
||||
|
||||
您也可以通过包管理器如 Homebrew、Chocolatey、Scoop、Snap 和 Apt 安装 Bruno。
|
||||
|
||||
```sh
|
||||
# 在 Mac 电脑上用 Homebrew 安装
|
||||
brew install bruno
|
||||
|
||||
# 在 Windows 上用 Chocolatey 安装
|
||||
choco install bruno
|
||||
|
||||
# 在 Windows 上用 Scoop 安装
|
||||
scoop bucket add extras
|
||||
scoop install bruno
|
||||
|
||||
# 在 Linux 上用 Snap 安装
|
||||
snap install bruno
|
||||
|
||||
# 在 Linux 上用 Apt 安装
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266
|
||||
|
||||
echo "deb [signed-by=/etc/apt/keyrings/bruno.gpg] http://debian.usebruno.com/ bruno stable" | sudo tee /etc/apt/sources.list.d/bruno.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install bruno
|
||||
```
|
||||
|
||||
### 在 Mac 上通过 Homebrew 安装 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Collaborate 安装 👩💻🧑💻
|
||||
|
||||
或者任何您选择的版本控制系统
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### 重要链接 📌
|
||||
|
||||
- [我们的愿景](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [路线图](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [文档](https://docs.usebruno.com)
|
||||
- [Stack Overflow](https://stackoverflow.com/questions/tagged/bruno)
|
||||
- [网站](https://www.usebruno.com)
|
||||
- [价格](https://www.usebruno.com/pricing)
|
||||
- [下载](https://www.usebruno.com/downloads)
|
||||
- [GitHub 赞助](https://github.com/sponsors/helloanoop).
|
||||
|
||||
### 展示 🎥
|
||||
|
||||
- [Testimonials](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Knowledge Hub](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Scriptmania](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### 支持 ❤️
|
||||
|
||||
如果您喜欢 Bruno 并想支持我们的开源工作,请考虑通过 [GitHub Sponsors](https://github.com/sponsors/helloanoop) 来赞助我们。
|
||||
|
||||
### 分享评价 📣
|
||||
|
||||
如果 Bruno 在您的工作和团队中帮助了您,请不要忘记在我们的 GitHub 讨论上分享您的 [评价](https://github.com/usebruno/bruno/discussions/343)
|
||||
|
||||
### 发布到新的包管理器
|
||||
|
||||
有关更多信息,请参见 [此处](../../publishing_cn.md) 。
|
||||
|
||||
### 贡献 👩💻🧑💻
|
||||
|
||||
我很高兴您希望改进bruno。请查看 [贡献指南](../../contributing_cn.md)。
|
||||
|
||||
即使您无法通过代码做出贡献,我们仍然欢迎您提出 BUG 和新的功能需求。
|
||||
|
||||
### 作者
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### 联系方式 🌐
|
||||
|
||||
[𝕏 (Twitter)](https://twitter.com/use_bruno) <br />
|
||||
[Website](https://www.usebruno.com) <br />
|
||||
[Discord](https://discord.com/invite/KgcZUncpjq) <br />
|
||||
[LinkedIn](https://www.linkedin.com/company/usebruno)
|
||||
|
||||
### 商标
|
||||
|
||||
**名称**
|
||||
|
||||
`Bruno` 是由 [Anoop M D](https://www.helloanoop.com/) 持有的商标。
|
||||
|
||||
**Logo**
|
||||
|
||||
Logo 源自 [OpenMoji](https://openmoji.org/library/emoji-1F436/). License: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
### 许可证 📄
|
||||
|
||||
[MIT](../../license.md)
|
||||
@@ -1,37 +1,94 @@
|
||||
<br />
|
||||
<img src="../../assets/images/logo-transparent.png" width="80"/>
|
||||
<img src="/assets/images/logo-transparent.png" width="80"/>
|
||||
|
||||
### Bruno - Opensource IDE zum Erkunden und Testen von APIs.
|
||||
|
||||
[](https://badge.fury.io/gh/usebruno%bruno)
|
||||
[](https://github.com/usebruno/bruno/workflows/unit-tests.yml)
|
||||
[](https://github.com/usebruno/bruno/workflows/unit-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) | [Українська](/readme_ua.md) | [Русский](/readme_ru.md) | [Türkçe](/readme_tr.md) | **Deutsch** | [Français](/readme_fr.md) | [বাংলা](docs/readme/readme_bn.md)
|
||||
[English](/readme.md) | [Українська](./readme_ua.md) | [Русский](./readme_ru.md) | [Türkçe](./readme_tr.md) | **Deutsch** | [Français](./readme_fr.md) | [Português (BR)](./readme_pt_br.md) | [한국어](./readme_kr.md) | [বাংলা](./readme_bn.md) | [Español](./readme_es.md) | [Italiano](./readme_it.md) | [Română](./readme_ro.md) | [Polski](./readme_pl.md) | [简体中文](./readme_cn.md) | [正體中文](./readme_zhtw.md)
|
||||
|
||||
Bruno ist ein neuer und innovativer API-Client, der den Status Quo von Postman und ähnlichen Tools revolutionieren soll.
|
||||
|
||||
Bruno speichert Deine Sammlungen direkt in einem Ordner in Deinem Dateisystem. Wir verwenden eine einfache Textauszeichnungssprache - Bru - um Informationen über API-Anfragen zu speichern.
|
||||
Bruno speichert deine Sammlungen direkt in einem Ordner in deinem Dateisystem. Wir verwenden eine einfache Textauszeichnungssprache - Bru - um Informationen über API-Anfragen zu speichern.
|
||||
|
||||
Du kannst Git oder eine andere Versionskontrolle deiner Wahl verwenden, um an deinen API-Sammlungen gemeinsam mit anderen zu arbeiten.
|
||||
Du kannst Git oder eine andere Versionskontrolle deiner Wahl verwenden, um gemeinsam mit anderen an deinen API-Sammlungen zu arbeiten.
|
||||
|
||||
Bruno ist ein reines Offline-Tool. Es gibt keine Pläne, Bruno eine Cloud-Synchronisation hinzuzufügen. Wir schätzen den Schutz Deiner Daten und glauben, dass sie auf Deinem Gerät bleiben sollten. Lies unsere Langzeit-Vision [hier](https://github.com/usebruno/bruno/discussions/269).
|
||||
Bruno ist ein reines Offline-Tool. Es gibt keine Pläne, Bruno um eine Cloud-Synchronisation zu erweitern. Wir schätzen den Schutz deiner Daten und glauben, dass sie auf deinem Gerät bleiben sollten. Lies unsere Langzeit-Vision [hier](https://github.com/usebruno/bruno/discussions/269).
|
||||
|
||||
[Download Bruno](https://www.usebruno.com/downloads)
|
||||
|
||||
📢 Sehen Sie sich unseren Vortrag auf der India FOSS 3.0 Conference [hier](https://www.youtube.com/watch?v=7bSMFpbcPiY) an.
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Golden Edition ✨
|
||||
|
||||
Die meisten unserer Funktionen sind kostenlos und quelloffen.
|
||||
Wir bemühen uns um ein Gleichgewicht zwischen [Open-Source-Prinzipien und Nachhaltigkeit](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
Sie können die [Golden Edition](https://www.usebruno.com/pricing) vorbestellen ~~$19~~ **$9** ! <br/>
|
||||
|
||||
### Installation
|
||||
|
||||
Bruno ist als Download [auf unserer Website](https://www.usebruno.com/downloads) für Mac, Windows und Linux verfügbar.
|
||||
|
||||
Sie können Bruno auch über Paketmanager wie Homebrew, Chocolatey, Scoop, Snap, Flatpak und Apt installieren.
|
||||
|
||||
```sh
|
||||
# Auf Mac via Homebrew
|
||||
brew install bruno
|
||||
|
||||
# Auf Windows via Chocolatey
|
||||
choco install bruno
|
||||
|
||||
# Auf Windows via Scoop
|
||||
scoop bucket add extras
|
||||
scoop install bruno
|
||||
|
||||
# Auf Windows via winget
|
||||
winget install Bruno.Bruno
|
||||
|
||||
# Auf Linux via Snap
|
||||
snap install bruno
|
||||
|
||||
# Auf Linux via Flatpak
|
||||
flatpak install com.usebruno.Bruno
|
||||
|
||||
# Auf Linux via Apt
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266
|
||||
|
||||
echo "deb [signed-by=/etc/apt/keyrings/bruno.gpg] http://debian.usebruno.com/ bruno stable" | sudo tee /etc/apt/sources.list.d/bruno.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install bruno
|
||||
```
|
||||
|
||||
### Einsatz auf verschiedensten Plattformen 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Zusammenarbeiten mit Git 👩💻🧑💻
|
||||
### Zusammenarbeit mit Git 👩💻🧑💻
|
||||
|
||||
oder eine Versionskontrolle Deiner Wahl
|
||||
Oder einer Versionskontrolle deiner Wahl
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Sponsoren
|
||||
|
||||
#### Gold Sponsoren
|
||||
|
||||
<img src="/assets/images/sponsors/samagata.png" width="150"/>
|
||||
|
||||
#### Silber Sponsoren
|
||||
|
||||
<img src="/assets/images/sponsors/commit-company.png" width="70"/>
|
||||
|
||||
### Wichtige Links 📌
|
||||
|
||||
- [Unsere Langzeit-Vision](https://github.com/usebruno/bruno/discussions/269)
|
||||
@@ -49,21 +106,21 @@ oder eine Versionskontrolle Deiner Wahl
|
||||
|
||||
### Unterstützung ❤️
|
||||
|
||||
Wuff! Wenn Du dieses Projekt magst, klick den ⭐ Button !!
|
||||
Wuff! Wenn du dieses Projekt magst, klick den ⭐ Button !!
|
||||
|
||||
### Teile Erfahrungsberichte 📣
|
||||
|
||||
Wenn Bruno Dir bei Deiner Arbeit und in Deinen Teams geholfen hat, vergiss bitte nicht, Deine [Erfahrungsberichte auf unserer GitHub-Diskussion](https://github.com/usebruno/bruno/discussions/343) zu teilen.
|
||||
Wenn Bruno dir und in deinen Teams bei der Arbeit geholfen hat, vergiss bitte nicht, deine [Erfahrungsberichte auf unserer GitHub-Diskussion](https://github.com/usebruno/bruno/discussions/343) zu teilen.
|
||||
|
||||
### Veröffentlichung in neuen Paketmanagern
|
||||
### Bereitstellung in neuen Paket-Managern
|
||||
|
||||
Bitte [hier](/publishing.md) für mehr Informationen lesen.
|
||||
Mehr Informationen findest du [hier](/publishing.md).
|
||||
|
||||
### Mitmachen 👩💻🧑💻
|
||||
|
||||
Ich freue mich, dass Du Bruno verbessern willst. Bitte schau Dir den [Leitfaden zum Mitmachen](../contributing/contributing_de.md) an.
|
||||
Ich freue mich, dass du Bruno verbessern willst. Bitte schau dir den [Leitfaden zum Mitmachen](../contributing/contributing_de.md) an.
|
||||
|
||||
Auch wenn Du nicht in der Lage bist, einen Beitrag in Form von Code zu leisten, zögere bitte nicht, uns Fehler und Funktionswünsche mitzuteilen, die implementiert werden müssen, um Deinen Anwendungsfall zu unterstützen.
|
||||
Auch wenn du nicht in der Lage bist, einen Beitrag in Form von Code zu leisten, zögere bitte nicht, uns Fehler und Funktionswünsche mitzuteilen, die implementiert werden müssen, um deinen Anwendungsfall zu unterstützen.
|
||||
|
||||
### Autoren
|
||||
|
||||
|
||||
@@ -4,22 +4,68 @@
|
||||
### Bruno - IDE de código abierto para explorar y probar APIs.
|
||||
|
||||
[](https://badge.fury.io/gh/usebruno%bruno)
|
||||
[](https://github.com/usebruno/bruno/workflows/unit-tests.yml)
|
||||
[](https://github.com/usebruno/bruno/workflows/tests.yml)
|
||||
[](https://github.com/usebruno/bruno/pulse)
|
||||
[](https://twitter.com/use_bruno)
|
||||
[](https://www.usebruno.com)
|
||||
[](https://www.usebruno.com/downloads)
|
||||
|
||||
Bruno un cliente de APIs nuevo e innovador, creado con el objetivo de revolucionar el panorama actual representado por Postman y otras herramientas similares.
|
||||
[English](/readme.md) | [Українська](./readme_ua.md) | [Русский](./readme_ru.md) | [Türkçe](./readme_tr.md) | [Deutsch](./readme_de.md) | [Français](./readme_fr.md) | [Português (BR)](./readme_pt_br.md) | [한국어](./readme_kr.md) | [বাংলা](./readme_bn.md) | **Español** | [Italiano](./readme_it.md) | [Română](./readme_ro.md) | [Polski](./readme_pl.md) | [简体中文](docs/readme/readme_cn.md) | [正體中文](./readme_zhtw.md)
|
||||
|
||||
Bruno es un cliente de APIs nuevo e innovador, creado con el objetivo de revolucionar el panorama actual representado por Postman y otras herramientas similares.
|
||||
|
||||
Bruno almacena tus colecciones directamente en una carpeta de tu sistema de archivos. Usamos un lenguaje de marcado de texto plano, llamado Bru, para guardar información sobre las peticiones a tus APIs.
|
||||
|
||||
Puedes usar git o cualquier otro sistema de control de versiones que prefieras para colaborar en tus colecciones.
|
||||
|
||||
Bruno funciona sin conexión a internet. No tenemos intenciones de añadir sincronización en la nube a Bruno, en ningún momento. Valoramos tu privacidad y creemos que tus datos deben permanecer en tu dispositivo. Puedes leer nuestra visión a largo plazo [aquí](https://github.com/usebruno/bruno/discussions/269)
|
||||
Bruno funciona sin conexión a internet. No tenemos intenciones de añadir sincronización en la nube a Bruno, en ningún momento. Valoramos tu privacidad y creemos que tus datos deben permanecer en tu dispositivo. Puedes leer nuestra visión a largo plazo [aquí](https://github.com/usebruno/bruno/discussions/269).
|
||||
|
||||
[Descarga Bruno](https://www.usebruno.com/downloads).
|
||||
|
||||
📢 Mira nuestra charla en la conferencia India FOSS 3.0 [aquí](https://www.youtube.com/watch?v=7bSMFpbcPiY).
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Golden Edition ✨
|
||||
|
||||
La mayoría de nuestras funcionalidades son gratis y de código abierto.
|
||||
Queremos alcanzar un equilibrio en armonía entre los [principios open-source y la sostenibilidad](https://github.com/usebruno/bruno/discussions/269).
|
||||
|
||||
¡Puedes reservar la [Golden Edition](https://www.usebruno.com/pricing) por ~~$19~~ **$9**! <br/>
|
||||
|
||||
### Instalación
|
||||
|
||||
Bruno está disponible para su descarga [en nuestro sitio web](https://www.usebruno.com/downloads) para Mac, Windows y Linux.
|
||||
|
||||
También puedes instalar Bruno mediante package managers como Homebrew, Chocolatey, Scoop, Flatpak y Apt.
|
||||
|
||||
```sh
|
||||
# En Mac con Homebrew
|
||||
brew install bruno
|
||||
|
||||
# En Windows con Chocolatey
|
||||
choco install bruno
|
||||
|
||||
# En Windows con Scoop
|
||||
scoop bucket add extras
|
||||
scoop install bruno
|
||||
|
||||
# En Linux con Snap
|
||||
snap install bruno
|
||||
|
||||
# En Linux con Flatpak
|
||||
flatpak install com.usebruno.Bruno
|
||||
|
||||
# En Linux con Apt
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266
|
||||
|
||||
echo "deb [signed-by=/etc/apt/keyrings/bruno.gpg] http://debian.usebruno.com/ bruno stable" | sudo tee /etc/apt/sources.list.d/bruno.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install bruno
|
||||
```
|
||||
|
||||
### Ejecútalo en múltiples plataformas 🖥️
|
||||
|
||||
 <br /><br />
|
||||
@@ -39,7 +85,7 @@ O cualquier otro sistema de control de versiones que prefieras
|
||||
- [Precios](https://www.usebruno.com/pricing)
|
||||
- [Descargas](https://www.usebruno.com/downloads)
|
||||
|
||||
### Casos de uso 🎥
|
||||
### Casos de uso 🎥
|
||||
|
||||
- [Testimonios](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Centro de Conocimiento](https://github.com/usebruno/bruno/discussions/386)
|
||||
|
||||
@@ -10,19 +10,50 @@
|
||||
[](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) | **Français** | [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)
|
||||
|
||||
[English](/readme.md) | [Українська](/readme_ua.md) | [Русский](/readme_ru.md) | [Türkçe](/readme_tr.md) | [Deutsch](/readme_de.md) | **Français** | [বাংলা](docs/readme/readme_bn.md)
|
||||
|
||||
Bruno est un nouveau client API, innovant, qui a pour but de révolutionner le _status quo_ que représente Postman et les autres outils.
|
||||
Bruno est un nouveau client API, innovant, qui a pour but de révolutionner le _statu quo_ que représente Postman et les autres outils.
|
||||
|
||||
Bruno sauvegarde vos collections directement sur votre système de fichiers. Nous utilisons un langage de balise de type texte pour décrire les requêtes API.
|
||||
|
||||
Vous pouvez utiliser git ou tout autre gestionnaire de version pour travailler de manière collaborative sur vos collections d'APIs.
|
||||
|
||||
Bruno ne fonctionne qu'en mode déconnecté. Il n'y a pas de d'abonnement ou de synchronisation avec le cloud Bruno, il n'y en aura jamais. Nous sommes conscients de la confidentialité de vos données et nous sommes convaincus qu'elles doivent rester sur vos appareils. Vous pouvez lire notre vision à long terme [ici (en anglais)](https://github.com/usebruno/bruno/discussions/269).
|
||||
Bruno ne fonctionne qu'en mode déconnecté. Il n'y a pas d'abonnement ou de synchronisation avec le cloud Bruno, il n'y en aura jamais. Nous sommes conscients de la confidentialité de vos données et nous sommes convaincus qu'elles doivent rester sur vos appareils. Vous pouvez lire notre vision à long terme [ici (en anglais)](https://github.com/usebruno/bruno/discussions/269).
|
||||
|
||||
📢 Regarder notre présentation récente lors de la conférence India FOSS 3.0 (en anglais) [ici](https://www.youtube.com/watch?v=7bSMFpbcPiY)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Installation
|
||||
|
||||
Bruno est disponible au téléchargement [sur notre site web](https://www.usebruno.com/downloads), pour Mac, Windows et Linux.
|
||||
|
||||
Vous pouvez aussi installer Bruno via un gestionnaire de paquets, comme Homebrew, Chocolatey, Scoop, Snap et Apt.
|
||||
|
||||
```sh
|
||||
# Mac via Homebrew
|
||||
brew install bruno
|
||||
|
||||
# Windows via Chocolatey
|
||||
choco install bruno
|
||||
|
||||
# Windows via Scoop
|
||||
scoop bucket add extras
|
||||
scoop install bruno
|
||||
|
||||
# Linux via Snap
|
||||
snap install bruno
|
||||
|
||||
# Linux via Apt
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266
|
||||
|
||||
echo "deb [signed-by=/etc/apt/keyrings/bruno.gpg] http://debian.usebruno.com/ bruno stable" | sudo tee /etc/apt/sources.list.d/bruno.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install bruno
|
||||
```
|
||||
|
||||
### Fonctionne sur de multiples platformes 🖥️
|
||||
|
||||
 <br /><br />
|
||||
@@ -41,6 +72,7 @@ Ou n'importe quel système de gestion de sources
|
||||
- [Site web](https://www.usebruno.com)
|
||||
- [Prix](https://www.usebruno.com/pricing)
|
||||
- [Téléchargement](https://www.usebruno.com/downloads)
|
||||
- [Sponsors GitHub](https://github.com/sponsors/helloanoop)
|
||||
|
||||
### Showcase 🎥
|
||||
|
||||
@@ -54,7 +86,7 @@ Ouaf! Si vous aimez le projet, cliquez sur le bouton ⭐ !!
|
||||
|
||||
### Partage de témoignages 📣
|
||||
|
||||
Si Bruno vous a aidé dans votre travail, au sein de votre équipe, merci de penser à partager votre témoignage sur la [page discussion Github dédiée](https://github.com/usebruno/bruno/discussions/343)
|
||||
Si Bruno vous a aidé dans votre travail, au sein de votre équipe, merci de penser à partager votre témoignage sur la [page discussion GitHub dédiée](https://github.com/usebruno/bruno/discussions/343)
|
||||
|
||||
### Publier Bruno sur un nouveau gestionnaire de paquets
|
||||
|
||||
@@ -90,7 +122,7 @@ Même si vous n'êtes pas en mesure de contribuer directement via du code, n'hé
|
||||
**Logo**
|
||||
|
||||
Le logo est issu de [OpenMoji](https://openmoji.org/library/emoji-1F436/).
|
||||
Licence: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
Licence : CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
### Licence 📄
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Bruno funziona solo in modalità offline. Non ci sono piani per aggiungere la si
|
||||
|
||||
### Installazione
|
||||
|
||||
Bruno è disponisible come download binario [sul nostro sito](https://www.usebruno.com/downloads) per Mac, Windows e Linux.
|
||||
Bruno è disponibile come download binario [sul nostro sito](https://www.usebruno.com/downloads) per Mac, Windows e Linux.
|
||||
|
||||
Puoi installare Bruno anche tramite package manger come Homebrew, Chocolatey, Snap e Apt.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
### Bruno - API 탐색 및 테스트를 위한 오픈소스 IDE.
|
||||
|
||||
[](https://badge.fury.io/gh/usebruno%bruno)
|
||||
[](https://github.com/usebruno/bruno/workflows/unit-tests.yml)
|
||||
[](https://github.com/usebruno/bruno/workflows/unit-tests.yml)
|
||||
[](https://github.com/usebruno/bruno/pulse)
|
||||
[](https://twitter.com/use_bruno)
|
||||
[](https://www.usebruno.com)
|
||||
@@ -50,13 +50,13 @@ sudo apt install bruno
|
||||
|
||||
### 여러 플랫폼에서 실행하세요. 🖥️
|
||||
|
||||
 <br /><br />
|
||||
 <br /><br />
|
||||
|
||||
### Git과 연동하세요. 👩💻🧑💻
|
||||
### Git과 연동하세요. 👩💻🧑💻
|
||||
|
||||
또는 원하는 버전 관리 시스템을 선택하세요.
|
||||
|
||||
 <br /><br />
|
||||
 <br /><br />
|
||||
|
||||
### 중요 링크 📌
|
||||
|
||||
@@ -79,15 +79,15 @@ sudo apt install bruno
|
||||
|
||||
### 후기 공유 📣
|
||||
|
||||
Bruno가 여러분과 여러분의 팀에 도움이 되었다면, 잊지 말고 공유해 주세요. [Github discussion 공유 링크](https://github.com/usebruno/bruno/discussions/343)
|
||||
Bruno가 여러분과 여러분의 팀에 도움이 되었다면, 잊지 말고 공유해 주세요. [GitHub discussion 공유 링크](https://github.com/usebruno/bruno/discussions/343)
|
||||
|
||||
### 새 패키지 관리자에게 게시
|
||||
|
||||
더 많은 정보를 확인하시려명 링크를 클릭해 주세요.[배포 가이드](publishing.md)
|
||||
더 많은 정보를 확인하시려면 링크를 클릭해 주세요. [배포 가이드](../../publishing.md)
|
||||
|
||||
### 컨트리뷰트 👩💻🧑💻
|
||||
|
||||
컨트리뷰트에 관심이 있으시면 링크를 참고해 주세요. [컨트리뷰트 가이드](contributing.md)
|
||||
컨트리뷰트에 관심이 있으시면 링크를 참고해 주세요. [컨트리뷰트 가이드](/docs/contributing/contributing_kr.md)
|
||||
|
||||
코드를 통해 기여할 수 없더라도 사용 사례를 해결하기 위해 구현이 필요한 버그나 기능 요청을 주저하지 마시고 제출해 주세요.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
[](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) | [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**
|
||||
[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) | [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_cn.md) | [正體中文](docs/readme/readme_zhtw.md)
|
||||
|
||||
Bruno to nowy i innowacyjny klient API, którego celem jest zrewolucjonizowanie status quo reprezentowy przez Postman i podobne narzędzia.
|
||||
|
||||
@@ -22,7 +22,7 @@ Bruno działa tylko w trybie offline. Nie planujemy nigdy dodawać synchronizacj
|
||||
|
||||
📢 Obejrzyj naszą ostatnią rozmowę na konferencji India FOSS 3.0 [tutaj](https://www.youtube.com/watch?v=7bSMFpbcPiY)
|
||||
|
||||
 <br /><br />
|
||||
 <br /><br />
|
||||
|
||||
### Instalacja
|
||||
|
||||
@@ -56,13 +56,13 @@ sudo apt install bruno
|
||||
|
||||
### Uruchom na wielu platformach 🖥️
|
||||
|
||||
 <br /><br />
|
||||
 <br /><br />
|
||||
|
||||
### Współpracuj przez Git 👩💻🧑💻
|
||||
|
||||
Lub dowolny inny system kontroli wersji, który wybierzesz
|
||||
|
||||
 <br /><br />
|
||||
 <br /><br />
|
||||
|
||||
### Ważne Linki 📌
|
||||
|
||||
@@ -73,7 +73,7 @@ Lub dowolny inny system kontroli wersji, który wybierzesz
|
||||
- [Strona Internetowa](https://www.usebruno.com)
|
||||
- [Cennik](https://www.usebruno.com/pricing)
|
||||
- [Pobieranie](https://www.usebruno.com/downloads)
|
||||
- [Sponsorzy Github](https://github.com/sponsors/helloanoop).
|
||||
- [Sponsorzy GitHub](https://github.com/sponsors/helloanoop).
|
||||
|
||||
### Zobacz 🎥
|
||||
|
||||
@@ -83,7 +83,7 @@ Lub dowolny inny system kontroli wersji, który wybierzesz
|
||||
|
||||
### Wsparcie ❤️
|
||||
|
||||
Jeśli podoba Ci się Bruno i chcesz wspierać naszą pracę opensource, rozważ sponsorowanie nas przez [Sponsorzy Github](https://github.com/sponsors/helloanoop).
|
||||
Jeśli podoba Ci się Bruno i chcesz wspierać naszą pracę opensource, rozważ sponsorowanie nas przez [Sponsorzy GitHub](https://github.com/sponsors/helloanoop).
|
||||
|
||||
### Udostępnij Opinie 📣
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
### Bruno - IDE de código aberto para explorar e testar APIs.
|
||||
|
||||
[](https://badge.fury.io/gh/usebruno%bruno)
|
||||
[](https://github.com/usebruno/bruno/workflows/unit-tests.yml)
|
||||
[](https://github.com/usebruno/bruno/workflows/unit-tests.yml)
|
||||
[](https://github.com/usebruno/bruno/pulse)
|
||||
[](https://twitter.com/use_bruno)
|
||||
[](https://www.usebruno.com)
|
||||
@@ -22,6 +22,13 @@ Bruno é totalmente offline. Não há planos de adicionar sincronização em nuv
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Golden Edition ✨
|
||||
|
||||
A grande maioria dos nossos recursos são gratuitos e de código aberto.
|
||||
Nós nos esforçamos para encontrar um equilíbrio harmônico entre [princípios de código aberto e sustentabilidade](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
Você pode pré encomendar o plano [Golden Edition](https://www.usebruno.com/pricing) por ~~USD $19~~ **USD $9** ! <br/>
|
||||
|
||||
### Instalação
|
||||
|
||||
Bruno está disponível para download como binário [em nosso site](https://www.usebruno.com/downloads) para Mac, Windows e Linux.
|
||||
@@ -29,16 +36,26 @@ Bruno está disponível para download como binário [em nosso site](https://www.
|
||||
Você também pode instalar o Bruno via gerenciadores de pacotes como Homebrew, Chocolatey, Snap e Apt.
|
||||
|
||||
```sh
|
||||
# Mac via Homebrew
|
||||
# No Mac via Homebrew
|
||||
brew install bruno
|
||||
|
||||
# Windows via Chocolatey
|
||||
# No Windows via Chocolatey
|
||||
choco install bruno
|
||||
|
||||
# Linux via Snap
|
||||
# No Windows via Scoop
|
||||
scoop bucket add extras
|
||||
scoop install bruno
|
||||
|
||||
# No Windows via winget
|
||||
winget install Bruno.Bruno
|
||||
|
||||
# No Linux via Snap
|
||||
snap install bruno
|
||||
|
||||
# Linux via Apt
|
||||
# No Linux via Flatpak
|
||||
flatpak install com.usebruno.Bruno
|
||||
|
||||
# No Linux via Apt
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266
|
||||
|
||||
@@ -58,14 +75,26 @@ Ou qualquer sistema de controle de versão de sua escolha.
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Apoiadores
|
||||
|
||||
#### Apoiadores Gold
|
||||
|
||||
<img src="../../assets/images/sponsors/samagata.png" width="150"/>
|
||||
|
||||
#### Apoiadores Silver
|
||||
|
||||
<img src="../../assets/images/sponsors/commit-company.png" width="70"/>
|
||||
|
||||
### Links Importantes 📌
|
||||
|
||||
- [Nossa Visão de Longo Prazo](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [Roadmap](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [Documentação](https://docs.usebruno.com)
|
||||
- [Stack Overflow](https://stackoverflow.com/questions/tagged/bruno)
|
||||
- [Website](https://www.usebruno.com)
|
||||
- [Preços](https://www.usebruno.com/pricing)
|
||||
- [Download](https://www.usebruno.com/downloads)
|
||||
- [GitHub Sponsors](https://github.com/sponsors/helloanoop)
|
||||
|
||||
### Showcase 🎥
|
||||
|
||||
@@ -75,7 +104,7 @@ Ou qualquer sistema de controle de versão de sua escolha.
|
||||
|
||||
### Apoie ❤️
|
||||
|
||||
Au-au! Se você gosta do projeto, clique no botão ⭐!!
|
||||
Au-au! Se você gosta do projeto e deseja apoiar nosso trabalho, considere nos ajudando via [GitHub Sponsors](https://github.com/sponsors/helloanoop).
|
||||
|
||||
### Compartilhe sua experiência 📣
|
||||
|
||||
@@ -85,20 +114,6 @@ Se o Bruno ajudou no seu trabalho e/ou no trabalho de sua equipe, por favor, nã
|
||||
|
||||
Por favor, verifique [aqui](../publishing/publishing_pt_br.md) mais informações.
|
||||
|
||||
### Colabore 👩💻🧑💻
|
||||
|
||||
Fico feliz que você queira melhorar o Bruno. Por favor, confira o [guia de colaboração](../contributing/contributing_pt_br.md).
|
||||
|
||||
Mesmo que você não possa contribuir codificando, não deixe de relatar problemas e solicitar recursos que precisam ser implementados para atender ao contexto de seu dia a dia.
|
||||
|
||||
### Authors
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Mantenha Contato 🌐
|
||||
|
||||
[𝕏 (Twitter)](https://twitter.com/use_bruno) <br />
|
||||
@@ -116,6 +131,20 @@ Mesmo que você não possa contribuir codificando, não deixe de relatar problem
|
||||
|
||||
A logo é original do [OpenMoji](https://openmoji.org/library/emoji-1F436/). Licença: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||
### Colabore 👩💻🧑💻
|
||||
|
||||
Fico feliz que você queira melhorar o Bruno. Por favor, confira o [guia de colaboração](../contributing/contributing_pt_br.md).
|
||||
|
||||
Mesmo que você não possa contribuir codificando, não deixe de relatar problemas e solicitar recursos que precisam ser implementados para atender ao contexto de seu dia a dia.
|
||||
|
||||
### Contribuidores
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Licença 📄
|
||||
|
||||
[MIT](license.md)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
[](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) | [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ă**
|
||||
[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) | [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_cn.md) | [正體中文](docs/readme/readme_zhtw.md)
|
||||
|
||||
Bruno este un client API nou și inovativ, care vizează să revoluționeze status quo-ul reprezentat de Postman și alte instrumente similare.
|
||||
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
[](https://www.usebruno.com)
|
||||
[](https://www.usebruno.com/downloads)
|
||||
|
||||
|
||||
[English](/readme.md) | [Українська](/readme_ua.md) | **Русский** | [Türkçe](/readme_tr.md) | [Deutsch](/readme_de.md) | [Français](/readme_fr.md) | [বাংলা](docs/readme/readme_bn.md)
|
||||
[English](/readme.md) | [Українська](/readme_ua.md) | **Русский** | [Türkçe](/readme_tr.md) | [Deutsch](/readme_de.md) | [Français](/readme_fr.md) | [বাংলা](docs/readme/readme_bn.md) | [简体中文](docs/readme/readme_cn.md) | [正體中文](docs/readme/readme_zhtw.md)
|
||||
|
||||
Bruno - новый и инновационный клиент API, направленный на революцию в установившейся ситуации, представленной Postman и подобными инструментами.
|
||||
|
||||
|
||||
@@ -10,23 +10,55 @@
|
||||
[](https://www.usebruno.com)
|
||||
[](https://www.usebruno.com/downloads)
|
||||
|
||||
[English](/readme.md) | [Українська](/readme_ua.md) | [Русский](/readme_ru.md) | **Türkçe** | [Deutsch](/readme_de.md) | [Français](/readme_fr.md) | [বাংলা](docs/readme/readme_bn.md)
|
||||
[English](../../readme.md) | [Українська](docs/readme/readme_ua.md) | [Русский](docs/readme/readme_ru.md) | **Türkçe** | [Deutsch](docs/readme/readme_de.md) | [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)
|
||||
|
||||
Bruno, Postman ve benzeri araçlar tarafından temsil edilen statükoda devrim yaratmayı amaçlayan yeni ve yenilikçi bir API istemcisidir.
|
||||
|
||||
Bruno koleksiyonlarınızı doğrudan dosya sisteminizdeki bir klasörde saklar. API istekleri hakkındaki bilgileri kaydetmek için düz bir metin biçimlendirme dili olan Bru kullanıyoruz.
|
||||
|
||||
API koleksiyonlarınız üzerinde işbirliği yapmak için git veya seçtiğiniz herhangi bir sürüm kontrolünü kullanabilirsiniz.
|
||||
API koleksiyonlarınız üzerinde işbirliği yapmak için Git veya seçtiğiniz herhangi bir sürüm kontrolünü kullanabilirsiniz.
|
||||
|
||||
Bruno yalnızca çevrimdışıdır. Bruno'ya bulut senkronizasyonu eklemek gibi bir planımız yok. Veri gizliliğinize değer veriyoruz ve cihazınızda kalması gerektiğine inanıyoruz. Uzun vadeli vizyonumuzu okuyun [burada](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
📢 Hindistan FOSS 3.0 Konferansındaki son konuşmamızı izleyin [burada](https://www.youtube.com/watch?v=7bSMFpbcPiY)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Kurulum
|
||||
|
||||
Bruno Mac, Windows ve Linux için ikili indirme olarak [web sitemizde](https://www.usebruno.com/downloads) mevcuttur.
|
||||
|
||||
Bruno'yu Homebrew, Chocolatey, Scoop, Snap ve Apt gibi paket yöneticileri aracılığıyla da yükleyebilirsiniz.
|
||||
|
||||
```sh
|
||||
# Homebrew aracılığıyla Mac'te
|
||||
brew install bruno
|
||||
|
||||
# Chocolatey aracılığıyla Windows'ta
|
||||
choco install bruno
|
||||
|
||||
# Scoop aracılığıyla Windows'ta
|
||||
scoop bucket add extras
|
||||
scoop install bruno
|
||||
|
||||
# Snap aracılığıyla Linux'ta
|
||||
snap install bruno
|
||||
|
||||
# Apt aracılığıyla Linux'ta
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266
|
||||
|
||||
echo "deb [signed-by=/etc/apt/keyrings/bruno.gpg] http://debian.usebruno.com/ bruno stable" | sudo tee /etc/apt/sources.list.d/bruno.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install bruno
|
||||
```
|
||||
|
||||
### Birden fazla platformda çalıştırın 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Git üzerinden işbirliği yapın 👩💻🧑💻
|
||||
### Git üzerinden katkıda bulunun 👩💻🧑💻
|
||||
|
||||
Veya seçtiğiniz herhangi bir sürüm kontrol sistemi
|
||||
|
||||
@@ -37,8 +69,11 @@ Veya seçtiğiniz herhangi bir sürüm kontrol sistemi
|
||||
- [Uzun Vadeli Vizyonumuz](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [Yol Haritası](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [Dokümantasyon](https://docs.usebruno.com)
|
||||
- [Stack Overflow](https://stackoverflow.com/questions/tagged/bruno)
|
||||
- [Web sitesi](https://www.usebruno.com)
|
||||
- [Fiyatlandırma](https://www.usebruno.com/pricing)
|
||||
- [İndir](https://www.usebruno.com/downloads)
|
||||
- [GitHub Sponsorları](https://github.com/sponsors/helloanoop).
|
||||
|
||||
### Vitrin 🎥
|
||||
|
||||
@@ -48,15 +83,19 @@ Veya seçtiğiniz herhangi bir sürüm kontrol sistemi
|
||||
|
||||
### Destek ❤️
|
||||
|
||||
Woof! Projeyi beğendiyseniz, şu ⭐ düğmesine basın!
|
||||
Bruno'yu seviyorsanız ve açık kaynak çalışmalarımızı desteklemek istiyorsanız, [GitHub Sponsorları](https://github.com/sponsors/helloanoop) aracılığıyla bize sponsor olmayı düşünün.
|
||||
|
||||
### Referansları Paylaşın 📣
|
||||
|
||||
Bruno işinizde ve ekiplerinizde size yardımcı olduysa, lütfen [github tartışmamızdaki referanslarınızı](https://github.com/usebruno/bruno/discussions/343) paylaşmayı unutmayın
|
||||
Bruno işinizde ve ekiplerinizde size yardımcı olduysa, lütfen [github tartışmamızdaki referanslarınızı](https://github.com/usebruno/bruno/discussions/343) paylaşmayı unutmayın.
|
||||
|
||||
### Yeni Paket Yöneticilerine Yayınlama
|
||||
|
||||
Daha fazla bilgi için lütfen [buraya](publishing.md) bakın.
|
||||
|
||||
### Katkıda Bulunun 👩💻🧑💻
|
||||
|
||||
Bruno'yu geliştirmek istemenize sevindim. Lütfen [katkıda bulunma kılavuzu](../contributing/contributing.md)'na göz atın
|
||||
Bruno'yu geliştirmek istemenize sevindim. Lütfen [katkıda bulunma kılavuzuna](contributing.md) göz atın
|
||||
|
||||
Kod yoluyla katkıda bulunamasanız bile, lütfen kullanım durumunuzu çözmek için uygulanması gereken hataları ve özellik isteklerini bildirmekten çekinmeyin.
|
||||
|
||||
@@ -70,11 +109,21 @@ Kod yoluyla katkıda bulunamasanız bile, lütfen kullanım durumunuzu çözmek
|
||||
|
||||
### İletişimde Kalın 🌐
|
||||
|
||||
[Twitter](https://twitter.com/use_bruno) <br />
|
||||
[𝕏 (Twitter)](https://twitter.com/use_bruno) <br />
|
||||
[Website](https://www.usebruno.com) <br />
|
||||
[Discord](https://discord.com/invite/KgcZUncpjq)
|
||||
[Discord](https://discord.com/invite/KgcZUncpjq) <br />
|
||||
[LinkedIn](https://www.linkedin.com/company/usebruno)
|
||||
|
||||
### Ticari Marka
|
||||
|
||||
**İsim**
|
||||
|
||||
`Bruno` [Anoop M D](https://www.helloanoop.com/) tarafından sahip olunan bir ticari markadır.
|
||||
|
||||
**Logo**
|
||||
|
||||
Logo [OpenMoji](https://openmoji.org/library/emoji-1F436/) adresinden alınmıştır. Lisans: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
### Lisans 📄
|
||||
|
||||
[MIT](/license.md)
|
||||
[MIT](license.md)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
[](https://www.usebruno.com)
|
||||
[](https://www.usebruno.com/downloads)
|
||||
|
||||
[English](/readme.md) | **Українська** | [Русский](/readme_ru.md) | [Türkçe](/readme_tr.md) | [Deutsch](/readme_de.md) | [Français](/readme_fr.md) | [বাংলা](docs/readme/readme_bn.md)
|
||||
[English](/readme.md) | **Українська** | [Русский](/readme_ru.md) | [Türkçe](/readme_tr.md) | [Deutsch](/readme_de.md) | [Français](/readme_fr.md) | [বাংলা](docs/readme/readme_bn.md) | [简体中文](docs/readme/readme_cn.md) | [正體中文](docs/readme/readme_zhtw.md)
|
||||
|
||||
Bruno це новий та іноваційний API клієнт, націлений на революційну зміну статус кво, запровадженого інструментами на кшталт Postman.
|
||||
|
||||
|
||||
129
docs/readme/readme_zhtw.md
Normal file
129
docs/readme/readme_zhtw.md
Normal file
@@ -0,0 +1,129 @@
|
||||
<br />
|
||||
<img src="../../assets/images/logo-transparent.png" width="80"/>
|
||||
|
||||
### Bruno - 探索和測試 API 的開源 IDE 工具
|
||||
|
||||
[](https://badge.fury.io/gh/usebruno%bruno)
|
||||
[](https://github.com/usebruno/bruno/workflows/unit-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) | [Українська](./readme_ua.md) | [Русский](./readme_ru.md) | [Türkçe](./readme_tr.md) | [Deutsch](./readme_de.md) | [Français](./readme_fr.md) | [Português (BR)](./readme_pt_br.md) | [한국어](./readme_kr.md) | [বাংলা](./readme_bn.md) | [Español](./readme_es.md) | [Italiano](./readme_it.md) | [Română](./readme_ro.md) | [Polski](./readme_pl.md) | [简体中文](docs/readme/readme_cn.md) | **正體中文**
|
||||
|
||||
Bruno 是一個全新且有創新性的 API 用戶端,目的在徹底改變以 Postman 和其他類似工具的現況。
|
||||
|
||||
Bruno 將您的 API 集合直接儲存在檔案系統上的資料夾中。我們以純文本標記語言- Bru,來儲存和 API 有關的資訊。
|
||||
|
||||
您可以使用 Git 或您選擇的任何版本管理軟體,來管理及協作 API 集合。
|
||||
|
||||
Bruno 僅能夠離線使用,永遠不會計劃為 Bruno 增加雲端同步的功能。我們重視您的資料隱私,並相信它應該保留在您的裝置上。瞭解我們的長期願景 [連結](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
📢 觀看我們最近在 India FOSS 3.0 研討會上的演講 [連結](https://www.youtube.com/watch?v=7bSMFpbcPiY)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### 安装
|
||||
|
||||
可以在我們的 [網站上下載](https://www.usebruno.com/downloads) 跨平臺(Mac、Windows 和 Linux)的 Bruno 程式檔。
|
||||
|
||||
您也可以透過套件管理程式來安裝 Bruno,如:Homebrew、Chocolatey、Scoop、Snap 和 Apt。
|
||||
|
||||
```shell
|
||||
# 在 Mac 上使用 Homebrew 安裝
|
||||
brew install bruno
|
||||
|
||||
# 在 Windows 上使用 Chocolatey 安裝
|
||||
choco install bruno
|
||||
|
||||
# 在 Windows 上使用 Scoop 安裝
|
||||
scoop bucket add extras
|
||||
scoop install bruno
|
||||
|
||||
# 在 Linux 上使用 Snap 安裝
|
||||
snap install bruno
|
||||
|
||||
# 在 Linux 上使用 Apt 安裝
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266
|
||||
|
||||
echo "deb [signed-by=/etc/apt/keyrings/bruno.gpg] http://debian.usebruno.com/ bruno stable" | sudo tee /etc/apt/sources.list.d/bruno.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install bruno
|
||||
```
|
||||
|
||||
### 跨多個平台運行 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### 透過 Git 進行協作 👩💻🧑💻
|
||||
|
||||
您選擇的任何版本管理軟體
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### 重要連結 📌
|
||||
|
||||
- [我們的長期願景](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [藍圖](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [說明文件](https://docs.usebruno.com)
|
||||
- [Stack Overflow](https://stackoverflow.com/questions/tagged/bruno)
|
||||
- [網站](https://www.usebruno.com)
|
||||
- [定價](https://www.usebruno.com/pricing)
|
||||
- [下載](https://www.usebruno.com/downloads)
|
||||
- [GitHub 贊助](https://github.com/sponsors/helloanoop).
|
||||
|
||||
### 展示 🎥
|
||||
|
||||
- [Testimonials](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Knowledge Hub](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Scriptmania](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### 贊助支持 ❤️
|
||||
|
||||
如果您喜歡 Bruno 和希望支持我們在開源上的工作,請考慮使用 [GitHub Sponsors](https://github.com/sponsors/helloanoop) 來贊助我們。
|
||||
|
||||
### 分享感想 📣
|
||||
|
||||
如果 Bruno 在工作和您的團隊中為您提供了幫助,請不要忘記在我們的 [GitHub 討論區](https://github.com/usebruno/bruno/discussions/343) 中分享您的感想。
|
||||
|
||||
### 發佈到新的套件管理器
|
||||
|
||||
更多資訊,請參考這個 [連結](../publishing/publishing_zhtw.md) 。
|
||||
|
||||
### 持續關注 🌐
|
||||
|
||||
[𝕏 (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)
|
||||
|
||||
### 商標
|
||||
|
||||
**名稱**
|
||||
|
||||
`Bruno` 是 [Anoop M D](https://www.helloanoop.com/) 持有的商標。
|
||||
|
||||
**Logo**
|
||||
|
||||
Logo 源自於 [OpenMoji](https://openmoji.org/library/emoji-1F436/)。授權: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
### 提供貢獻 👩💻🧑💻
|
||||
|
||||
我很高興您希望一同改善 Bruno。請參考 [貢獻指南](../contributing/contributing_zhtw.md)。
|
||||
|
||||
即使您無法透過程式碼做出貢獻,我們仍然歡迎您提出 Bug 及新的實作需求。
|
||||
|
||||
### 作者們
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### 授權許可 📄
|
||||
|
||||
[MIT](../../license.md)
|
||||
19955
package-lock.json
generated
19955
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
@@ -5,11 +5,13 @@
|
||||
"packages/bruno-app",
|
||||
"packages/bruno-electron",
|
||||
"packages/bruno-cli",
|
||||
"packages/bruno-common",
|
||||
"packages/bruno-schema",
|
||||
"packages/bruno-query",
|
||||
"packages/bruno-js",
|
||||
"packages/bruno-lang",
|
||||
"packages/bruno-testbench",
|
||||
"packages/bruno-tests",
|
||||
"packages/bruno-toml",
|
||||
"packages/bruno-graphql-docs"
|
||||
],
|
||||
"homepage": "https://usebruno.com",
|
||||
@@ -17,18 +19,20 @@
|
||||
"@faker-js/faker": "^7.6.0",
|
||||
"@jest/globals": "^29.2.0",
|
||||
"@playwright/test": "^1.27.1",
|
||||
"@types/jest": "^29.5.11",
|
||||
"fs-extra": "^11.1.1",
|
||||
"husky": "^8.0.3",
|
||||
"jest": "^29.2.0",
|
||||
"pretty-quick": "^3.1.3",
|
||||
"randomstring": "^1.2.2",
|
||||
"ts-jest": "^29.0.5",
|
||||
"fs-extra": "^11.1.1"
|
||||
"ts-jest": "^29.0.5"
|
||||
},
|
||||
"scripts": {
|
||||
"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",
|
||||
"build:bruno-common": "npm run build --workspace=packages/bruno-common",
|
||||
"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",
|
||||
@@ -43,7 +47,12 @@
|
||||
"test:prettier:web": "npm run test:prettier --workspace=packages/bruno-app",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"rollup": "3.2.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"json-bigint": "^1.0.0",
|
||||
"lossless-json": "^4.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
ENV=production
|
||||
|
||||
NEXT_PUBLIC_ENV=prod
|
||||
|
||||
NEXT_PUBLIC_BRUNO_SERVER_API=https://ada.grafnode.com/api
|
||||
3
packages/bruno-app/.env.production
Normal file
3
packages/bruno-app/.env.production
Normal file
@@ -0,0 +1,3 @@
|
||||
ENV=production
|
||||
|
||||
NEXT_PUBLIC_ENV=prod
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react",
|
||||
"target": "es2017",
|
||||
"allowSyntheticDefaultImports": false,
|
||||
"baseUrl": "./",
|
||||
|
||||
@@ -18,12 +18,13 @@
|
||||
"@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.6.0",
|
||||
"@usebruno/schema": "0.7.0",
|
||||
"axios": "^1.5.1",
|
||||
"classnames": "^2.3.1",
|
||||
"codemirror": "^5.65.2",
|
||||
"codemirror-graphql": "^1.2.5",
|
||||
"codemirror": "5.65.2",
|
||||
"codemirror-graphql": "1.2.5",
|
||||
"cookie": "^0.6.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"file": "^0.2.2",
|
||||
@@ -34,14 +35,15 @@
|
||||
"graphiql": "^1.5.9",
|
||||
"graphql": "^16.6.0",
|
||||
"graphql-request": "^3.7.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"httpsnippet": "^3.0.1",
|
||||
"idb": "^7.0.0",
|
||||
"immer": "^9.0.15",
|
||||
"jsesc": "^3.0.2",
|
||||
"jsonpath-plus": "^7.2.0",
|
||||
"jshint": "^2.13.6",
|
||||
"json5": "^2.2.3",
|
||||
"jsonc-parser": "^3.2.1",
|
||||
"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",
|
||||
@@ -52,9 +54,11 @@
|
||||
"pdfjs-dist": "^3.11.174",
|
||||
"platform": "^1.3.6",
|
||||
"posthog-node": "^2.1.0",
|
||||
"prettier": "^2.7.1",
|
||||
"qs": "^6.11.0",
|
||||
"query-string": "^7.0.1",
|
||||
"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": "18.2.0",
|
||||
@@ -68,7 +72,6 @@
|
||||
"strip-json-comments": "^5.0.1",
|
||||
"styled-components": "^5.3.3",
|
||||
"system": "^2.0.1",
|
||||
"tailwindcss": "^2.2.19",
|
||||
"url": "^0.11.3",
|
||||
"xml-formatter": "^3.5.0",
|
||||
"yargs-parser": "^21.1.1",
|
||||
@@ -80,6 +83,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": "^6.5.1",
|
||||
@@ -87,8 +91,9 @@
|
||||
"html-loader": "^3.0.1",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"mini-css-extract-plugin": "^2.4.5",
|
||||
"prettier": "^2.7.1",
|
||||
"postcss": "^8.4.35",
|
||||
"style-loader": "^3.3.1",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"webpack": "^5.64.4",
|
||||
"webpack-cli": "^4.9.1"
|
||||
}
|
||||
|
||||
6
packages/bruno-app/postcss.config.js
Normal file
6
packages/bruno-app/postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
}
|
||||
};
|
||||
@@ -43,6 +43,7 @@ if (!SERVER_RENDERED) {
|
||||
'req.getUrl()',
|
||||
'req.setUrl(url)',
|
||||
'req.getMethod()',
|
||||
'req.getAuthMode()',
|
||||
'req.setMethod(method)',
|
||||
'req.getHeader(name)',
|
||||
'req.getHeaders()',
|
||||
@@ -60,7 +61,8 @@ if (!SERVER_RENDERED) {
|
||||
'bru.getEnvVar(key)',
|
||||
'bru.setEnvVar(key,value)',
|
||||
'bru.getVar(key)',
|
||||
'bru.setVar(key,value)'
|
||||
'bru.setVar(key,value)',
|
||||
'bru.setNextRequest(requestName)'
|
||||
];
|
||||
CodeMirror.registerHelper('hint', 'brunoJS', (editor, options) => {
|
||||
const cursor = editor.getCursor();
|
||||
@@ -103,6 +105,12 @@ export default class CodeEditor extends React.Component {
|
||||
// unnecessary updates during the update lifecycle.
|
||||
this.cachedValue = props.value || '';
|
||||
this.variables = {};
|
||||
|
||||
this.lintOptions = {
|
||||
esversion: 11,
|
||||
expr: true,
|
||||
asi: true
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -118,7 +126,7 @@ export default class CodeEditor extends React.Component {
|
||||
showCursorWhenSelecting: true,
|
||||
foldGutter: true,
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'],
|
||||
lint: { esversion: 11 },
|
||||
lint: this.lintOptions,
|
||||
readOnly: this.props.readOnly,
|
||||
scrollbarStyle: 'overlay',
|
||||
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
|
||||
@@ -209,7 +217,7 @@ export default class CodeEditor extends React.Component {
|
||||
return found;
|
||||
});
|
||||
if (editor) {
|
||||
editor.setOption('lint', this.props.mode && editor.getValue().trim().length > 0 ? { esversion: 11 } : false);
|
||||
editor.setOption('lint', this.props.mode && editor.getValue().trim().length > 0 ? this.lintOptions : false);
|
||||
editor.on('change', this._onEdit);
|
||||
this.addOverlay();
|
||||
}
|
||||
@@ -224,7 +232,7 @@ export default class CodeEditor extends React.Component {
|
||||
let curWord = start != end && currentLine.slice(start, end);
|
||||
//Qualify if autocomplete will be shown
|
||||
if (
|
||||
/^(?!Shift|Tab|Enter|ArrowUp|ArrowDown|ArrowLeft|ArrowRight|\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)
|
||||
@@ -299,7 +307,7 @@ export default class CodeEditor extends React.Component {
|
||||
|
||||
_onEdit = () => {
|
||||
if (!this.ignoreChangeEvent && this.editor) {
|
||||
this.editor.setOption('lint', this.editor.getValue().trim().length > 0 ? { esversion: 11 } : false);
|
||||
this.editor.setOption('lint', this.editor.getValue().trim().length > 0 ? this.lintOptions : false);
|
||||
this.cachedValue = this.editor.getValue();
|
||||
if (this.props.onEdit) {
|
||||
this.props.onEdit(this.cachedValue);
|
||||
|
||||
@@ -70,6 +70,15 @@ const AuthMode = ({ collection }) => {
|
||||
>
|
||||
Digest Auth
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
dropdownTippyRef.current.hide();
|
||||
onModeChange('oauth2');
|
||||
}}
|
||||
>
|
||||
Oauth2
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
|
||||
@@ -11,7 +11,7 @@ const BearerAuth = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
|
||||
const bearerToken = get(collection, 'root.request.auth.bearer.token');
|
||||
const bearerToken = get(collection, 'root.request.auth.bearer.token', '');
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.single-line-editor-wrapper {
|
||||
max-width: 400px;
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
border: solid 1px ${(props) => props.theme.input.border};
|
||||
background-color: ${(props) => props.theme.input.bg};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
@@ -0,0 +1,117 @@
|
||||
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, pkce } = oAuth;
|
||||
|
||||
const handleChange = (key, value) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'oauth2',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
grantType: 'authorization_code',
|
||||
callbackUrl,
|
||||
authorizationUrl,
|
||||
accessTokenUrl,
|
||||
clientId,
|
||||
clientSecret,
|
||||
scope,
|
||||
pkce,
|
||||
[key]: value
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handlePKCEToggle = (e) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'oauth2',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
grantType: 'authorization_code',
|
||||
callbackUrl,
|
||||
authorizationUrl,
|
||||
accessTokenUrl,
|
||||
clientId,
|
||||
clientSecret,
|
||||
scope,
|
||||
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 } = 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}
|
||||
/>
|
||||
</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,28 @@
|
||||
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'
|
||||
},
|
||||
{
|
||||
key: 'scope',
|
||||
label: 'Scope'
|
||||
}
|
||||
];
|
||||
|
||||
export { inputsConfig };
|
||||
@@ -0,0 +1,16 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.single-line-editor-wrapper {
|
||||
max-width: 400px;
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
border: solid 1px ${(props) => props.theme.input.border};
|
||||
background-color: ${(props) => props.theme.input.bg};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
@@ -0,0 +1,69 @@
|
||||
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 } = 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}
|
||||
/>
|
||||
</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,20 @@
|
||||
const inputsConfig = [
|
||||
{
|
||||
key: 'accessTokenUrl',
|
||||
label: 'Access Token URL'
|
||||
},
|
||||
{
|
||||
key: 'clientId',
|
||||
label: 'Client ID'
|
||||
},
|
||||
{
|
||||
key: 'clientSecret',
|
||||
label: 'Client Secret'
|
||||
},
|
||||
{
|
||||
key: 'scope',
|
||||
label: 'Scope'
|
||||
}
|
||||
];
|
||||
|
||||
export { inputsConfig };
|
||||
@@ -0,0 +1,54 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
font-size: 0.8125rem;
|
||||
|
||||
.grant-type-mode-selector {
|
||||
padding: 0.5rem 0px;
|
||||
border-radius: 3px;
|
||||
border: solid 1px ${(props) => props.theme.input.border};
|
||||
background-color: ${(props) => props.theme.input.bg};
|
||||
|
||||
.dropdown {
|
||||
width: fit-content;
|
||||
|
||||
div[data-tippy-root] {
|
||||
width: fit-content;
|
||||
}
|
||||
.tippy-box {
|
||||
width: fit-content;
|
||||
max-width: none !important;
|
||||
|
||||
.tippy-content: {
|
||||
width: fit-content;
|
||||
max-width: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.grant-type-label {
|
||||
width: fit-content;
|
||||
color: ${(props) => props.theme.colors.text.yellow};
|
||||
justify-content: space-between;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.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;
|
||||
@@ -0,0 +1,16 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.single-line-editor-wrapper {
|
||||
max-width: 400px;
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
border: solid 1px ${(props) => props.theme.input.border};
|
||||
background-color: ${(props) => props.theme.input.bg};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
@@ -0,0 +1,71 @@
|
||||
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 } = 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}
|
||||
/>
|
||||
</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,28 @@
|
||||
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'
|
||||
},
|
||||
{
|
||||
key: 'scope',
|
||||
label: 'Scope'
|
||||
}
|
||||
];
|
||||
|
||||
export { inputsConfig };
|
||||
@@ -0,0 +1,16 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.single-line-editor-wrapper {
|
||||
max-width: 400px;
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
border: solid 1px ${(props) => props.theme.input.border};
|
||||
background-color: ${(props) => props.theme.input.bg};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
@@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import get from 'lodash/get';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import GrantTypeSelector from './GrantTypeSelector/index';
|
||||
import OAuth2PasswordCredentials from './PasswordCredentials/index';
|
||||
import OAuth2AuthorizationCode from './AuthorizationCode/index';
|
||||
import OAuth2ClientCredentials from './ClientCredentials/index';
|
||||
|
||||
const grantTypeComponentMap = (grantType, collection) => {
|
||||
switch (grantType) {
|
||||
case 'password':
|
||||
return <OAuth2PasswordCredentials collection={collection} />;
|
||||
break;
|
||||
case 'authorization_code':
|
||||
return <OAuth2AuthorizationCode collection={collection} />;
|
||||
break;
|
||||
case 'client_credentials':
|
||||
return <OAuth2ClientCredentials collection={collection} />;
|
||||
break;
|
||||
default:
|
||||
return <div>TBD</div>;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const OAuth2 = ({ collection }) => {
|
||||
const oAuth = get(collection, 'root.request.auth.oauth2', {});
|
||||
|
||||
return (
|
||||
<StyledWrapper className="mt-2 w-full">
|
||||
<GrantTypeSelector collection={collection} />
|
||||
{grantTypeComponentMap(oAuth?.grantType, collection)}
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default OAuth2;
|
||||
@@ -8,6 +8,7 @@ import BasicAuth from './BasicAuth';
|
||||
import DigestAuth from './DigestAuth';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import OAuth2 from './OAuth2';
|
||||
|
||||
const Auth = ({ collection }) => {
|
||||
const authMode = get(collection, 'root.request.auth.mode');
|
||||
@@ -29,16 +30,22 @@ const Auth = ({ collection }) => {
|
||||
case 'digest': {
|
||||
return <DigestAuth collection={collection} />;
|
||||
}
|
||||
case 'oauth2': {
|
||||
return <OAuth2 collection={collection} />;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="w-full mt-2">
|
||||
<StyledWrapper className="w-full h-full">
|
||||
<div className="text-xs mb-4 text-muted">
|
||||
Configures authentication for the entire collection. This applies to all requests using the{' '}
|
||||
<span className="font-medium">Inherit</span> option in the <span className="font-medium">Auth</span> tab.
|
||||
</div>
|
||||
<div className="flex flex-grow justify-start items-center">
|
||||
<AuthMode collection={collection} />
|
||||
</div>
|
||||
{getAuthView()}
|
||||
|
||||
<div className="mt-6">
|
||||
<button type="submit" className="submit btn btn-sm btn-secondary" onClick={handleSave}>
|
||||
Save
|
||||
|
||||
@@ -9,7 +9,7 @@ const StyledWrapper = styled.div`
|
||||
color: ${(props) => props.theme.colors.text.yellow};
|
||||
}
|
||||
|
||||
input {
|
||||
.non-passphrase-input {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ import { IconCertificate, IconTrash, IconWorld } from '@tabler/icons';
|
||||
import { useFormik } from 'formik';
|
||||
import { uuid } from 'utils/common';
|
||||
import * as Yup from 'yup';
|
||||
import { IconEye, IconEyeOff } from '@tabler/icons';
|
||||
import { useState } from 'react';
|
||||
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
@@ -29,14 +31,16 @@ const ClientCertSettings = ({ clientCertConfig, onUpdate, onRemove }) => {
|
||||
formik.values[e.name] = e.files[0].path;
|
||||
};
|
||||
|
||||
const [passwordVisible, setPasswordVisible] = useState(false);
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<div className="flex items-center font-semibold mt-4 mb-2">
|
||||
<IconCertificate className="mr-1 certificate-icon" size={24} strokeWidth={1.5} /> Client Certificates
|
||||
</div>
|
||||
<StyledWrapper className="w-full h-full">
|
||||
<div className="text-xs mb-4 text-muted">Add client certificates to be used for specific domains.</div>
|
||||
|
||||
<h1 className="font-semibold">Client Certificates</h1>
|
||||
<ul className="mt-4">
|
||||
{!clientCertConfig.length
|
||||
? 'None'
|
||||
? 'No client certificates added'
|
||||
: 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">
|
||||
@@ -52,7 +56,7 @@ const ClientCertSettings = ({ clientCertConfig, onUpdate, onRemove }) => {
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<h1 className="font-semibold mt-8 mb-2">Add Client Certicate</h1>
|
||||
<h1 className="font-semibold mt-8 mb-2">Add Client Certificate</h1>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label" htmlFor="domain">
|
||||
@@ -63,7 +67,7 @@ const ClientCertSettings = ({ clientCertConfig, onUpdate, onRemove }) => {
|
||||
type="text"
|
||||
name="domain"
|
||||
placeholder="*.example.org"
|
||||
className="block textbox"
|
||||
className="block textbox non-passphrase-input"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.domain || ''}
|
||||
/>
|
||||
@@ -79,7 +83,7 @@ const ClientCertSettings = ({ clientCertConfig, onUpdate, onRemove }) => {
|
||||
id="certFilePath"
|
||||
type="file"
|
||||
name="certFilePath"
|
||||
className="block"
|
||||
className="block non-passphrase-input"
|
||||
onChange={(e) => getFile(e.target)}
|
||||
/>
|
||||
{formik.touched.certFilePath && formik.errors.certFilePath ? (
|
||||
@@ -94,7 +98,7 @@ const ClientCertSettings = ({ clientCertConfig, onUpdate, onRemove }) => {
|
||||
id="keyFilePath"
|
||||
type="file"
|
||||
name="keyFilePath"
|
||||
className="block"
|
||||
className="block non-passphrase-input"
|
||||
onChange={(e) => getFile(e.target)}
|
||||
/>
|
||||
{formik.touched.keyFilePath && formik.errors.keyFilePath ? (
|
||||
@@ -105,14 +109,23 @@ const ClientCertSettings = ({ clientCertConfig, onUpdate, onRemove }) => {
|
||||
<label className="settings-label" htmlFor="passphrase">
|
||||
Passphrase
|
||||
</label>
|
||||
<input
|
||||
id="passphrase"
|
||||
type="text"
|
||||
name="passphrase"
|
||||
className="block textbox"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.passphrase || ''}
|
||||
/>
|
||||
<div className="textbox flex flex-row items-center w-[300px] h-[1.70rem] relative">
|
||||
<input
|
||||
id="passphrase"
|
||||
type={passwordVisible ? 'text' : 'password'}
|
||||
name="passphrase"
|
||||
className="outline-none w-64 bg-transparent"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.passphrase || ''}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm absolute right-0 l"
|
||||
onClick={() => setPasswordVisible(!passwordVisible)}
|
||||
>
|
||||
{passwordVisible ? <IconEyeOff size={18} strokeWidth={1.5} /> : <IconEye size={18} strokeWidth={1.5} />}
|
||||
</button>
|
||||
</div>
|
||||
{formik.touched.passphrase && formik.errors.passphrase ? (
|
||||
<div className="ml-1 text-red-500">{formik.errors.passphrase}</div>
|
||||
) : null}
|
||||
|
||||
@@ -3,7 +3,7 @@ import get from 'lodash/get';
|
||||
import { updateCollectionDocs } from 'providers/ReduxStore/slices/collections';
|
||||
import { useTheme } from 'providers/Theme';
|
||||
import { useState } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import Markdown from 'components/MarkDown';
|
||||
import CodeEditor from 'components/CodeEditor';
|
||||
@@ -11,9 +11,10 @@ import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const Docs = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
const { displayedTheme } = useTheme();
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const docs = get(collection, 'root.docs', '');
|
||||
const preferences = useSelector((state) => state.app.preferences);
|
||||
|
||||
const toggleViewMode = () => {
|
||||
setIsEditing((prev) => !prev);
|
||||
@@ -39,11 +40,12 @@ const Docs = ({ collection }) => {
|
||||
{isEditing ? (
|
||||
<CodeEditor
|
||||
collection={collection}
|
||||
theme={storedTheme}
|
||||
theme={displayedTheme}
|
||||
value={docs || ''}
|
||||
onEdit={onEdit}
|
||||
onSave={onSave}
|
||||
mode="application/text"
|
||||
font={get(preferences, 'font.codeFont', 'default')}
|
||||
/>
|
||||
) : (
|
||||
<Markdown onDoubleClick={toggleViewMode} content={docs} />
|
||||
|
||||
@@ -63,7 +63,10 @@ const Headers = ({ collection }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="w-full">
|
||||
<StyledWrapper className="h-full w-full">
|
||||
<div className="text-xs mb-4 text-muted">
|
||||
Add request headers that will be sent with every request in this collection.
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -23,6 +23,7 @@ function countRequests(items) {
|
||||
const Info = ({ 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="">
|
||||
@@ -33,6 +34,10 @@ const Info = ({ collection }) => {
|
||||
<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>
|
||||
|
||||
@@ -27,8 +27,10 @@ const PresetsSettings = ({ collection }) => {
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<h1 className="font-medium mb-3">Collection Presets</h1>
|
||||
<StyledWrapper className="h-full w-full">
|
||||
<div className="text-xs mb-4 text-muted">
|
||||
These presets will be used as the default values for new requests in this collection.
|
||||
</div>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label flex items-center" htmlFor="enabled">
|
||||
@@ -66,7 +68,7 @@ const PresetsSettings = ({ collection }) => {
|
||||
<label className="settings-label" htmlFor="requestUrl">
|
||||
Base URL
|
||||
</label>
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center w-full">
|
||||
<div className="flex items-center flex-grow input-container h-full">
|
||||
<input
|
||||
id="request-url"
|
||||
@@ -79,6 +81,7 @@ const PresetsSettings = ({ collection }) => {
|
||||
spellCheck="false"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.requestUrl || ''}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,8 @@ import Tooltip from 'components/Tooltip';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import * as Yup from 'yup';
|
||||
import toast from 'react-hot-toast';
|
||||
import { IconEye, IconEyeOff } from '@tabler/icons';
|
||||
import { useState } from 'react';
|
||||
|
||||
const ProxySettings = ({ proxyConfig, onUpdate }) => {
|
||||
const proxySchema = Yup.object({
|
||||
@@ -78,6 +80,7 @@ const ProxySettings = ({ proxyConfig, onUpdate }) => {
|
||||
});
|
||||
}
|
||||
});
|
||||
const [passwordVisible, setPasswordVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
formik.setValues({
|
||||
@@ -95,8 +98,8 @@ const ProxySettings = ({ proxyConfig, onUpdate }) => {
|
||||
}, [proxyConfig]);
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<h1 className="font-medium mb-3">Proxy Settings</h1>
|
||||
<StyledWrapper className="h-full w-full">
|
||||
<div className="text-xs mb-4 text-muted">Configure proxy settings for this collection.</div>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label flex items-center" htmlFor="enabled">
|
||||
@@ -164,7 +167,7 @@ const ProxySettings = ({ proxyConfig, onUpdate }) => {
|
||||
onChange={formik.handleChange}
|
||||
className="mr-1"
|
||||
/>
|
||||
http
|
||||
HTTP
|
||||
</label>
|
||||
<label className="flex items-center ml-4">
|
||||
<input
|
||||
@@ -175,18 +178,18 @@ const ProxySettings = ({ proxyConfig, onUpdate }) => {
|
||||
onChange={formik.handleChange}
|
||||
className="mr-1"
|
||||
/>
|
||||
https
|
||||
HTTPS
|
||||
</label>
|
||||
<label className="flex items-center ml-4">
|
||||
<input
|
||||
type="radio"
|
||||
name="protocol"
|
||||
value="socks5"
|
||||
value="socks4"
|
||||
checked={formik.values.protocol === 'socks4'}
|
||||
onChange={formik.handleChange}
|
||||
className="mr-1"
|
||||
/>
|
||||
socks4
|
||||
SOCKS4
|
||||
</label>
|
||||
<label className="flex items-center ml-4">
|
||||
<input
|
||||
@@ -197,7 +200,7 @@ const ProxySettings = ({ proxyConfig, onUpdate }) => {
|
||||
onChange={formik.handleChange}
|
||||
className="mr-1"
|
||||
/>
|
||||
socks5
|
||||
SOCKS5
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -277,18 +280,27 @@ const ProxySettings = ({ proxyConfig, onUpdate }) => {
|
||||
<label className="settings-label" htmlFor="auth.password">
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
id="auth.password"
|
||||
type="text"
|
||||
name="auth.password"
|
||||
className="block textbox"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
value={formik.values.auth.password}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
<div className="textbox flex flex-row items-center w-[13.2rem] h-[1.70rem] relative">
|
||||
<input
|
||||
id="auth.password"
|
||||
type={passwordVisible ? 'text' : 'password'}
|
||||
name="auth.password"
|
||||
className="outline-none bg-transparent w-[10.5rem]"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
value={formik.values.auth.password}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm absolute right-0"
|
||||
onClick={() => setPasswordVisible(!passwordVisible)}
|
||||
>
|
||||
{passwordVisible ? <IconEyeOff size={18} strokeWidth={1.5} /> : <IconEye size={18} strokeWidth={1.5} />}
|
||||
</button>
|
||||
</div>
|
||||
{formik.touched.auth?.password && formik.errors.auth?.password ? (
|
||||
<div className="ml-3 text-red-500">{formik.errors.auth.password}</div>
|
||||
) : null}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import CodeEditor from 'components/CodeEditor';
|
||||
import { updateCollectionRequestScript, updateCollectionResponseScript } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
@@ -12,7 +12,8 @@ const Script = ({ collection }) => {
|
||||
const requestScript = get(collection, 'root.request.script.req', '');
|
||||
const responseScript = get(collection, 'root.request.script.res', '');
|
||||
|
||||
const { storedTheme } = useTheme();
|
||||
const { displayedTheme } = useTheme();
|
||||
const preferences = useSelector((state) => state.app.preferences);
|
||||
|
||||
const onRequestScriptEdit = (value) => {
|
||||
dispatch(
|
||||
@@ -37,16 +38,20 @@ const Script = ({ collection }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="w-full flex flex-col">
|
||||
<StyledWrapper className="w-full flex flex-col h-full">
|
||||
<div className="text-xs mb-4 text-muted">
|
||||
Write pre and post-request scripts that will run before and after any request in this collection is sent.
|
||||
</div>
|
||||
<div className="flex-1 mt-2">
|
||||
<div className="mb-1 title text-xs">Pre Request</div>
|
||||
<CodeEditor
|
||||
collection={collection}
|
||||
value={requestScript || ''}
|
||||
theme={storedTheme}
|
||||
theme={displayedTheme}
|
||||
onEdit={onRequestScriptEdit}
|
||||
mode="javascript"
|
||||
onSave={handleSave}
|
||||
font={get(preferences, 'font.codeFont', 'default')}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 mt-6">
|
||||
@@ -54,10 +59,11 @@ const Script = ({ collection }) => {
|
||||
<CodeEditor
|
||||
collection={collection}
|
||||
value={responseScript || ''}
|
||||
theme={storedTheme}
|
||||
theme={displayedTheme}
|
||||
onEdit={onResponseScriptEdit}
|
||||
mode="javascript"
|
||||
onSave={handleSave}
|
||||
font={get(preferences, 'font.codeFont', 'default')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import CodeEditor from 'components/CodeEditor';
|
||||
import { updateCollectionTests } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
@@ -11,7 +11,8 @@ const Tests = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const tests = get(collection, 'root.request.tests', '');
|
||||
|
||||
const { storedTheme } = useTheme();
|
||||
const { displayedTheme } = useTheme();
|
||||
const preferences = useSelector((state) => state.app.preferences);
|
||||
|
||||
const onEdit = (value) => {
|
||||
dispatch(
|
||||
@@ -26,13 +27,15 @@ const Tests = ({ collection }) => {
|
||||
|
||||
return (
|
||||
<StyledWrapper className="w-full flex flex-col h-full">
|
||||
<div className="text-xs mb-4 text-muted">These tests will run any time a request in this collection is sent.</div>
|
||||
<CodeEditor
|
||||
collection={collection}
|
||||
value={tests || ''}
|
||||
theme={storedTheme}
|
||||
theme={displayedTheme}
|
||||
onEdit={onEdit}
|
||||
mode="javascript"
|
||||
onSave={handleSave}
|
||||
font={get(preferences, 'font.codeFont', 'default')}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
|
||||
@@ -147,9 +147,7 @@ const CollectionSettings = ({ collection }) => {
|
||||
Info
|
||||
</div>
|
||||
</div>
|
||||
<section className={`flex ${['auth', 'script', 'docs', 'clientCert'].includes(tab) ? '' : 'mt-4'}`}>
|
||||
{getTabPanel(tab)}
|
||||
</section>
|
||||
<section className="mt-4 h-full">{getTabPanel(tab)}</section>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'github-markdown-css/github-markdown.css';
|
||||
import get from 'lodash/get';
|
||||
import { updateRequestDocs } from 'providers/ReduxStore/slices/collections';
|
||||
import { useTheme } from 'providers/Theme/index';
|
||||
import { useTheme } from 'providers/Theme';
|
||||
import { useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||
@@ -11,7 +11,7 @@ import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const Documentation = ({ item, collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
const { displayedTheme } = useTheme();
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const docs = item.draft ? get(item, 'draft.request.docs') : get(item, 'request.docs');
|
||||
const preferences = useSelector((state) => state.app.preferences);
|
||||
@@ -45,7 +45,7 @@ const Documentation = ({ item, collection }) => {
|
||||
{isEditing ? (
|
||||
<CodeEditor
|
||||
collection={collection}
|
||||
theme={storedTheme}
|
||||
theme={displayedTheme}
|
||||
font={get(preferences, 'font.codeFont', 'default')}
|
||||
value={docs || ''}
|
||||
onEdit={onEdit}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
.current-enviroment {
|
||||
.current-environment {
|
||||
background-color: ${(props) => props.theme.sidebar.badge.bg};
|
||||
border-radius: 15px;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useRef, forwardRef, useState } from 'react';
|
||||
import find from 'lodash/find';
|
||||
import Dropdown from 'components/Dropdown';
|
||||
import { selectEnvironment } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { updateEnvironmentSettingsModalVisibility } from 'providers/ReduxStore/slices/app';
|
||||
import { IconSettings, IconCaretDown, IconDatabase, IconDatabaseOff } from '@tabler/icons';
|
||||
import EnvironmentSettings from '../EnvironmentSettings';
|
||||
import toast from 'react-hot-toast';
|
||||
@@ -17,13 +18,23 @@ const EnvironmentSelector = ({ collection }) => {
|
||||
|
||||
const Icon = forwardRef((props, ref) => {
|
||||
return (
|
||||
<div ref={ref} className="current-enviroment flex items-center justify-center pl-3 pr-2 py-1 select-none">
|
||||
<div ref={ref} className="current-environment flex items-center justify-center pl-3 pr-2 py-1 select-none">
|
||||
{activeEnvironment ? activeEnvironment.name : 'No Environment'}
|
||||
<IconCaretDown className="caret" size={14} strokeWidth={2} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const handleSettingsIconClick = () => {
|
||||
setOpenSettingsModal(true);
|
||||
dispatch(updateEnvironmentSettingsModalVisibility(true));
|
||||
};
|
||||
|
||||
const handleModalClose = () => {
|
||||
setOpenSettingsModal(false);
|
||||
dispatch(updateEnvironmentSettingsModalVisibility(false));
|
||||
};
|
||||
|
||||
const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
|
||||
|
||||
const onSelect = (environment) => {
|
||||
@@ -52,7 +63,7 @@ const EnvironmentSelector = ({ collection }) => {
|
||||
dropdownTippyRef.current.hide();
|
||||
}}
|
||||
>
|
||||
<IconDatabase size={18} strokeWidth={1.5} /> <span className="ml-2">{e.name}</span>
|
||||
<IconDatabase size={18} strokeWidth={1.5} /> <span className="ml-2 break-all">{e.name}</span>
|
||||
</div>
|
||||
))
|
||||
: null}
|
||||
@@ -66,7 +77,7 @@ const EnvironmentSelector = ({ collection }) => {
|
||||
<IconDatabaseOff size={18} strokeWidth={1.5} />
|
||||
<span className="ml-2">No Environment</span>
|
||||
</div>
|
||||
<div className="dropdown-item border-top" onClick={() => setOpenSettingsModal(true)}>
|
||||
<div className="dropdown-item border-top" onClick={handleSettingsIconClick}>
|
||||
<div className="pr-2 text-gray-600">
|
||||
<IconSettings size={18} strokeWidth={1.5} />
|
||||
</div>
|
||||
@@ -74,7 +85,7 @@ const EnvironmentSelector = ({ collection }) => {
|
||||
</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
{openSettingsModal && <EnvironmentSettings collection={collection} onClose={() => setOpenSettingsModal(false)} />}
|
||||
{openSettingsModal && <EnvironmentSettings collection={collection} onClose={handleModalClose} />}
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import React from 'react';
|
||||
import { IconAlertTriangle } from '@tabler/icons';
|
||||
import Modal from 'components/Modal';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
const ConfirmSwitchEnv = ({ onCancel }) => {
|
||||
return createPortal(
|
||||
<Modal
|
||||
size="md"
|
||||
title="Unsaved changes"
|
||||
confirmText="Save and Close"
|
||||
cancelText="Close without saving"
|
||||
disableEscapeKey={true}
|
||||
disableCloseOnOutsideClick={true}
|
||||
closeModalFadeTimeout={150}
|
||||
handleCancel={onCancel}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}}
|
||||
hideFooter={true}
|
||||
>
|
||||
<div className="flex items-center font-normal">
|
||||
<IconAlertTriangle size={32} strokeWidth={1.5} className="text-yellow-600" />
|
||||
<h1 className="ml-2 text-lg font-semibold">Hold on..</h1>
|
||||
</div>
|
||||
<div className="font-normal mt-4">You have unsaved changes in this environment.</div>
|
||||
|
||||
<div className="flex justify-between mt-6">
|
||||
<div>
|
||||
<button className="btn btn-sm btn-danger" onClick={onCancel}>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</Modal>,
|
||||
document.body
|
||||
);
|
||||
};
|
||||
|
||||
export default ConfirmSwitchEnv;
|
||||
@@ -1,18 +1,19 @@
|
||||
import React from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { IconTrash } from '@tabler/icons';
|
||||
import { useTheme } from 'providers/Theme';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { saveEnvironment } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import SingleLineEditor from 'components/SingleLineEditor';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { uuid } from 'utils/common';
|
||||
import { maskInputValue } from 'utils/collections';
|
||||
import { useFormik } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import { uuid } from 'utils/common';
|
||||
import { variableNameRegex } from 'utils/common/regex';
|
||||
import { saveEnvironment } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
const EnvironmentVariables = ({ environment, collection }) => {
|
||||
const EnvironmentVariables = ({ environment, collection, setIsModified, originalEnvironmentVariables }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
|
||||
@@ -45,11 +46,17 @@ const EnvironmentVariables = ({ environment, collection }) => {
|
||||
.then(() => {
|
||||
toast.success('Changes saved successfully');
|
||||
formik.resetForm({ values });
|
||||
setIsModified(false);
|
||||
})
|
||||
.catch(() => toast.error('An error occurred while saving the changes'));
|
||||
}
|
||||
});
|
||||
|
||||
// Effect to track modifications.
|
||||
React.useEffect(() => {
|
||||
setIsModified(formik.dirty);
|
||||
}, [formik.dirty]);
|
||||
|
||||
const ErrorMessage = ({ name }) => {
|
||||
const meta = formik.getFieldMeta(name);
|
||||
if (!meta.error) {
|
||||
@@ -79,73 +86,82 @@ const EnvironmentVariables = ({ environment, collection }) => {
|
||||
formik.setValues(formik.values.filter((variable) => variable.uid !== id));
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
formik.resetForm({ originalEnvironmentVariables });
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="w-full mt-6 mb-6">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Enabled</td>
|
||||
<td>Name</td>
|
||||
<td>Value</td>
|
||||
<td>Secret</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{formik.values.map((variable, index) => (
|
||||
<tr key={variable.uid}>
|
||||
<td className="text-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mr-3 mousetrap"
|
||||
name={`${index}.enabled`}
|
||||
checked={variable.enabled}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
className="mousetrap"
|
||||
id={`${index}.name`}
|
||||
name={`${index}.name`}
|
||||
value={variable.name}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
<ErrorMessage name={`${index}.name`} />
|
||||
</td>
|
||||
<td>
|
||||
<SingleLineEditor
|
||||
theme={storedTheme}
|
||||
collection={collection}
|
||||
name={`${index}.value`}
|
||||
value={variable.value}
|
||||
onChange={(newValue) => formik.setFieldValue(`${index}.value`, newValue, true)}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mr-3 mousetrap"
|
||||
name={`${index}.secret`}
|
||||
checked={variable.secret}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<button onClick={() => handleRemoveVar(variable.uid)}>
|
||||
<IconTrash strokeWidth={1.5} size={20} />
|
||||
</button>
|
||||
</td>
|
||||
<div className="h-[50vh] overflow-y-auto w-full">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Enabled</td>
|
||||
<td>Name</td>
|
||||
<td>Value</td>
|
||||
<td>Secret</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</thead>
|
||||
<tbody>
|
||||
{formik.values.map((variable, index) => (
|
||||
<tr key={variable.uid}>
|
||||
<td className="text-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mr-3 mousetrap"
|
||||
name={`${index}.enabled`}
|
||||
checked={variable.enabled}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
className="mousetrap"
|
||||
id={`${index}.name`}
|
||||
name={`${index}.name`}
|
||||
value={variable.name}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
<ErrorMessage name={`${index}.name`} />
|
||||
</td>
|
||||
<td>
|
||||
{variable.secret ? (
|
||||
<div className="overflow-hidden text-ellipsis">{maskInputValue(variable.value)}</div>
|
||||
) : (
|
||||
<SingleLineEditor
|
||||
theme={storedTheme}
|
||||
collection={collection}
|
||||
name={`${index}.value`}
|
||||
value={variable.value}
|
||||
onChange={(newValue) => formik.setFieldValue(`${index}.value`, newValue, true)}
|
||||
/>
|
||||
)}
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mr-3 mousetrap"
|
||||
name={`${index}.secret`}
|
||||
checked={variable.secret}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<button onClick={() => handleRemoveVar(variable.uid)}>
|
||||
<IconTrash strokeWidth={1.5} size={20} />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<button className="btn-add-param text-link pr-2 py-3 mt-2 select-none" onClick={addVariable}>
|
||||
+ Add Variable
|
||||
@@ -156,6 +172,9 @@ const EnvironmentVariables = ({ environment, collection }) => {
|
||||
<button type="submit" className="submit btn btn-md btn-secondary mt-2" onClick={formik.handleSubmit}>
|
||||
Save
|
||||
</button>
|
||||
<button type="submit" className="ml-2 px-1 submit btn btn-md btn-secondary mt-2" onClick={handleReset}>
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
|
||||
@@ -5,7 +5,7 @@ import DeleteEnvironment from '../../DeleteEnvironment';
|
||||
import RenameEnvironment from '../../RenameEnvironment';
|
||||
import EnvironmentVariables from './EnvironmentVariables';
|
||||
|
||||
const EnvironmentDetails = ({ environment, collection }) => {
|
||||
const EnvironmentDetails = ({ environment, collection, setIsModified }) => {
|
||||
const [openEditModal, setOpenEditModal] = useState(false);
|
||||
const [openDeleteModal, setOpenDeleteModal] = useState(false);
|
||||
const [openCopyModal, setOpenCopyModal] = useState(false);
|
||||
@@ -28,7 +28,7 @@ const EnvironmentDetails = ({ environment, collection }) => {
|
||||
<div className="flex">
|
||||
<div className="flex flex-grow items-center">
|
||||
<IconDatabase className="cursor-pointer" size={20} strokeWidth={1.5} />
|
||||
<span className="ml-1 font-semibold">{environment.name}</span>
|
||||
<span className="ml-1 font-semibold break-all">{environment.name}</span>
|
||||
</div>
|
||||
<div className="flex gap-x-4 pl-4">
|
||||
<IconEdit className="cursor-pointer" size={20} strokeWidth={1.5} onClick={() => setOpenEditModal(true)} />
|
||||
@@ -38,7 +38,7 @@ const EnvironmentDetails = ({ environment, collection }) => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<EnvironmentVariables key={environment.uid} environment={environment} collection={collection} />
|
||||
<EnvironmentVariables environment={environment} collection={collection} setIsModified={setIsModified} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState, forwardRef, useRef } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { findEnvironmentInCollection } from 'utils/collections';
|
||||
import usePrevious from 'hooks/usePrevious';
|
||||
import EnvironmentDetails from './EnvironmentDetails';
|
||||
@@ -7,19 +7,23 @@ import { IconDownload, IconShieldLock } from '@tabler/icons';
|
||||
import ImportEnvironment from '../ImportEnvironment';
|
||||
import ManageSecrets from '../ManageSecrets';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import ConfirmSwitchEnv from './ConfirmSwitchEnv';
|
||||
|
||||
const EnvironmentList = ({ collection }) => {
|
||||
const EnvironmentList = ({ selectedEnvironment, setSelectedEnvironment, collection, isModified, setIsModified }) => {
|
||||
const { environments } = collection;
|
||||
const [selectedEnvironment, setSelectedEnvironment] = useState(null);
|
||||
const [openCreateModal, setOpenCreateModal] = useState(false);
|
||||
const [openImportModal, setOpenImportModal] = useState(false);
|
||||
const [openManageSecretsModal, setOpenManageSecretsModal] = useState(false);
|
||||
|
||||
const [switchEnvConfirmClose, setSwitchEnvConfirmClose] = useState(false);
|
||||
const [originalEnvironmentVariables, setOriginalEnvironmentVariables] = useState([]);
|
||||
|
||||
const envUids = environments ? environments.map((env) => env.uid) : [];
|
||||
const prevEnvUids = usePrevious(envUids);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEnvironment) {
|
||||
setOriginalEnvironmentVariables(selectedEnvironment.variables);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -32,7 +36,6 @@ const EnvironmentList = ({ collection }) => {
|
||||
}, [collection, environments, selectedEnvironment]);
|
||||
|
||||
useEffect(() => {
|
||||
// check env add
|
||||
if (prevEnvUids && prevEnvUids.length && envUids.length > prevEnvUids.length) {
|
||||
const newEnv = environments.find((env) => !prevEnvUids.includes(env.uid));
|
||||
if (newEnv) {
|
||||
@@ -40,23 +43,62 @@ const EnvironmentList = ({ collection }) => {
|
||||
}
|
||||
}
|
||||
|
||||
// check env delete
|
||||
if (prevEnvUids && prevEnvUids.length && envUids.length < prevEnvUids.length) {
|
||||
setSelectedEnvironment(environments && environments.length ? environments[0] : null);
|
||||
}
|
||||
}, [envUids, environments, prevEnvUids]);
|
||||
|
||||
const handleEnvironmentClick = (env) => {
|
||||
if (!isModified) {
|
||||
setSelectedEnvironment(env);
|
||||
} else {
|
||||
setSwitchEnvConfirmClose(true);
|
||||
}
|
||||
};
|
||||
|
||||
if (!selectedEnvironment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleCreateEnvClick = () => {
|
||||
if (!isModified) {
|
||||
setOpenCreateModal(true);
|
||||
} else {
|
||||
setSwitchEnvConfirmClose(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleImportClick = () => {
|
||||
if (!isModified) {
|
||||
setOpenImportModal(true);
|
||||
} else {
|
||||
setSwitchEnvConfirmClose(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSecretsClick = () => {
|
||||
setOpenManageSecretsModal(true);
|
||||
};
|
||||
|
||||
const handleConfirmSwitch = (saveChanges) => {
|
||||
if (!saveChanges) {
|
||||
setSwitchEnvConfirmClose(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
{openCreateModal && <CreateEnvironment collection={collection} onClose={() => setOpenCreateModal(false)} />}
|
||||
{openImportModal && <ImportEnvironment collection={collection} onClose={() => setOpenImportModal(false)} />}
|
||||
{openManageSecretsModal && <ManageSecrets onClose={() => setOpenManageSecretsModal(false)} />}
|
||||
|
||||
<div className="flex">
|
||||
<div>
|
||||
{switchEnvConfirmClose && (
|
||||
<div className="flex items-center justify-between tab-container px-1">
|
||||
<ConfirmSwitchEnv onCancel={() => handleConfirmSwitch(false)} />
|
||||
</div>
|
||||
)}
|
||||
<div className="environments-sidebar flex flex-col">
|
||||
{environments &&
|
||||
environments.length &&
|
||||
@@ -64,28 +106,33 @@ const EnvironmentList = ({ collection }) => {
|
||||
<div
|
||||
key={env.uid}
|
||||
className={selectedEnvironment.uid === env.uid ? 'environment-item active' : 'environment-item'}
|
||||
onClick={() => setSelectedEnvironment(env)}
|
||||
onClick={() => handleEnvironmentClick(env)} // Use handleEnvironmentClick to handle clicks
|
||||
>
|
||||
<span>{env.name}</span>
|
||||
<span className="break-all">{env.name}</span>
|
||||
</div>
|
||||
))}
|
||||
<div className="btn-create-environment" onClick={() => setOpenCreateModal(true)}>
|
||||
<div className="btn-create-environment" onClick={() => handleCreateEnvClick()}>
|
||||
+ <span>Create</span>
|
||||
</div>
|
||||
|
||||
<div className="mt-auto btn-import-environment">
|
||||
<div className="flex items-center" onClick={() => setOpenImportModal(true)}>
|
||||
<div className="flex items-center" onClick={() => handleImportClick()}>
|
||||
<IconDownload size={12} strokeWidth={2} />
|
||||
<span className="label ml-1 text-xs">Import</span>
|
||||
</div>
|
||||
<div className="flex items-center mt-2" onClick={() => setOpenManageSecretsModal(true)}>
|
||||
<div className="flex items-center mt-2" onClick={() => handleSecretsClick()}>
|
||||
<IconShieldLock size={12} strokeWidth={2} />
|
||||
<span className="label ml-1 text-xs">Managing Secrets</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<EnvironmentDetails environment={selectedEnvironment} collection={collection} />
|
||||
<EnvironmentDetails
|
||||
environment={selectedEnvironment}
|
||||
collection={collection}
|
||||
setIsModified={setIsModified}
|
||||
originalEnvironmentVariables={originalEnvironmentVariables}
|
||||
/>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
|
||||
@@ -13,7 +13,7 @@ const ManageSecrets = ({ onClose }) => {
|
||||
<p className="mt-2">
|
||||
Read more about it in our{' '}
|
||||
<a
|
||||
href="https://docs.usebruno.com/secrets-management/overview.html"
|
||||
href="https://docs.usebruno.com/secrets-management/overview"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-link hover:underline"
|
||||
|
||||
@@ -6,9 +6,11 @@ import StyledWrapper from './StyledWrapper';
|
||||
import ImportEnvironment from './ImportEnvironment';
|
||||
|
||||
const EnvironmentSettings = ({ collection, onClose }) => {
|
||||
const [isModified, setIsModified] = useState(false);
|
||||
const { environments } = collection;
|
||||
const [openCreateModal, setOpenCreateModal] = useState(false);
|
||||
const [openImportModal, setOpenImportModal] = useState(false);
|
||||
const [selectedEnvironment, setSelectedEnvironment] = useState(null);
|
||||
|
||||
if (!environments || !environments.length) {
|
||||
return (
|
||||
@@ -48,7 +50,13 @@ const EnvironmentSettings = ({ collection, onClose }) => {
|
||||
|
||||
return (
|
||||
<Modal size="lg" title="Environments" handleCancel={onClose} hideFooter={true}>
|
||||
<EnvironmentList collection={collection} />
|
||||
<EnvironmentList
|
||||
selectedEnvironment={selectedEnvironment}
|
||||
setSelectedEnvironment={setSelectedEnvironment}
|
||||
collection={collection}
|
||||
isModified={isModified}
|
||||
setIsModified={setIsModified}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
74
packages/bruno-app/src/components/FilePickerEditor/index.js
Normal file
74
packages/bruno-app/src/components/FilePickerEditor/index.js
Normal file
@@ -0,0 +1,74 @@
|
||||
import React from 'react';
|
||||
import path from 'path';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { browseFiles } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { IconX } from '@tabler/icons';
|
||||
import { isWindowsOS } from 'utils/common/platform';
|
||||
import slash from 'utils/common/slash';
|
||||
|
||||
const FilePickerEditor = ({ value, onChange, collection }) => {
|
||||
value = value || [];
|
||||
const dispatch = useDispatch();
|
||||
const filenames = value
|
||||
.filter((v) => v != null && v != '')
|
||||
.map((v) => {
|
||||
const separator = isWindowsOS() ? '\\' : '/';
|
||||
return v.split(separator).pop();
|
||||
});
|
||||
|
||||
// title is shown when hovering over the button
|
||||
const title = filenames.map((v) => `- ${v}`).join('\n');
|
||||
|
||||
const browse = () => {
|
||||
dispatch(browseFiles())
|
||||
.then((filePaths) => {
|
||||
// If file is in the collection's directory, then we use relative path
|
||||
// Otherwise, we use the absolute path
|
||||
filePaths = filePaths.map((filePath) => {
|
||||
const collectionDir = collection.pathname;
|
||||
|
||||
if (filePath.startsWith(collectionDir)) {
|
||||
return path.relative(slash(collectionDir), slash(filePath));
|
||||
}
|
||||
|
||||
return filePath;
|
||||
});
|
||||
|
||||
onChange(filePaths);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
const clear = () => {
|
||||
onChange('');
|
||||
};
|
||||
|
||||
const renderButtonText = (filenames) => {
|
||||
if (filenames.length == 1) {
|
||||
return filenames[0];
|
||||
}
|
||||
return filenames.length + ' files selected';
|
||||
};
|
||||
|
||||
return filenames.length > 0 ? (
|
||||
<div
|
||||
className="btn btn-secondary px-1"
|
||||
style={{ fontWeight: 400, width: '100%', textOverflow: 'ellipsis', overflowX: 'hidden' }}
|
||||
title={title}
|
||||
>
|
||||
<button className="align-middle" onClick={clear}>
|
||||
<IconX size={18} />
|
||||
</button>
|
||||
|
||||
{renderButtonText(filenames)}
|
||||
</div>
|
||||
) : (
|
||||
<button className="btn btn-secondary px-1" style={{ width: '100%' }} onClick={browse}>
|
||||
Select Files
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default FilePickerEditor;
|
||||
@@ -1,19 +1,13 @@
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import * as React from 'react';
|
||||
|
||||
const md = new MarkdownIt();
|
||||
|
||||
const Markdown = ({ onDoubleClick, content }) => {
|
||||
const handleOnDoubleClick = (event) => {
|
||||
switch (event.detail) {
|
||||
case 2: {
|
||||
onDoubleClick();
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
if (event?.detail === 2) {
|
||||
onDoubleClick();
|
||||
}
|
||||
};
|
||||
const htmlFromMarkdown = md.render(content || '');
|
||||
@@ -21,7 +21,7 @@ const Wrapper = styled.div`
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
overflow-y: auto;
|
||||
z-index: 10;
|
||||
z-index: 20;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ const Wrapper = styled.div`
|
||||
background: var(--color-background-top);
|
||||
border-radius: var(--border-radius);
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
z-index: 11;
|
||||
max-width: calc(100% - var(--spacing-base-unit));
|
||||
box-shadow: var(--box-shadow-base);
|
||||
display: flex;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const ModalHeader = ({ title, handleCancel }) => (
|
||||
const ModalHeader = ({ title, handleCancel, customHeader }) => (
|
||||
<div className="bruno-modal-header">
|
||||
{title ? <div className="bruno-modal-header-title">{title}</div> : null}
|
||||
{customHeader ? customHeader : <>{title ? <div className="bruno-modal-header-title">{title}</div> : null}</>}
|
||||
{handleCancel ? (
|
||||
<div className="close cursor-pointer" onClick={handleCancel ? () => handleCancel() : null}>
|
||||
×
|
||||
@@ -54,6 +54,7 @@ const ModalFooter = ({
|
||||
const Modal = ({
|
||||
size,
|
||||
title,
|
||||
customHeader,
|
||||
confirmText,
|
||||
cancelText,
|
||||
handleCancel,
|
||||
@@ -62,6 +63,9 @@ const Modal = ({
|
||||
confirmDisabled,
|
||||
hideCancel,
|
||||
hideFooter,
|
||||
disableCloseOnOutsideClick,
|
||||
disableEscapeKey,
|
||||
onClick,
|
||||
closeModalFadeTimeout = 500
|
||||
}) => {
|
||||
const [isClosing, setIsClosing] = useState(false);
|
||||
@@ -78,12 +82,13 @@ const Modal = ({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (disableEscapeKey) return;
|
||||
document.addEventListener('keydown', escFunction, false);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('keydown', escFunction, false);
|
||||
};
|
||||
}, []);
|
||||
}, [disableEscapeKey, document]);
|
||||
|
||||
let classes = 'bruno-modal';
|
||||
if (isClosing) {
|
||||
@@ -93,9 +98,9 @@ const Modal = ({
|
||||
classes += ' modal-footer-none';
|
||||
}
|
||||
return (
|
||||
<StyledWrapper className={classes}>
|
||||
<StyledWrapper className={classes} onClick={onClick ? (e) => onClick(e) : null}>
|
||||
<div className={`bruno-modal-card modal-${size}`}>
|
||||
<ModalHeader title={title} handleCancel={() => closeModal({ type: 'icon' })} />
|
||||
<ModalHeader title={title} handleCancel={() => closeModal({ type: 'icon' })} customHeader={customHeader} />
|
||||
<ModalContent>{children}</ModalContent>
|
||||
<ModalFooter
|
||||
confirmText={confirmText}
|
||||
@@ -111,9 +116,13 @@ const Modal = ({
|
||||
{/* Clicking on backdrop closes the modal */}
|
||||
<div
|
||||
className="bruno-modal-backdrop"
|
||||
onClick={() => {
|
||||
closeModal({ type: 'backdrop' });
|
||||
}}
|
||||
onClick={
|
||||
disableCloseOnOutsideClick
|
||||
? null
|
||||
: () => {
|
||||
closeModal({ type: 'backdrop' });
|
||||
}
|
||||
}
|
||||
/>
|
||||
</StyledWrapper>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
width: 100%;
|
||||
height: fit-content;
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
|
||||
.CodeMirror {
|
||||
background: transparent;
|
||||
height: fit-content;
|
||||
font-size: 14px;
|
||||
line-height: 30px;
|
||||
overflow: hidden;
|
||||
|
||||
.CodeMirror-scroll {
|
||||
overflow: hidden !important;
|
||||
${'' /* padding-bottom: 50px !important; */}
|
||||
position: relative;
|
||||
display: contents;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar,
|
||||
.CodeMirror-hscrollbar,
|
||||
.CodeMirror-scrollbar-filler {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.CodeMirror-lines {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-cursor {
|
||||
height: 20px !important;
|
||||
margin-top: 5px !important;
|
||||
border-left: 1px solid ${(props) => props.theme.text} !important;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: Inter, sans-serif !important;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.CodeMirror-line {
|
||||
color: ${(props) => props.theme.text};
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-selected {
|
||||
background-color: rgba(212, 125, 59, 0.3);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
140
packages/bruno-app/src/components/MultiLineEditor/index.js
Normal file
140
packages/bruno-app/src/components/MultiLineEditor/index.js
Normal file
@@ -0,0 +1,140 @@
|
||||
import React, { Component } from 'react';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { getAllVariables } from 'utils/collections';
|
||||
import { defineCodeMirrorBrunoVariablesMode } from 'utils/common/codemirror';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
let CodeMirror;
|
||||
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
|
||||
|
||||
if (!SERVER_RENDERED) {
|
||||
CodeMirror = require('codemirror');
|
||||
}
|
||||
|
||||
class MultiLineEditor extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
// Keep a cached version of the value, this cache will be updated when the
|
||||
// editor is updated, which can later be used to protect the editor from
|
||||
// unnecessary updates during the update lifecycle.
|
||||
this.cachedValue = props.value || '';
|
||||
this.editorRef = React.createRef();
|
||||
this.variables = {};
|
||||
}
|
||||
componentDidMount() {
|
||||
// Initialize CodeMirror as a single line editor
|
||||
/** @type {import("codemirror").Editor} */
|
||||
this.editor = CodeMirror(this.editorRef.current, {
|
||||
lineWrapping: false,
|
||||
lineNumbers: false,
|
||||
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
|
||||
mode: 'brunovariables',
|
||||
brunoVarInfo: {
|
||||
variables: getAllVariables(this.props.collection)
|
||||
},
|
||||
scrollbarStyle: null,
|
||||
tabindex: 0,
|
||||
extraKeys: {
|
||||
Enter: () => {
|
||||
if (this.props.onRun) {
|
||||
this.props.onRun();
|
||||
}
|
||||
},
|
||||
'Ctrl-Enter': () => {
|
||||
if (this.props.onRun) {
|
||||
this.props.onRun();
|
||||
}
|
||||
},
|
||||
'Cmd-Enter': () => {
|
||||
if (this.props.onRun) {
|
||||
this.props.onRun();
|
||||
}
|
||||
},
|
||||
'Alt-Enter': () => {
|
||||
this.editor.setValue(this.editor.getValue() + '\n');
|
||||
this.editor.setCursor({ line: this.editor.lineCount(), ch: 0 });
|
||||
},
|
||||
'Shift-Enter': () => {
|
||||
this.editor.setValue(this.editor.getValue() + '\n');
|
||||
this.editor.setCursor({ line: this.editor.lineCount(), ch: 0 });
|
||||
},
|
||||
'Cmd-S': () => {
|
||||
if (this.props.onSave) {
|
||||
this.props.onSave();
|
||||
}
|
||||
},
|
||||
'Ctrl-S': () => {
|
||||
if (this.props.onSave) {
|
||||
this.props.onSave();
|
||||
}
|
||||
},
|
||||
'Cmd-F': () => {},
|
||||
'Ctrl-F': () => {},
|
||||
// Tabbing disabled to make tabindex work
|
||||
Tab: false,
|
||||
'Shift-Tab': false
|
||||
}
|
||||
});
|
||||
if (this.props.autocomplete) {
|
||||
this.editor.on('keyup', (cm, event) => {
|
||||
if (!cm.state.completionActive /*Enables keyboard navigation in autocomplete list*/ && event.keyCode != 13) {
|
||||
/*Enter - do not open autocomplete list just after item has been selected in it*/
|
||||
CodeMirror.commands.autocomplete(cm, CodeMirror.hint.anyword, { autocomplete: this.props.autocomplete });
|
||||
}
|
||||
});
|
||||
}
|
||||
this.editor.setValue(String(this.props.value) || '');
|
||||
this.editor.on('change', this._onEdit);
|
||||
this.addOverlay();
|
||||
}
|
||||
|
||||
_onEdit = () => {
|
||||
if (!this.ignoreChangeEvent && this.editor) {
|
||||
this.cachedValue = this.editor.getValue();
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(this.cachedValue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
// Ensure the changes caused by this update are not interpreted as
|
||||
// user-input changes which could otherwise result in an infinite
|
||||
// event loop.
|
||||
this.ignoreChangeEvent = true;
|
||||
|
||||
let variables = getAllVariables(this.props.collection);
|
||||
if (!isEqual(variables, this.variables)) {
|
||||
this.editor.options.brunoVarInfo.variables = variables;
|
||||
this.addOverlay();
|
||||
}
|
||||
if (this.props.theme !== prevProps.theme && this.editor) {
|
||||
this.editor.setOption('theme', this.props.theme === 'dark' ? 'monokai' : 'default');
|
||||
}
|
||||
if (this.props.value !== prevProps.value && this.props.value !== this.cachedValue && this.editor) {
|
||||
this.cachedValue = String(this.props.value);
|
||||
this.editor.setValue(String(this.props.value) || '');
|
||||
}
|
||||
if (this.editorRef?.current) {
|
||||
this.editorRef.current.scrollTo(0, 10000);
|
||||
}
|
||||
this.ignoreChangeEvent = false;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.editor.getWrapperElement().remove();
|
||||
}
|
||||
|
||||
addOverlay = () => {
|
||||
let variables = getAllVariables(this.props.collection);
|
||||
this.variables = variables;
|
||||
|
||||
defineCodeMirrorBrunoVariablesMode(variables, 'text/plain');
|
||||
this.editor.setOption('mode', 'brunovariables');
|
||||
};
|
||||
|
||||
render() {
|
||||
return <StyledWrapper ref={this.editorRef} className="single-line-editor"></StyledWrapper>;
|
||||
}
|
||||
}
|
||||
export default MultiLineEditor;
|
||||
@@ -0,0 +1,85 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
.notifications-modal {
|
||||
margin-inline: -1rem;
|
||||
margin-block: -1.5rem;
|
||||
background-color: ${(props) => props.theme.notifications.bg};
|
||||
}
|
||||
|
||||
.notification-count {
|
||||
display: flex;
|
||||
color: white;
|
||||
position: absolute;
|
||||
top: -0.625rem;
|
||||
right: -0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
justify-content: center;
|
||||
font-size: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: ${(props) => props.theme.colors.text.yellow};
|
||||
border: solid 2px ${(props) => props.theme.sidebar.bg};
|
||||
min-width: 1.25rem;
|
||||
}
|
||||
|
||||
button.mark-as-read {
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
|
||||
ul.notifications {
|
||||
background-color: ${(props) => props.theme.notifications.list.bg};
|
||||
border-right: solid 1px ${(props) => props.theme.notifications.list.borderRight};
|
||||
min-height: 400px;
|
||||
height: 100%;
|
||||
max-height: 85vh;
|
||||
overflow-y: auto;
|
||||
|
||||
li {
|
||||
min-width: 150px;
|
||||
cursor: pointer;
|
||||
padding: 0.5rem 0.625rem;
|
||||
border-left: solid 2px transparent;
|
||||
color: ${(props) => props.theme.textLink};
|
||||
border-bottom: solid 1px ${(props) => props.theme.notifications.list.borderBottom};
|
||||
&:hover {
|
||||
background-color: ${(props) => props.theme.notifications.list.hoverBg};
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: ${(props) => props.theme.text} !important;
|
||||
background-color: ${(props) => props.theme.notifications.list.active.bg} !important;
|
||||
border-left: solid 2px ${(props) => props.theme.notifications.list.active.border};
|
||||
&:hover {
|
||||
background-color: ${(props) => props.theme.notifications.list.active.hoverBg} !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.read {
|
||||
color: ${(props) => props.theme.text} !important;
|
||||
}
|
||||
|
||||
.notification-date {
|
||||
font-size: 0.6875rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notification-title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.notification-date {
|
||||
color: ${(props) => props.theme.colors.text.muted};
|
||||
}
|
||||
|
||||
.pagination {
|
||||
background-color: ${(props) => props.theme.notifications.list.bg};
|
||||
border-right: solid 1px ${(props) => props.theme.notifications.list.borderRight};
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
192
packages/bruno-app/src/components/Notifications/index.js
Normal file
192
packages/bruno-app/src/components/Notifications/index.js
Normal file
@@ -0,0 +1,192 @@
|
||||
import { IconBell } from '@tabler/icons';
|
||||
import { useState } from 'react';
|
||||
import StyledWrapper from './StyleWrapper';
|
||||
import Modal from 'components/Modal/index';
|
||||
import { useEffect } from 'react';
|
||||
import {
|
||||
fetchNotifications,
|
||||
markAllNotificationsAsRead,
|
||||
markNotificationAsRead
|
||||
} from 'providers/ReduxStore/slices/notifications';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { humanizeDate, relativeDate } from 'utils/common';
|
||||
|
||||
const PAGE_SIZE = 5;
|
||||
|
||||
const Notifications = () => {
|
||||
const dispatch = useDispatch();
|
||||
const notifications = useSelector((state) => state.notifications.notifications);
|
||||
|
||||
const [showNotificationsModal, setShowNotificationsModal] = useState(false);
|
||||
const [selectedNotification, setSelectedNotification] = useState(null);
|
||||
const [pageNumber, setPageNumber] = useState(1);
|
||||
|
||||
const notificationsStartIndex = (pageNumber - 1) * PAGE_SIZE;
|
||||
const notificationsEndIndex = pageNumber * PAGE_SIZE;
|
||||
const totalPages = Math.ceil(notifications.length / PAGE_SIZE);
|
||||
const unreadNotifications = notifications.filter((notification) => !notification.read);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchNotifications());
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
reset();
|
||||
}, [showNotificationsModal]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedNotification && notifications?.length > 0 && showNotificationsModal) {
|
||||
let firstNotification = notifications[0];
|
||||
setSelectedNotification(firstNotification);
|
||||
dispatch(markNotificationAsRead({ notificationId: firstNotification?.id }));
|
||||
}
|
||||
}, [notifications, selectedNotification, showNotificationsModal]);
|
||||
|
||||
const reset = () => {
|
||||
setSelectedNotification(null);
|
||||
setPageNumber(1);
|
||||
};
|
||||
|
||||
const handlePrev = (e) => {
|
||||
if (pageNumber - 1 < 1) return;
|
||||
setPageNumber(pageNumber - 1);
|
||||
};
|
||||
|
||||
const handleNext = (e) => {
|
||||
if (pageNumber + 1 > totalPages) return;
|
||||
setPageNumber(pageNumber + 1);
|
||||
};
|
||||
|
||||
const handleNotificationItemClick = (notification) => (e) => {
|
||||
e.preventDefault();
|
||||
setSelectedNotification(notification);
|
||||
dispatch(markNotificationAsRead({ notificationId: notification?.id }));
|
||||
};
|
||||
|
||||
const modalCustomHeader = (
|
||||
<div className="flex flex-row gap-8">
|
||||
<div>NOTIFICATIONS</div>
|
||||
{unreadNotifications.length > 0 && (
|
||||
<>
|
||||
<div className="normal-case font-normal">
|
||||
{unreadNotifications.length} <span>unread notifications</span>
|
||||
</div>
|
||||
<button
|
||||
className={`select-none ${1 == 2 ? 'opacity-50' : 'text-link mark-as-read cursor-pointer hover:underline'}`}
|
||||
onClick={() => dispatch(markAllNotificationsAsRead())}
|
||||
>
|
||||
{'Mark all as read'}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<a
|
||||
title="Notifications"
|
||||
className="relative cursor-pointer"
|
||||
onClick={() => {
|
||||
dispatch(fetchNotifications());
|
||||
setShowNotificationsModal(true);
|
||||
}}
|
||||
>
|
||||
<IconBell
|
||||
size={18}
|
||||
strokeWidth={1.5}
|
||||
className={`mr-2 hover:text-gray-700 ${unreadNotifications?.length > 0 ? 'bell' : ''}`}
|
||||
/>
|
||||
{unreadNotifications.length > 0 && (
|
||||
<span className="notification-count text-xs">{unreadNotifications.length}</span>
|
||||
)}
|
||||
</a>
|
||||
|
||||
{showNotificationsModal && (
|
||||
<Modal
|
||||
size="lg"
|
||||
title="Notifications"
|
||||
confirmText={'Close'}
|
||||
handleConfirm={() => {
|
||||
setShowNotificationsModal(false);
|
||||
}}
|
||||
handleCancel={() => {
|
||||
setShowNotificationsModal(false);
|
||||
}}
|
||||
hideFooter={true}
|
||||
customHeader={modalCustomHeader}
|
||||
disableCloseOnOutsideClick={true}
|
||||
disableEscapeKey={true}
|
||||
>
|
||||
<div className="notifications-modal">
|
||||
{notifications?.length > 0 ? (
|
||||
<div className="grid grid-cols-4 flex flex-row text-sm">
|
||||
<div className="col-span-1 flex flex-col">
|
||||
<ul
|
||||
className="notifications w-full flex flex-col h-[50vh] max-h-[50vh] overflow-y-auto"
|
||||
style={{ maxHeight: '50vh', height: '46vh' }}
|
||||
>
|
||||
{notifications?.slice(notificationsStartIndex, notificationsEndIndex)?.map((notification) => (
|
||||
<li
|
||||
key={notification.id}
|
||||
className={`p-4 flex flex-col justify-center ${
|
||||
selectedNotification?.id == notification.id ? 'active' : notification.read ? 'read' : ''
|
||||
}`}
|
||||
onClick={handleNotificationItemClick(notification)}
|
||||
>
|
||||
<div className="notification-title w-full">{notification?.title}</div>
|
||||
<div className="notification-date text-xs py-2">{relativeDate(notification?.date)}</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="w-full pagination flex flex-row gap-4 justify-center p-2 items-center text-xs">
|
||||
<button
|
||||
className={`pl-2 pr-2 py-3 select-none ${
|
||||
pageNumber <= 1 ? 'opacity-50' : 'text-link cursor-pointer hover:underline'
|
||||
}`}
|
||||
onClick={handlePrev}
|
||||
>
|
||||
{'Prev'}
|
||||
</button>
|
||||
<div className="flex flex-row items-center justify-center gap-1">
|
||||
Page
|
||||
<div className="w-[20px] flex justify-center" style={{ width: '20px' }}>
|
||||
{pageNumber}
|
||||
</div>
|
||||
of
|
||||
<div className="w-[20px] flex justify-center" style={{ width: '20px' }}>
|
||||
{totalPages}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className={`pl-2 pr-2 py-3 select-none ${
|
||||
pageNumber == totalPages ? 'opacity-50' : 'text-link cursor-pointer hover:underline'
|
||||
}`}
|
||||
onClick={handleNext}
|
||||
>
|
||||
{'Next'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full col-span-3 p-4 flex-col">
|
||||
<div className="w-full text-lg flex flex-wrap h-fit mb-1">{selectedNotification?.title}</div>
|
||||
<div className="w-full notification-date text-xs mb-4">
|
||||
{humanizeDate(selectedNotification?.date)}
|
||||
</div>
|
||||
<div
|
||||
className="flex w-full flex-col flex-wrap h-fit"
|
||||
dangerouslySetInnerHTML={{ __html: selectedNotification?.description }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="opacity-50 italic text-xs p-12 flex justify-center">No Notifications</div>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
)}
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Notifications;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user