mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-03 09:28:33 +00:00
Compare commits
937 Commits
feature/su
...
v1.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95197098af | ||
|
|
06893bf3c3 | ||
|
|
861d76f7b7 | ||
|
|
33f780fb76 | ||
|
|
bacb70ea7e | ||
|
|
2aa876e526 | ||
|
|
2240acb272 | ||
|
|
752d4ae79e | ||
|
|
32c8bf296a | ||
|
|
ba994cb5a0 | ||
|
|
f4b27afb8d | ||
|
|
d23bd85cc6 | ||
|
|
a1f2e9336d | ||
|
|
d13b4d1a6b | ||
|
|
161b5eed10 | ||
|
|
41e922544c | ||
|
|
669a9fad69 | ||
|
|
3c5a8b32be | ||
|
|
d0f858681d | ||
|
|
bb852c5f80 | ||
|
|
6c73362ff2 | ||
|
|
e307c12fc8 | ||
|
|
b7e84f3623 | ||
|
|
8e78c1b4e4 | ||
|
|
64bdda6f90 | ||
|
|
a6a59ddbd7 | ||
|
|
b715e917fe | ||
|
|
78c5392675 | ||
|
|
4e02f8ad45 | ||
|
|
ffe4f7dba8 | ||
|
|
e31b601cef | ||
|
|
7d3d543f24 | ||
|
|
8d372fcdbc | ||
|
|
d00e3479cb | ||
|
|
d7eca52473 | ||
|
|
cf767165e6 | ||
|
|
3bc774bf55 | ||
|
|
0d9b5451fe | ||
|
|
0fe657d0fc | ||
|
|
ce545724bd | ||
|
|
2b08468581 | ||
|
|
0e320535a8 | ||
|
|
746c5e825e | ||
|
|
6a55a8d6ea | ||
|
|
8a48797e00 | ||
|
|
fad71e936c | ||
|
|
61f3e64751 | ||
|
|
fc6ba4641a | ||
|
|
e7d2aa3599 | ||
|
|
aa1cef9e70 | ||
|
|
3b77cfb8d6 | ||
|
|
fb8277f03e | ||
|
|
fa7afd4237 | ||
|
|
2b19ef0c2d | ||
|
|
f0d5cdecb7 | ||
|
|
be58497ba9 | ||
|
|
db1883536e | ||
|
|
c018bfc044 | ||
|
|
379697a02d | ||
|
|
c62f96c96e | ||
|
|
e1e0696e3c | ||
|
|
98ea1aa548 | ||
|
|
553d1c062e | ||
|
|
2ec343a95b | ||
|
|
2ddf79ed3f | ||
|
|
ef98eb707c | ||
|
|
fd1e8f6aa8 | ||
|
|
738c6af797 | ||
|
|
4c83dff96c | ||
|
|
531426b0a6 | ||
|
|
4d9549d2cc | ||
|
|
7980b726f6 | ||
|
|
3f80a4dfa2 | ||
|
|
e1a96e0f23 | ||
|
|
49be0b243b | ||
|
|
9f535aeba7 | ||
|
|
bd71adebe0 | ||
|
|
7367972d56 | ||
|
|
f345155a94 | ||
|
|
8f4ce9c13b | ||
|
|
7a4d59d50c | ||
|
|
a7e2f08efc | ||
|
|
30a2eb5ee7 | ||
|
|
7b40432195 | ||
|
|
699f6ba97d | ||
|
|
9486d0c829 | ||
|
|
1f0370c422 | ||
|
|
10fb06eb97 | ||
|
|
a11247d359 | ||
|
|
61f70b3e6a | ||
|
|
75bbb6d66a | ||
|
|
11ce057310 | ||
|
|
42f6353ec8 | ||
|
|
3bd7bc75a8 | ||
|
|
d2a99b0221 | ||
|
|
4abb4009e6 | ||
|
|
f8c23ed6da | ||
|
|
e96da632b2 | ||
|
|
cef8094709 | ||
|
|
353386b4da | ||
|
|
4f56506dac | ||
|
|
722fbdb474 | ||
|
|
ae689a8615 | ||
|
|
52baa69b70 | ||
|
|
b68e622695 | ||
|
|
005a936a61 | ||
|
|
bad9d0a3ef | ||
|
|
fff6870002 | ||
|
|
2ee6c5effc | ||
|
|
d3c854a9da | ||
|
|
f39d985877 | ||
|
|
500e3853a5 | ||
|
|
d76793e74d | ||
|
|
d17c2f8ebd | ||
|
|
a5ce7e9c9c | ||
|
|
f617504cd6 | ||
|
|
924bf1217f | ||
|
|
0c51e77d6c | ||
|
|
a0b2f80508 | ||
|
|
e1a74d0652 | ||
|
|
a5523967f6 | ||
|
|
c3895d65e1 | ||
|
|
8ed88d42c0 | ||
|
|
043b80171e | ||
|
|
ba761098be | ||
|
|
7b9a4f457e | ||
|
|
3e137ac6b4 | ||
|
|
a0196a01b3 | ||
|
|
aab591cb12 | ||
|
|
07a9d4645f | ||
|
|
bab12d7894 | ||
|
|
25af7a211a | ||
|
|
86553464cc | ||
|
|
35a4d46dc5 | ||
|
|
159f39dd18 | ||
|
|
50d8577298 | ||
|
|
af0d4d26bb | ||
|
|
435847081d | ||
|
|
b8f4236c1a | ||
|
|
ce91812ce5 | ||
|
|
04aa921099 | ||
|
|
08fbb91667 | ||
|
|
5be12543e5 | ||
|
|
1e6c85eb01 | ||
|
|
a3125605f3 | ||
|
|
3ed86acb46 | ||
|
|
8fb8eee5ef | ||
|
|
4a23e75dee | ||
|
|
64923e47a2 | ||
|
|
0ce3deea86 | ||
|
|
56ac0eefb8 | ||
|
|
fdb9b10353 | ||
|
|
44d90c42ed | ||
|
|
9271c67d7f | ||
|
|
1f709c6faa | ||
|
|
741718ede6 | ||
|
|
c46fbfbde3 | ||
|
|
b633fc58d2 | ||
|
|
09d6bc8169 | ||
|
|
9cf8a584a0 | ||
|
|
cd9276f4d2 | ||
|
|
87b34122c2 | ||
|
|
0e0f04c5ad | ||
|
|
dbd3ab6064 | ||
|
|
e8f88d8a13 | ||
|
|
c1f5d474b1 | ||
|
|
c04b83bcaa | ||
|
|
f8b5a48076 | ||
|
|
6fd84fcec3 | ||
|
|
6687a20835 | ||
|
|
68a508e26a | ||
|
|
05bf40fa82 | ||
|
|
49f29fa2af | ||
|
|
89e0d3ae7e | ||
|
|
bbcab8d338 | ||
|
|
2d4f337f03 | ||
|
|
fb4ad848d6 | ||
|
|
31ecc281a8 | ||
|
|
745cb85f95 | ||
|
|
aac4a33c92 | ||
|
|
32d9c4833e | ||
|
|
ff63cea108 | ||
|
|
65f688dbc2 | ||
|
|
3f6f4ccd12 | ||
|
|
fa8ec4267f | ||
|
|
3838848b03 | ||
|
|
915b227ede | ||
|
|
206098a216 | ||
|
|
99b25fc5b2 | ||
|
|
a0fe80604e | ||
|
|
7ac39bcf5c | ||
|
|
5df9981e20 | ||
|
|
03184fa1e8 | ||
|
|
e4b2b651f5 | ||
|
|
fd6b083ae5 | ||
|
|
91d9e81da4 | ||
|
|
1e435b8e10 | ||
|
|
834014b5d1 | ||
|
|
85b22b53aa | ||
|
|
769e48706d | ||
|
|
24f92d2b4e | ||
|
|
5f5ad288dc | ||
|
|
e274aedb9a | ||
|
|
7fa68731d2 | ||
|
|
c6440ab849 | ||
|
|
d52163ceb3 | ||
|
|
827df18c62 | ||
|
|
3c9e913349 | ||
|
|
7f7b3f479a | ||
|
|
3a5a213242 | ||
|
|
1f0bde4a12 | ||
|
|
2e38300a67 | ||
|
|
b731aa28be | ||
|
|
ddfd3bdf15 | ||
|
|
32b696da57 | ||
|
|
36f19ec7bc | ||
|
|
53e85f4568 | ||
|
|
4607814c09 | ||
|
|
c40f8e654c | ||
|
|
7fbd8f0a8a | ||
|
|
c5a47ba7ec | ||
|
|
13a7e4538e | ||
|
|
36443edca3 | ||
|
|
5e94ea0e83 | ||
|
|
fbeaa96419 | ||
|
|
8e5234d76a | ||
|
|
f4b9b53922 | ||
|
|
3f1b4dc628 | ||
|
|
7cd46c3a6c | ||
|
|
3300e67900 | ||
|
|
abd7edf1db | ||
|
|
7b1223d2c5 | ||
|
|
a3e6ecddbb | ||
|
|
276c9ce1b0 | ||
|
|
3687594cc4 | ||
|
|
5274d77660 | ||
|
|
ba3db06ac6 | ||
|
|
2f9762da0e | ||
|
|
766d103e20 | ||
|
|
c7fa5c5608 | ||
|
|
8f398bacb2 | ||
|
|
e0afbdbb74 | ||
|
|
d90cb91a19 | ||
|
|
1026addc8f | ||
|
|
ecf849b207 | ||
|
|
98a87dcc00 | ||
|
|
973f8e036d | ||
|
|
da9afcabe8 | ||
|
|
177f23e19f | ||
|
|
97b634f608 | ||
|
|
c572ba574f | ||
|
|
84c8676804 | ||
|
|
586e26fa2e | ||
|
|
83779dd2e1 | ||
|
|
e77a9adebd | ||
|
|
e8156c5611 | ||
|
|
471e1780a0 | ||
|
|
89c5dae881 | ||
|
|
6c52263c3c | ||
|
|
9602f42a71 | ||
|
|
3bfc966e10 | ||
|
|
d4b8caeedc | ||
|
|
fcaf3a8e85 | ||
|
|
62295e7a23 | ||
|
|
5e5b00e487 | ||
|
|
36d0db43b2 | ||
|
|
76787b4080 | ||
|
|
34ea7f0673 | ||
|
|
73062472b7 | ||
|
|
eb043fb465 | ||
|
|
a46e8851c6 | ||
|
|
4d23b4b372 | ||
|
|
45126c99ab | ||
|
|
5ba3903c31 | ||
|
|
03460c592a | ||
|
|
e658629482 | ||
|
|
07dd409acd | ||
|
|
ddc2740b31 | ||
|
|
d06d28b7fc | ||
|
|
b35596bb59 | ||
|
|
a35b04ad48 | ||
|
|
9d9e4b5065 | ||
|
|
6b07cc6e8f | ||
|
|
296e067222 | ||
|
|
49ea7f33e6 | ||
|
|
7267ba6485 | ||
|
|
59c5c24752 | ||
|
|
64b46caacd | ||
|
|
213f21bd01 | ||
|
|
861604075a | ||
|
|
d2de19f31c | ||
|
|
ffa4708ea8 | ||
|
|
6b85323d1f | ||
|
|
f22e975d90 | ||
|
|
1d58bdab59 | ||
|
|
cbfd7fa5f4 | ||
|
|
564825868e | ||
|
|
e8199f102a | ||
|
|
82c6e83d56 | ||
|
|
6bfdd58b59 | ||
|
|
9fd937bfbc | ||
|
|
bbb904437f | ||
|
|
36d6d115d4 | ||
|
|
fe59cd3223 | ||
|
|
a6ddf12ee1 | ||
|
|
7e8073cbdb | ||
|
|
846ac66ca3 | ||
|
|
c2bdddaa59 | ||
|
|
55c52971d6 | ||
|
|
3ed7dd3893 | ||
|
|
16cf654e57 | ||
|
|
89fbb42512 | ||
|
|
b00d35f007 | ||
|
|
ddddab8112 | ||
|
|
f8f38802a9 | ||
|
|
fc25ea597c | ||
|
|
72df4419ff | ||
|
|
e9a8763ca0 | ||
|
|
a1d54eacf6 | ||
|
|
f75121d426 | ||
|
|
16137a8189 | ||
|
|
922c1ff253 | ||
|
|
d3e625ef84 | ||
|
|
623ac0bac6 | ||
|
|
7dc09faa9b | ||
|
|
21c49093a5 | ||
|
|
f2c32a8812 | ||
|
|
232027ff4e | ||
|
|
f08871d491 | ||
|
|
31c4d7ecfd | ||
|
|
0dcd50f546 | ||
|
|
ece5ad3175 | ||
|
|
1f6366f262 | ||
|
|
3f7ace8bdf | ||
|
|
0ca035f492 | ||
|
|
79be625fb5 | ||
|
|
2d29eaa31a | ||
|
|
2c9b1b801a | ||
|
|
82abda85fe | ||
|
|
2ce5a6eacb | ||
|
|
7484a8a72b | ||
|
|
5f77ee342b | ||
|
|
e715a47eb6 | ||
|
|
ae36bdfe7b | ||
|
|
1aa91cd2be | ||
|
|
95419413b5 | ||
|
|
b6da0b2113 | ||
|
|
d5a72b1a5d | ||
|
|
ca8b2a58d4 | ||
|
|
9bd7723c48 | ||
|
|
d809a58deb | ||
|
|
edbe9ee4f0 | ||
|
|
924f415176 | ||
|
|
c3decadf30 | ||
|
|
b150694a5c | ||
|
|
b3ee0af226 | ||
|
|
187e482feb | ||
|
|
d034d599c5 | ||
|
|
d767a144f2 | ||
|
|
ad8e9c2561 | ||
|
|
0cf4f09608 | ||
|
|
b05d8d7da0 | ||
|
|
5f94fa1174 | ||
|
|
b31d7044a0 | ||
|
|
2acf8cae86 | ||
|
|
4ab4f09987 | ||
|
|
7e654a81bf | ||
|
|
8c101a8684 | ||
|
|
95190fa424 | ||
|
|
544edfa7d7 | ||
|
|
ba9766fbf0 | ||
|
|
0cd4a4ed94 | ||
|
|
67218f5bb4 | ||
|
|
b28f7625e4 | ||
|
|
5b00f7a8b3 | ||
|
|
fe1e260e92 | ||
|
|
ee3ef0b68c | ||
|
|
63e0df1640 | ||
|
|
4258e031c6 | ||
|
|
1b9ad34f3f | ||
|
|
19463cd0cf | ||
|
|
3fa87fe99a | ||
|
|
658a47e03e | ||
|
|
6e7fc2a9aa | ||
|
|
1244716b9b | ||
|
|
ddd479ed45 | ||
|
|
a9459bc236 | ||
|
|
cdfa839cf3 | ||
|
|
4c8ebe7765 | ||
|
|
15f3276663 | ||
|
|
1f8c4431e0 | ||
|
|
6c92ad22ef | ||
|
|
4dd17247d1 | ||
|
|
58fbe2e64b | ||
|
|
333564f687 | ||
|
|
faa7cdb1d5 | ||
|
|
3302e2e910 | ||
|
|
0e1869139b | ||
|
|
353be75d9c | ||
|
|
43c5b4cf53 | ||
|
|
6dd6879e8f | ||
|
|
955fcb795d | ||
|
|
ad3f1b2331 | ||
|
|
f2bdf2eaf6 | ||
|
|
470e9d0442 | ||
|
|
4230bf8e41 | ||
|
|
7bf049a1f0 | ||
|
|
074cbf0c03 | ||
|
|
211f941b9f | ||
|
|
363cbe75d2 | ||
|
|
ead1225bc4 | ||
|
|
61b705112e | ||
|
|
0f1fb72e21 | ||
|
|
7808a6db05 | ||
|
|
b07ccbdfab | ||
|
|
a2b6bc5970 | ||
|
|
3cc2e3d4fa | ||
|
|
a0be0e10ac | ||
|
|
78eec9ea5c | ||
|
|
97a300fbfc | ||
|
|
e898ebdfa9 | ||
|
|
d6628d960e | ||
|
|
e0266f0a69 | ||
|
|
ec89acde48 | ||
|
|
102f7a5ecb | ||
|
|
19498363e1 | ||
|
|
be857d7812 | ||
|
|
e95d9fe611 | ||
|
|
e7f130f8a1 | ||
|
|
d71e69ac3c | ||
|
|
442e68283d | ||
|
|
e218b8276d | ||
|
|
36ee1f542a | ||
|
|
97871c25cf | ||
|
|
35db296c1f | ||
|
|
e90fc466b4 | ||
|
|
b11113b529 | ||
|
|
79072785e2 | ||
|
|
ce59170752 | ||
|
|
60d3d07459 | ||
|
|
4eb74c8ed3 | ||
|
|
9e4ff465af | ||
|
|
7b55d52c11 | ||
|
|
6b668aaebe | ||
|
|
ad02ab8f36 | ||
|
|
5d1be2f18a | ||
|
|
6c3dc7bbd2 | ||
|
|
30adea3146 | ||
|
|
eed952d43f | ||
|
|
09f67abad6 | ||
|
|
d595032f46 | ||
|
|
671fcecb38 | ||
|
|
ca615e8662 | ||
|
|
d3ab2f28c6 | ||
|
|
a3cdc871d2 | ||
|
|
774ce327a9 | ||
|
|
625a19e86c | ||
|
|
1087cacdb0 | ||
|
|
faccca3921 | ||
|
|
3810152c6b | ||
|
|
816496246b | ||
|
|
fcbecfb480 | ||
|
|
dc425b067b | ||
|
|
03011a41a8 | ||
|
|
46e59eac4b | ||
|
|
cf96527ffb | ||
|
|
e4df7e3111 | ||
|
|
3ca32d4199 | ||
|
|
1298df384d | ||
|
|
fbfdfdca04 | ||
|
|
36bf2c8648 | ||
|
|
ba8bfc6d17 | ||
|
|
f781bd7d8a | ||
|
|
6e246410d5 | ||
|
|
d4e07d2028 | ||
|
|
542735e220 | ||
|
|
062adf019c | ||
|
|
7a864e0054 | ||
|
|
72521a6007 | ||
|
|
0466cd6233 | ||
|
|
8a0f7c6b8f | ||
|
|
d145275172 | ||
|
|
6cbdbad09d | ||
|
|
6d7f397d7b | ||
|
|
5ea9799c49 | ||
|
|
608d606f64 | ||
|
|
d922376d57 | ||
|
|
33cd30315a | ||
|
|
01c298c58e | ||
|
|
250227a134 | ||
|
|
21c9fda04f | ||
|
|
36caa5c2d3 | ||
|
|
9beb422674 | ||
|
|
93f89698fd | ||
|
|
cf8eb7e4ac | ||
|
|
8d4e5bc732 | ||
|
|
de223acb19 | ||
|
|
037793c113 | ||
|
|
5682c47d00 | ||
|
|
32629cdcca | ||
|
|
1979be6c4b | ||
|
|
84ed2aff72 | ||
|
|
f602306069 | ||
|
|
9e8488d417 | ||
|
|
4b297f32e0 | ||
|
|
9c3c28be42 | ||
|
|
bd5bc4acb2 | ||
|
|
e20dc985ef | ||
|
|
79379b23e2 | ||
|
|
41abdbb7fa | ||
|
|
d637334fd7 | ||
|
|
9ca22cd1d1 | ||
|
|
ff3c666f48 | ||
|
|
0a2835a543 | ||
|
|
f9f3b3ebc0 | ||
|
|
dfefb0a314 | ||
|
|
12f8ae37a6 | ||
|
|
d5c24d417d | ||
|
|
d64f4d3740 | ||
|
|
571b4459ac | ||
|
|
d4683ab961 | ||
|
|
91b1814c55 | ||
|
|
ff3321d643 | ||
|
|
659a71491d | ||
|
|
3d366477d0 | ||
|
|
beaa20c134 | ||
|
|
99fe4432c4 | ||
|
|
71e8ea457c | ||
|
|
53e49ffdd3 | ||
|
|
9ee398dc3b | ||
|
|
c4a21e1089 | ||
|
|
2b25a0be18 | ||
|
|
524c3f8445 | ||
|
|
c67cf6cca2 | ||
|
|
33da3a1303 | ||
|
|
c586deeb30 | ||
|
|
051dac02cd | ||
|
|
0668331822 | ||
|
|
1affe0056b | ||
|
|
0ad2186c43 | ||
|
|
5db50339e0 | ||
|
|
2df7f63ba9 | ||
|
|
0e1c4008e7 | ||
|
|
fdca86ffd2 | ||
|
|
b9291201d9 | ||
|
|
239caa1763 | ||
|
|
362289b7cd | ||
|
|
f9f1ca0640 | ||
|
|
53eb53e062 | ||
|
|
2d149d94ef | ||
|
|
f0c3b8a877 | ||
|
|
3a222458d1 | ||
|
|
46bc097733 | ||
|
|
1ce8d707f1 | ||
|
|
b854e66a24 | ||
|
|
1a366893ec | ||
|
|
bf90ee96e5 | ||
|
|
ce2e997c06 | ||
|
|
7617ae12cb | ||
|
|
905e993a13 | ||
|
|
be6abf421f | ||
|
|
b47b0565e5 | ||
|
|
094bf7bc60 | ||
|
|
159dd90b03 | ||
|
|
c222bf47c3 | ||
|
|
c91bc0d1c6 | ||
|
|
64ac763a13 | ||
|
|
bca3d5749b | ||
|
|
2ee6759282 | ||
|
|
c479c2e786 | ||
|
|
6d8bdfa276 | ||
|
|
024f61a95e | ||
|
|
856236c918 | ||
|
|
0179c58cd2 | ||
|
|
515381b930 | ||
|
|
5ef0de2e4d | ||
|
|
c6fef2f1be | ||
|
|
21536f9a27 | ||
|
|
faf8581ddf | ||
|
|
47992288c4 | ||
|
|
640692abc7 | ||
|
|
ed95b8349e | ||
|
|
81b1982d4f | ||
|
|
e381d0c00b | ||
|
|
50f2f54335 | ||
|
|
fab350a32d | ||
|
|
4600217606 | ||
|
|
6421148dc1 | ||
|
|
12f3f802a7 | ||
|
|
ae78ed36ef | ||
|
|
1e27427d09 | ||
|
|
f2a8bd5d10 | ||
|
|
860a3b16ad | ||
|
|
8fadaf98ae | ||
|
|
8f1f41374c | ||
|
|
e3679c9ee9 | ||
|
|
7f17999486 | ||
|
|
d2b35beb6f | ||
|
|
0f3a8a87bb | ||
|
|
3c0770b792 | ||
|
|
5a89d12716 | ||
|
|
8730c5a85b | ||
|
|
24fcb8caf2 | ||
|
|
5a0e68073f | ||
|
|
945f1eb74a | ||
|
|
de74edb50f | ||
|
|
80414d751d | ||
|
|
295d82dca9 | ||
|
|
9474918853 | ||
|
|
6db36513c5 | ||
|
|
7be38bcfe0 | ||
|
|
289625c851 | ||
|
|
1f5aa25d5e | ||
|
|
e2e3895a58 | ||
|
|
65e448b1eb | ||
|
|
d5a6522563 | ||
|
|
be72d24ecb | ||
|
|
c25542bbdf | ||
|
|
a838185ddf | ||
|
|
ac3637fcfa | ||
|
|
e3f32dfc87 | ||
|
|
a204e3814b | ||
|
|
be8db1876a | ||
|
|
64d9413777 | ||
|
|
a71afc8f73 | ||
|
|
4e4130acf5 | ||
|
|
bb7d13d2d9 | ||
|
|
c08be14d87 | ||
|
|
90f47e5877 | ||
|
|
8a19189dcd | ||
|
|
efbc119e7c | ||
|
|
d36956e0a4 | ||
|
|
efbdde8252 | ||
|
|
ae2f170fe6 | ||
|
|
4f0d87fba4 | ||
|
|
8703124007 | ||
|
|
f9f99adbf9 | ||
|
|
da9a6c434a | ||
|
|
c8764f6555 | ||
|
|
e90718f47b | ||
|
|
af130bac17 | ||
|
|
04481a26e1 | ||
|
|
86c2a60184 | ||
|
|
0cbf803ed9 | ||
|
|
c91819c072 | ||
|
|
2c4a3a5eb4 | ||
|
|
99fc980a48 | ||
|
|
960f62ac8e | ||
|
|
57e0f0c0c4 | ||
|
|
8216bf5eec | ||
|
|
9f11cfc836 | ||
|
|
51cb930b6a | ||
|
|
1c8712b6eb | ||
|
|
6c1f8c78b2 | ||
|
|
b35b814561 | ||
|
|
80eaaad658 | ||
|
|
51a73d864e | ||
|
|
87e29db545 | ||
|
|
0cf18e6804 | ||
|
|
3a6dacc1f4 | ||
|
|
8d89496304 | ||
|
|
6ef7891f8a | ||
|
|
e1bf475f1f | ||
|
|
f7eb325e11 | ||
|
|
c50b88d60d | ||
|
|
90fedc8ec6 | ||
|
|
9c46bc79d9 | ||
|
|
9ecfb3a640 | ||
|
|
da4e96d1ef | ||
|
|
bf2d1220a1 | ||
|
|
744abe585c | ||
|
|
5e2640fe73 | ||
|
|
7513314179 | ||
|
|
d4b663bfa8 | ||
|
|
9b2e2ed3d8 | ||
|
|
e4ea6b9109 | ||
|
|
1a8feb8029 | ||
|
|
72a5f05009 | ||
|
|
d5ef240de6 | ||
|
|
1932d98b57 | ||
|
|
bdb7ff9947 | ||
|
|
3f4f7fb24c | ||
|
|
494b484cd9 | ||
|
|
48e4e60696 | ||
|
|
2e600838b2 | ||
|
|
52428c6b35 | ||
|
|
2734f26c78 | ||
|
|
73c62010b7 | ||
|
|
26853787da | ||
|
|
712319ff34 | ||
|
|
7a80247fc5 | ||
|
|
ea9e294c54 | ||
|
|
55315b5b88 | ||
|
|
d63e7371fe | ||
|
|
dce11d1bd5 | ||
|
|
e720fed63b | ||
|
|
43f7c2ab86 | ||
|
|
95532102ba | ||
|
|
4603ec4d5e | ||
|
|
cbdd56e577 | ||
|
|
ce77d08408 | ||
|
|
3a5071412e | ||
|
|
336ad38cb9 | ||
|
|
636e14a385 | ||
|
|
bfc03f5ae4 | ||
|
|
97200961eb | ||
|
|
7297bb184e | ||
|
|
b74922c8f3 | ||
|
|
ce0827308f | ||
|
|
3d0c9cc0ae | ||
|
|
1804454ff0 | ||
|
|
3c710120b9 | ||
|
|
fcc12fb089 | ||
|
|
3d8dee944f | ||
|
|
78e5cd3c03 | ||
|
|
26d99c7aee | ||
|
|
77a7318dfb | ||
|
|
b83da46f12 | ||
|
|
cf6ec4e84f | ||
|
|
978d810473 | ||
|
|
cedcd2cf35 | ||
|
|
ce9cdc5293 | ||
|
|
e83c2da798 | ||
|
|
39f148267e | ||
|
|
f4f093d4db | ||
|
|
3c4ef2f2df | ||
|
|
e39975cb3c | ||
|
|
b767ccd063 | ||
|
|
c5adfd8975 | ||
|
|
6695d90609 | ||
|
|
5c79282a1b | ||
|
|
64019f8ecf | ||
|
|
4c89f31934 | ||
|
|
1c53ce91f0 | ||
|
|
0b83fbb7ce | ||
|
|
08ceed86a8 | ||
|
|
f99918d725 | ||
|
|
1877dd858e | ||
|
|
acff0c379e | ||
|
|
a849e4fb7b | ||
|
|
613699fb69 | ||
|
|
0c4ba71922 | ||
|
|
d346bb00eb | ||
|
|
8bb57aa41d | ||
|
|
f378f04fc3 | ||
|
|
742d69b03c | ||
|
|
0e3bc62d9d | ||
|
|
a02d2b9c58 | ||
|
|
21edfbc25a | ||
|
|
4ba4d8fc27 | ||
|
|
45042cd52a | ||
|
|
314e8c17d3 | ||
|
|
69a7c0e4ce | ||
|
|
626d925ad6 | ||
|
|
2c0ccf769c | ||
|
|
5f32924ddb | ||
|
|
9bcf56d689 | ||
|
|
516411b9a2 | ||
|
|
0f1e330dc5 | ||
|
|
60e3f3bb6a | ||
|
|
51ee37cf96 | ||
|
|
a6b19605b5 | ||
|
|
7ba471f26a | ||
|
|
f23dcf50a4 | ||
|
|
86cda2cf5a | ||
|
|
00b6e007af | ||
|
|
7313d1b4d7 | ||
|
|
8f803234ce | ||
|
|
76a743b74e | ||
|
|
c623aa0909 | ||
|
|
3eb26834c7 | ||
|
|
64a5852227 | ||
|
|
6471ca74c3 | ||
|
|
f77d955839 | ||
|
|
9947a55b8d | ||
|
|
a71555725c | ||
|
|
c9ec6902a5 | ||
|
|
c9c675e187 | ||
|
|
0517b2685e | ||
|
|
5d01c0a765 | ||
|
|
f3925923c9 | ||
|
|
6facdfd66b | ||
|
|
0f211131b1 | ||
|
|
cd3b8a948e | ||
|
|
f695036721 | ||
|
|
3661fa7df3 | ||
|
|
559fcb0806 | ||
|
|
d5da8a9e2f | ||
|
|
a3050db6c4 | ||
|
|
c27f090583 | ||
|
|
487dd73040 | ||
|
|
665428a2d0 | ||
|
|
6a2ba0f746 | ||
|
|
36f9902f2e | ||
|
|
c0b7dad030 | ||
|
|
8780d309ac | ||
|
|
08c1563a7a | ||
|
|
07ad1f9f60 | ||
|
|
8df6b241bb | ||
|
|
50e0558d7d | ||
|
|
cbe84cc512 | ||
|
|
cbb975d81d | ||
|
|
30ee472c40 | ||
|
|
c7aecbea79 | ||
|
|
b814c84411 | ||
|
|
6306ad17c3 | ||
|
|
4b800e30e4 | ||
|
|
89f418a114 | ||
|
|
9c8ef09d01 | ||
|
|
83d354c25c | ||
|
|
bb31ddc5d2 | ||
|
|
ff40178c8c | ||
|
|
1c549f7faf | ||
|
|
eb6b75ff98 | ||
|
|
eb010adeac | ||
|
|
7e5e22cfcf | ||
|
|
2515e78a10 | ||
|
|
511854369f | ||
|
|
18f185d37c | ||
|
|
7a0322d09e | ||
|
|
2dadad3af0 | ||
|
|
eaa31342dc | ||
|
|
c4fd9d38a5 | ||
|
|
9c4c219b99 | ||
|
|
8e22aa2fca | ||
|
|
6b9e085696 | ||
|
|
74282706aa | ||
|
|
aa88aa73a2 | ||
|
|
f78c1640e9 | ||
|
|
a5a17cf8eb | ||
|
|
c5a86cb343 | ||
|
|
9b94cddc9b | ||
|
|
0a172ddce8 | ||
|
|
aea1cbba9e | ||
|
|
7a1b44858d | ||
|
|
1c89ab3450 | ||
|
|
e3ce420216 | ||
|
|
c91fef2264 | ||
|
|
c83fce16dc | ||
|
|
5415e20d7e | ||
|
|
2f45b95930 | ||
|
|
4531cfc994 | ||
|
|
bd0738198c | ||
|
|
9a81793151 | ||
|
|
88c16fa388 | ||
|
|
f68eacfe0d | ||
|
|
116e050987 | ||
|
|
5af2f68252 | ||
|
|
a53dd76854 | ||
|
|
67fe264494 | ||
|
|
ae692dde06 | ||
|
|
1c4c5cc0c0 | ||
|
|
19ca1af71e | ||
|
|
4016a83626 | ||
|
|
71b18c8b21 | ||
|
|
b53fcbb3d1 | ||
|
|
19a7f397bb | ||
|
|
a103f41d85 | ||
|
|
7d4d1573af | ||
|
|
6f2bb55ecf | ||
|
|
f189cb1a2e | ||
|
|
c020cd94a8 | ||
|
|
0d4f7e6a06 | ||
|
|
f9ed68843d | ||
|
|
d3a56fdc82 | ||
|
|
e6c3a5af4c | ||
|
|
cee8073bb7 | ||
|
|
69be52cf9e | ||
|
|
9e400085e3 | ||
|
|
b07bb67943 | ||
|
|
593210456a | ||
|
|
e328a4615e | ||
|
|
18afb73238 | ||
|
|
73b71e0829 | ||
|
|
4c25aa99aa | ||
|
|
23843b5d0a | ||
|
|
7fbd338fa6 | ||
|
|
4aeb5cf56d | ||
|
|
1ed39a5ea6 | ||
|
|
74f248782b | ||
|
|
99239e19b4 | ||
|
|
f46160e161 | ||
|
|
d0147778db | ||
|
|
87119cee2e | ||
|
|
b25d896dd6 | ||
|
|
08495e7fb5 | ||
|
|
ee084696f5 | ||
|
|
aeb9fc8875 | ||
|
|
26a05f92cb | ||
|
|
fff7819c46 | ||
|
|
1d678ee0d9 | ||
|
|
fd4c188c95 | ||
|
|
97678b05fc | ||
|
|
a1c9625aee | ||
|
|
a9d74467ff | ||
|
|
bd670eceb6 | ||
|
|
1ccb66e92a | ||
|
|
d62881fe0d | ||
|
|
9ea95b4571 | ||
|
|
df9322b767 | ||
|
|
c27c750c3e | ||
|
|
94baee8e25 | ||
|
|
417b50b0ad | ||
|
|
bf5ee7e409 | ||
|
|
3ca0107f1b | ||
|
|
aeb29393c5 | ||
|
|
ec22fdb637 | ||
|
|
0866d33858 | ||
|
|
66024d04e9 | ||
|
|
330a7ad18a | ||
|
|
2976842588 | ||
|
|
51e0ea2c2d | ||
|
|
3b85e7ebcc | ||
|
|
49b0f3a322 | ||
|
|
ad905d1a0a | ||
|
|
45ca5ded96 | ||
|
|
b6528062f0 | ||
|
|
86094cc054 | ||
|
|
8e0bc68ada | ||
|
|
c36c7b44a6 | ||
|
|
0ac27dee56 | ||
|
|
ede122ab09 | ||
|
|
96e368cb18 | ||
|
|
942b75861c | ||
|
|
c1711ea01b | ||
|
|
dedfefbc9a | ||
|
|
65dd5df87e | ||
|
|
78d2393686 | ||
|
|
0b65c4580e | ||
|
|
9cc1bf1e2f | ||
|
|
b96e3d0f23 | ||
|
|
11c99d55dc | ||
|
|
d054dc4c78 | ||
|
|
9014dc5769 | ||
|
|
d346970241 | ||
|
|
bdb3051c2b | ||
|
|
f8325b22b3 |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
github: helloanoop
|
||||
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Description
|
||||
|
||||
<!-- Explain here the changes your PR introduces and text to help us understand the context of this change. -->
|
||||
|
||||
### Contribution Checklist:
|
||||
|
||||
- [ ] **The pull request only addresses one issue or adds one feature.**
|
||||
- [ ] **The pull request does not introduce any breaking changes**
|
||||
- [ ] **I have added screenshots or gifs to help explain the change if applicable.**
|
||||
- [ ] **I have read the [contribution guidelines](https://github.com/usebruno/bruno/blob/main/contributing.md).**
|
||||
- [ ] **Create an issue and link to the pull request.**
|
||||
|
||||
Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.
|
||||
|
||||
### Publishing to New Package Managers
|
||||
|
||||
Please see [here](../publishing.md) for more information.
|
||||
12
.github/workflows/bump-homebrew-cask.yml
vendored
Normal file
12
.github/workflows/bump-homebrew-cask.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
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}"
|
||||
50
.github/workflows/release-snap.yml
vendored
Normal file
50
.github/workflows/release-snap.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
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 }}
|
||||
58
.github/workflows/unit-tests.yml
vendored
58
.github/workflows/unit-tests.yml
vendored
@@ -1,29 +1,45 @@
|
||||
name: Unit Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
jobs:
|
||||
test:
|
||||
tests:
|
||||
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: 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
|
||||
- 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
|
||||
|
||||
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
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -4,7 +4,6 @@
|
||||
node_modules
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
.pnp
|
||||
.pnp.js
|
||||
|
||||
@@ -41,3 +40,7 @@ yarn-error.log*
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
||||
|
||||
#dev editor
|
||||
bruno.iml
|
||||
.idea
|
||||
4
.husky/pre-commit
Executable file
4
.husky/pre-commit
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npx pretty-quick --staged
|
||||
7
.prettierrc.json
Normal file
7
.prettierrc.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"printWidth": 120
|
||||
}
|
||||
BIN
assets/images/cli-demo.png
Normal file
BIN
assets/images/cli-demo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
BIN
assets/images/run-anywhere.png
Normal file
BIN
assets/images/run-anywhere.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 153 KiB |
BIN
assets/images/version-control.png
Normal file
BIN
assets/images/version-control.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
@@ -1,10 +1,12 @@
|
||||
## Lets make bruno better, together !!
|
||||
**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)
|
||||
|
||||
I am happy that you are looking to improve bruno. Below are the guidelines to get started bringing up bruno on your computer.
|
||||
## 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.
|
||||
|
||||
### Technology Stack
|
||||
|
||||
Bruno is built using NextJs and React. We also use electron to ship a desktop version (that supports local collections)
|
||||
Bruno is built using Next.js and React. We also use electron to ship a desktop version (that supports local collections)
|
||||
|
||||
Libraries we use
|
||||
|
||||
@@ -19,11 +21,61 @@ Libraries we use
|
||||
|
||||
### Dependencies
|
||||
|
||||
You would need [Node v14.x or the latest LTS version](https://nodejs.org/en/) and npm 8.x. We use npm workspaces in the project
|
||||
You would need [Node v18.x or the latest LTS version](https://nodejs.org/en/) and npm 8.x. We use npm workspaces in the project
|
||||
|
||||
### Lets start coding
|
||||
## Development
|
||||
|
||||
Please reference [development.md](docs/development.md) for instructions on running the local development environment.
|
||||
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
|
||||
# use nodejs 18 version
|
||||
nvm use
|
||||
|
||||
# install deps
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# build graphql docs
|
||||
npm run build:graphql-docs
|
||||
|
||||
# build bruno query
|
||||
npm run build:bruno-query
|
||||
|
||||
# run next app (terminal 1)
|
||||
npm run dev:web
|
||||
|
||||
# run electron app (terminal 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
You might encounter a `Unsupported platform` error when you run `npm install`. To fix this, you will need to delete `node_modules` and `package-lock.json` and run `npm install`. This should install all the necessary packages needed to run the app.
|
||||
|
||||
```shell
|
||||
# Delete node_modules in sub-directories
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# Delete package-lock in sub-directories
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Raising Pull Request
|
||||
|
||||
@@ -31,5 +83,5 @@ Please reference [development.md](docs/development.md) for instructions on runni
|
||||
- Please follow the format of creating branches
|
||||
- feature/[feature name]: This branch should contain changes for a specific feature
|
||||
- Example: feature/dark-mode
|
||||
- bugfix/[bug name]: This branch should container only bug fixes for a specific bug
|
||||
- bugfix/[bug name]: This branch should contain only bug fixes for a specific bug
|
||||
- Example bugfix/bug-1
|
||||
|
||||
87
docs/contributing/contributing_bn.md
Normal file
87
docs/contributing/contributing_bn.md
Normal file
@@ -0,0 +1,87 @@
|
||||
[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) | **বাংলা**
|
||||
|
||||
## আসুন ব্রুনোকে আরও ভালো করি, একসাথে!!
|
||||
|
||||
আমরা খুশি যে আপনি ব্রুনোর উন্নতি করতে চাইছেন। নীচে আপনার কম্পিউটারে ব্রুনো ইনষ্টল করার নির্দেশিকা রয়েছে৷।
|
||||
|
||||
### Technology Stack (প্রযুক্তি স্ট্যাক)
|
||||
|
||||
ব্রুনো Next.js এবং React ব্যবহার করে নির্মিত। এছাড়াও আমরা একটি ডেস্কটপ সংস্করণ পাঠাতে ইলেক্ট্রন ব্যবহার করি (যা স্থানীয় সংগ্রহ সমর্থন করে)
|
||||
|
||||
নিম্ন লিখিত লাইব্রেরি আমরা ব্যবহার করি -
|
||||
|
||||
- CSS - Tailwind
|
||||
- Code Editors - Codemirror
|
||||
- State Management - Redux
|
||||
- Icons - Tabler Icons
|
||||
- Forms - formik
|
||||
- Schema Validation - Yup
|
||||
- Request Client - axios
|
||||
- Filesystem Watcher - chokidar
|
||||
|
||||
### Dependencies (নির্ভরতা)
|
||||
|
||||
আপনার প্রয়োজন হবে [নোড v18.x বা সর্বশেষ LTS সংস্করণ](https://nodejs.org/en/) এবং npm 8.x। আমরা প্রকল্পে npm ওয়ার্কস্পেস ব্যবহার করি ।
|
||||
|
||||
## Development
|
||||
|
||||
ব্রুনো একটি ডেস্কটপ অ্যাপ হিসেবে তৈরি করা হচ্ছে। আপনাকে একটি টার্মিনালে Next.js অ্যাপটি চালিয়ে অ্যাপটি লোড করতে হবে এবং তারপরে অন্য টার্মিনালে ইলেক্ট্রন অ্যাপটি চালাতে হবে।
|
||||
|
||||
### Dependencies (নির্ভরতা)
|
||||
|
||||
- NodeJS v18
|
||||
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
# nodejs 18 সংস্করণ ব্যবহার করুন
|
||||
nvm use
|
||||
|
||||
# নির্ভরতা ইনস্টল করুন
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# গ্রাফকিউএল ডক্স তৈরি করুন
|
||||
npm run build:graphql-docs
|
||||
|
||||
# ব্রুনো কোয়েরি তৈরি করুন
|
||||
npm run build:bruno-query
|
||||
|
||||
# NextJs অ্যাপ চালান (টার্মিনাল 1)
|
||||
npm run dev:web
|
||||
|
||||
# ইলেক্ট্রন অ্যাপ চালান (টার্মিনাল 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### Troubleshooting (সমস্যা সমাধান)
|
||||
|
||||
আপনি যখন 'npm install' চালান তখন আপনি একটি 'অসমর্থিত প্ল্যাটফর্ম' ত্রুটির সম্মুখীন হতে পারেন৷ এটি ঠিক করতে, আপনাকে `node_modules` এবং `package-lock.json` মুছে ফেলতে হবে এবং `npm install` চালাতে হবে। এটি অ্যাপটি চালানোর জন্য প্রয়োজনীয় সমস্ত প্যাকেজ ইনস্টল করবে যাতে এই ত্রুটি ঠিক হয়ে যেতে পারে ।
|
||||
|
||||
```shell
|
||||
# সাব-ডিরেক্টরিতে নোড_মডিউল মুছুন
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# সাব-ডিরেক্টরিতে প্যাকেজ-লক মুছুন
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### Testing (পরীক্ষা)
|
||||
|
||||
```bash
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Raising Pull Request (পুল অনুরোধ উত্থাপন)
|
||||
|
||||
- অনুগ্রহ করে PR এর আকার ছোট রাখুন এবং একটি বিষয়ে ফোকাস করুন।
|
||||
- অনুগ্রহ করে শাখা তৈরির বিন্যাস অনুসরণ করুন।
|
||||
- বৈশিষ্ট্য/[ফিচারের নাম]: এই শাখায় একটি নির্দিষ্ট বৈশিষ্ট্যের জন্য পরিবর্তন থাকতে হবে।
|
||||
- উদাহরণ: বৈশিষ্ট্য/ডার্ক-মোড।
|
||||
- বাগফিক্স/[বাগ নাম]: এই শাখায় একটি নির্দিষ্ট বাগ-এর জন্য শুধুমাত্র বাগ ফিক্স থাকা উচিত।
|
||||
- উদাহরণ বাগফিক্স/বাগ-1।
|
||||
91
docs/contributing/contributing_de.md
Normal file
91
docs/contributing/contributing_de.md
Normal file
@@ -0,0 +1,91 @@
|
||||
[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)
|
||||
|
||||
## Lass uns Bruno noch besser machen, gemeinsam !!
|
||||
|
||||
Ich freue mich, dass Du Bruno verbessern möchtest. Hier findest Du eine Anleitung, mit der Du Bruno auf Deinem Computer einrichten kannst.
|
||||
|
||||
### Technologie Stack
|
||||
|
||||
Bruno ist mit Next.js und React erstellt. Außerdem benötigen wir electron für die Desktop Version (die lokale Sammlungen unterstützt).
|
||||
|
||||
Bibliotheken die wir benutzen
|
||||
|
||||
- CSS - Tailwind
|
||||
- Code Editoren - Codemirror
|
||||
- State Management - Redux
|
||||
- Icons - Tabler Icons
|
||||
- Formulare - formik
|
||||
- Schema Validierung - Yup
|
||||
- Request Client - axios
|
||||
- Dateisystem Watcher - chokidar
|
||||
|
||||
### Abhängigkeiten
|
||||
|
||||
Du benötigst [Node v18.x oder die neuste LTS Version](https://nodejs.org/en/) und npm 8.x. Wir benutzen npm workspaces in dem Projekt.
|
||||
|
||||
### Lass uns coden
|
||||
|
||||
Eine Anleitung zum Ausführen einer lokalen Entwicklungsumgebung findest Du in [development.md](docs/development_de.md).
|
||||
|
||||
### Pull Request erstellen
|
||||
|
||||
- Bitte halte die PRs klein und begrenzt auf eine Sache
|
||||
- Bitte halte Dich beim Erstellen eines Branches an das folgende Format
|
||||
- feature/[feature name]: Dieser Branch soll Änderungen für ein bestimmtes Feature enthalten
|
||||
- Beispiel: feature/dark-mode
|
||||
- bugfix/[bug name]: Dieser Branch soll ausschließlich Bugfixes für einen bestimmten Bug enthalten
|
||||
- Beispiel: bugfix/bug-1
|
||||
|
||||
## Entwicklung
|
||||
|
||||
Bruno wird als Desktop-Anwendung entwickelt. Um die App zu starten, musst Du zuerst die Next.js App in einem Terminal ausführen und anschließend in einem anderen Terminal die Electron-App.
|
||||
|
||||
### Abhängigkeiten
|
||||
|
||||
- NodeJS v18
|
||||
|
||||
### Lokales Entwickeln
|
||||
|
||||
```bash
|
||||
# use nodejs 18 version
|
||||
nvm use
|
||||
|
||||
# install deps
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# build graphql docs
|
||||
npm run build:graphql-docs
|
||||
|
||||
# build bruno query
|
||||
npm run build:bruno-query
|
||||
|
||||
# run next app (terminal 1)
|
||||
npm run dev:web
|
||||
|
||||
# run electron app (terminal 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
Es kann sein, dass Du einen `Unsupported platform`-Fehler bekommst, wenn Du `npm install` ausführst. Um dies zu beheben, musst Du `node_modules` und `package-lock.json` löschen und `npm install` erneut ausführen. Dies sollte alle notwendigen Pakete installieren, die zum Ausführen der Anwendung benötigt werden.
|
||||
|
||||
```shell
|
||||
# Delete node_modules in sub-directories
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# Delete package-lock in sub-directories
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### Testen
|
||||
|
||||
```bash
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
85
docs/contributing/contributing_es.md
Normal file
85
docs/contributing/contributing_es.md
Normal file
@@ -0,0 +1,85 @@
|
||||
## ¡Juntos, hagamos a Bruno mejor!
|
||||
|
||||
Estamos encantados de que quieras ayudar a mejorar Bruno. A continuación encontrarás las instrucciones para empezar a trabajar con Bruno en tu computadora.
|
||||
|
||||
### Tecnologías utilizadas
|
||||
|
||||
Bruno está construido con NextJs y React. También usamos electron para distribuir una versión de escritorio (que soporta colecciones locales).
|
||||
|
||||
Librerías que utilizamos:
|
||||
|
||||
- CSS - Tailwind
|
||||
- Editores de código - Codemirror
|
||||
- Manejo del estado - Redux
|
||||
- Íconos - Tabler Icons
|
||||
- Formularios - formik
|
||||
- Validación de esquemas - Yup
|
||||
- Cliente de peticiones - axios
|
||||
- Monitor del sistema de archivos - chokidar
|
||||
|
||||
### Dependencias
|
||||
|
||||
Necesitarás [Node v18.x o la última versión LTS](https://nodejs.org/es) y npm 8.x. Ten en cuenta que utilizamos espacios de trabajo de npm en el proyecto.
|
||||
|
||||
## Desarrollo
|
||||
|
||||
Bruno está siendo desarrollado como una aplicación de escritorio. Para ejecutarlo, primero debes ejecutar la aplicación de nextjs en una terminal y luego ejecutar la aplicación de electron en otra terminal.
|
||||
|
||||
### Dependencias
|
||||
|
||||
- NodeJS v18
|
||||
|
||||
### Desarrollo local
|
||||
|
||||
```bash
|
||||
# Utiliza la versión 18 de nodejs
|
||||
nvm use
|
||||
|
||||
# Instala las dependencias
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# Construye la documentación de graphql
|
||||
npm run build:graphql-docs
|
||||
|
||||
# Construye bruno-query
|
||||
npm run build:bruno-query
|
||||
|
||||
# Ejecuta la aplicación de nextjs (terminal 1)
|
||||
npm run dev:web
|
||||
|
||||
# Ejecuta la aplicación de electron (terminal 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### Solución de problemas
|
||||
|
||||
Es posible que encuentres un error de `Unsupported platform` cuando ejecutes `npm install`. Para solucionarlo, debes eliminar la carpeta `node_modules` y el archivo `package-lock.json`, luego, ejecuta `npm install`. Lo anterior debería instalar todos los paquetes necesarios para ejecutar la aplicación.
|
||||
|
||||
```shell
|
||||
# Elimina la carpeta node_modules en los subdirectorios
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# Elimina el archivo package-lock en los subdirectorios
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### Pruebas
|
||||
|
||||
```bash
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Crea un Pull Request
|
||||
|
||||
- Por favor, mantén los Pull Request pequeños y enfocados en una sola cosa.
|
||||
- Por favor, sigue el siguiente formato para la creación de ramas:
|
||||
- feature/[nombre de la funcionalidad]: Esta rama debe contener los cambios para una funcionalidad específica.
|
||||
- Ejemplo: feature/dark-mode
|
||||
- bugfix/[nombre del error]: Esta rama debe contener solo correcciones de errores para un error específico.
|
||||
- Ejemplo: bugfix/bug-1
|
||||
91
docs/contributing/contributing_fr.md
Normal file
91
docs/contributing/contributing_fr.md
Normal file
@@ -0,0 +1,91 @@
|
||||
[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)
|
||||
|
||||
## Ensemble, améliorons Bruno !
|
||||
|
||||
Je suis content de voir que vous envisagez d'améliorer Bruno. Vous trouverez ci-dessous les règles et guides pour récupérer Bruno sur votre ordinateur.
|
||||
|
||||
### Technologies utilisées
|
||||
|
||||
Bruno est basé sur NextJs et React. Nous utilisons aussi Electron pour embarquer la version ordinateur (ce qui permet les collections locales).
|
||||
|
||||
Les librairies que nous utilisons :
|
||||
|
||||
- CSS - Tailwind
|
||||
- Code Editors - Codemirror
|
||||
- State Management - Redux
|
||||
- Icons - Tabler Icons
|
||||
- Forms - formik
|
||||
- Schema Validation - Yup
|
||||
- Request Client - axios
|
||||
- Filesystem Watcher - chokidar
|
||||
|
||||
### Dépendances
|
||||
|
||||
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.
|
||||
|
||||
### Dépendances
|
||||
|
||||
- NodeJS v18
|
||||
|
||||
### Développement local
|
||||
|
||||
```bash
|
||||
# utiliser node en version 18
|
||||
nvm use
|
||||
|
||||
# installation des dépendances
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# construction des docs graphql
|
||||
npm run build:graphql-docs
|
||||
|
||||
# construction de bruno query
|
||||
npm run build:bruno-query
|
||||
|
||||
# démarrage de next (terminal 1)
|
||||
npm run dev:web
|
||||
|
||||
# démarrage du client lourd (terminal 2)
|
||||
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.
|
||||
|
||||
```shell
|
||||
# Efface les répertoires node_modules dans les sous-répertoires
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# Efface les fichiers package-lock.json dans les sous-répertoires
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
```bash
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
89
docs/contributing/contributing_it.md
Normal file
89
docs/contributing/contributing_it.md
Normal file
@@ -0,0 +1,89 @@
|
||||
## Insieme, miglioriamo Bruno!
|
||||
|
||||
Sono felice di vedere che hai intenzione di migliorare Bruno. Di seguito, troverai le regole e le guide per ripristinare Bruno sul tuo computer.
|
||||
|
||||
### Tecnologie utilizzate
|
||||
|
||||
Bruno è costruito utilizzando Next.js e React. Utilizziamo anche Electron per incorporare la versione desktop (che consente raccolte locali).
|
||||
|
||||
Le librerie che utilizziamo sono:
|
||||
|
||||
- CSS - Tailwind
|
||||
- Code Editors - Codemirror
|
||||
- State Management - Redux
|
||||
- Icons - Tabler Icons
|
||||
- Forms - formik
|
||||
- Schema Validation - Yup
|
||||
- Request Client - axios
|
||||
- Filesystem Watcher - chokidar
|
||||
|
||||
### Dependences
|
||||
|
||||
Hai bisogno di [Node v18.x o dell'ultima versione LTS](https://nodejs.org/en/) di npm 8.x. Utilizziamo gli spazi di lavoro npm (_npm workspaces_) in questo progetto.
|
||||
|
||||
### Iniziamo a codificare
|
||||
|
||||
Si prega di fare riferimento alla [documentazione di sviluppo](docs/development_it.md) per le istruzioni su come avviare l'ambiente di sviluppo locale.
|
||||
|
||||
### Aprire una richiesta di pull (Pull Request)
|
||||
|
||||
- Si prega di mantenere le Pull Request (PR) brevi e concentrate su un singolo obiettivo.
|
||||
- Si prega di seguire il formato di denominazione dei rami.
|
||||
- feature/[feature name]: Questo ramo dovrebbe contenere una specifica funzionalità.
|
||||
- Esempio: feature/dark-mode
|
||||
- bugfix/[bug name]: Questo ramo dovrebbe contenere solo una soluzione per un bug specifico.
|
||||
- Esempio: bugfix/bug-1
|
||||
|
||||
## Sviluppo
|
||||
|
||||
Bruno è sviluppato come un'applicazione "heavy". È necessario caricare l'applicazione avviando Next.js in una finestra del terminale e quindi avviare l'applicazione Electron in un altro terminale.
|
||||
|
||||
### Sviluppo
|
||||
|
||||
- NodeJS v18
|
||||
|
||||
### Sviluppo locale
|
||||
|
||||
```bash
|
||||
# use nodejs 18 version
|
||||
nvm use
|
||||
|
||||
# install deps
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# build graphql docs
|
||||
npm run build:graphql-docs
|
||||
|
||||
# build bruno query
|
||||
npm run build:bruno-query
|
||||
|
||||
# run next app (terminal 1)
|
||||
npm run dev:web
|
||||
|
||||
# run electron app (terminal 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### Risoluzione dei problemi
|
||||
|
||||
Potresti trovare un errore `Unsupported platform` durante l'esecuzione di `npm install`. Per risolvere questo problema, ti preghiamo di eliminare la cartella `node_modules`, il file `package-lock.json` e di seguito nuovamente `npm install`. Qeusto dovrebbe installare tutti i pacchetti necessari per avviare l'applicazione.
|
||||
|
||||
```shell
|
||||
# delete node_modules in sub-directories
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# delete package-lock in sub-directories
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
```bash
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
85
docs/contributing/contributing_pt_br.md
Normal file
85
docs/contributing/contributing_pt_br.md
Normal file
@@ -0,0 +1,85 @@
|
||||
## Vamos tornar o Bruno melhor, juntos!!
|
||||
|
||||
Estamos felizes que você queira ajudar a melhorar o Bruno. Abaixo estão as diretrizes e orientações para começar a executar o Bruno no seu computador.
|
||||
|
||||
### Stack de Tecnologias
|
||||
|
||||
O Bruno é construído usando Next.js e React. Também usamos o Electron para disponibilizar uma versão para desktop (que suporta coleções locais).
|
||||
|
||||
Bibliotecas que utilizamos:
|
||||
|
||||
- CSS - Tailwind
|
||||
- Editor de Código - Codemirror
|
||||
- Gerenciador de Estado - Redux
|
||||
- Ícones - Tabler Icons
|
||||
- Formulários - formik
|
||||
- Validador de Schema - Yup
|
||||
- Cliente de Requisições - axios
|
||||
- Monitor de Arquivos - chokidar
|
||||
|
||||
### Dependências
|
||||
|
||||
Você precisará do [Node v18.x (ou da versão LTS mais recente)](https://nodejs.org/en/) e do npm na versão 8.x. Nós utilizamos npm workspaces no projeto.
|
||||
|
||||
## Desenvolvimento
|
||||
|
||||
Bruno está sendo desenvolvido como um aplicativo de desktop. Você precisa carregar o programa executando o aplicativo Next.js em um terminal e, em seguida, executar o aplicativo Electron em outro terminal.
|
||||
|
||||
### Dependências
|
||||
|
||||
- NodeJS v18
|
||||
|
||||
### Desenvolvimento Local
|
||||
|
||||
```bash
|
||||
# use nodejs 18 version
|
||||
nvm use
|
||||
|
||||
# install deps
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# build graphql docs
|
||||
npm run build:graphql-docs
|
||||
|
||||
# build bruno query
|
||||
npm run build:bruno-query
|
||||
|
||||
# run next app (terminal 1)
|
||||
npm run dev:web
|
||||
|
||||
# run electron app (terminal 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
Você pode se deparar com o erro `Unsupported platform` ao executar o comando `npm install`. Para corrigir isso, você precisará excluir a pasta `node_modules` e o arquivo `package-lock.json` e, em seguida, executar o comando `npm install` novamente. Isso deve instalar todos os pacotes necessários para executar o aplicativo.
|
||||
|
||||
```shell
|
||||
# delete node_modules in sub-directories
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# delete package-lock in sub-directories
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### Testando
|
||||
|
||||
```bash
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Envio de Pull Request
|
||||
|
||||
- Por favor, mantenha os PRs pequenos e focados em uma única coisa.
|
||||
- Siga o formato de criação de branches.
|
||||
- feature/[nome da funcionalidade]: Esta branch deve conter alterações para uma funcionalidade específica.
|
||||
- Exemplo: feature/dark-mode
|
||||
- bugfix/[nome do bug]: Esta branch deve conter apenas correções para um bug específico.
|
||||
- Exemplo: bugfix/bug-1
|
||||
81
docs/contributing/contributing_ro.md
Normal file
81
docs/contributing/contributing_ro.md
Normal file
@@ -0,0 +1,81 @@
|
||||
[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ă**
|
||||
|
||||
## Haideţi să îmbunătățim Bruno, împreună!!
|
||||
|
||||
Ne bucurăm că doriți să îmbunătățiți bruno. Mai jos sunt instrucțiunile pentru ca să porniți bruno pe calculatorul dvs.
|
||||
|
||||
### Stack-ul tehnologic
|
||||
|
||||
Bruno este construit cu Next.js și React. De asemenea, folosim electron pentru a livra o versiune desktop (care poate folosi colecții locale)
|
||||
|
||||
Bibliotecile pe care le folosim
|
||||
|
||||
- CSS - Tailwind
|
||||
- Editori de cod - Codemirror
|
||||
- Management de condiție - Redux
|
||||
- Icoane - Tabler Icons
|
||||
- Formulare - formik
|
||||
- Validarea schemelor - Yup
|
||||
- Cererile client - axios
|
||||
- Observatorul sistemului de fișiere - chokidar
|
||||
|
||||
### Dependențele
|
||||
|
||||
Veți avea nevoie de [Node v18.x sau cea mai recentă versiune LTS](https://nodejs.org/en/) și npm 8.x. Noi folosim spații de lucru npm în proiect
|
||||
|
||||
## Dezvoltarea
|
||||
|
||||
Bruno este dezvoltat ca o aplicație desktop. Ca să porniți aplicatia trebuie să rulați aplicația Next.js într-un terminal și apoi să rulați aplicația electron într-un alt terminal.
|
||||
|
||||
```shell
|
||||
# folosiți nodejs versiunea 18
|
||||
nvm use
|
||||
|
||||
# instalați dependențele
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# construiți documente graphql
|
||||
npm run build:graphql-docs
|
||||
|
||||
# construiți bruno query
|
||||
npm run build:bruno-query
|
||||
|
||||
# rulați aplicația next (terminal 1)
|
||||
npm run dev:web
|
||||
|
||||
# rulați aplicația electron (terminal 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### Depanare
|
||||
|
||||
Este posibil să întâmpinați o eroare `Unsupported platform` când rulați „npm install”. Pentru a remedia acest lucru, va trebui să ștergeți `node_modules` și `package-lock.json` și să rulați `npm install`. Aceasta ar trebui să instaleze toate pachetele necesare pentru a rula aplicația.
|
||||
|
||||
```shell
|
||||
# Ștergeți node_modules din subdirectoare
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# Ștergeți package-lock din subdirectoare
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### Testarea
|
||||
|
||||
```shell
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
|
||||
### Crearea unui Pull Request
|
||||
|
||||
- Vă rugăm să păstrați PR-urile mici și concentrate pe un singur lucru
|
||||
- Vă rugăm să urmați formatul de creare a branchurilor
|
||||
- feature/[Numele funcției]: Acest branch ar trebui să conțină modificări pentru o funcție anumită
|
||||
- Exemplu: feature/dark-mode
|
||||
- bugfix/[Numele eroarei]: Acest branch ar trebui să conţină numai remedieri pentru o eroare anumită
|
||||
- Exemplu bugfix/bug-1
|
||||
91
docs/contributing/contributing_ru.md
Normal file
91
docs/contributing/contributing_ru.md
Normal file
@@ -0,0 +1,91 @@
|
||||
[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)
|
||||
|
||||
## Давайте вместе сделаем Бруно лучше!!!
|
||||
|
||||
Я рад, что Вы хотите усовершенствовать bruno. Ниже приведены рекомендации по запуску bruno на вашем компьютере.
|
||||
|
||||
### Стек
|
||||
|
||||
Bruno построен с использованием Next.js и React. Мы также используем electron для поставки десктопной версии ( которая поддерживает локальные коллекции )
|
||||
|
||||
Библиотеки, которые мы используем
|
||||
|
||||
- CSS - Tailwind
|
||||
- Редакторы кода - Codemirror
|
||||
- Управление состоянием - Redux
|
||||
- Иконки - Tabler Icons
|
||||
- Формы - formik
|
||||
- Валидация схем - Yup
|
||||
- Запросы клиента - axios
|
||||
- Наблюдатель за файловой системой - chokidar
|
||||
|
||||
### Зависимости
|
||||
|
||||
Вам потребуется [Node v18.x или последняя версия LTS](https://nodejs.org/en/) и npm 8.x. В проекте мы используем рабочие пространства npm
|
||||
|
||||
### Приступим к коду
|
||||
|
||||
Пожалуйста, обратитесь к [development_ru.md](docs/development_ru.md) для получения инструкций по запуску локальной среды разработки.
|
||||
|
||||
### Создание Pull Request
|
||||
|
||||
- Пожалуйста, пусть PR будет небольшим и сфокусированным на одной вещи
|
||||
- Пожалуйста, соблюдайте формат создания веток
|
||||
- feature/[название функции]: Эта ветка должна содержать изменения для конкретной функции
|
||||
- Пример: feature/dark-mode
|
||||
- bugfix/[название ошибки]: Эта ветка должна содержать только исправления для конкретной ошибки
|
||||
- Пример bugfix/bug-1
|
||||
|
||||
## Разработка
|
||||
|
||||
Bruno разрабатывается как десктопное приложение. Необходимо загрузить приложение, запустив приложение Next.js в одном терминале, а затем запустить приложение electron в другом терминале.
|
||||
|
||||
### Зависимости
|
||||
|
||||
- NodeJS v18
|
||||
|
||||
### Локальная разработка
|
||||
|
||||
```bash
|
||||
# используйте nodejs 18 версии
|
||||
nvm use
|
||||
|
||||
# установите зависимости
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# билд документации по graphql
|
||||
npm run build:graphql-docs
|
||||
|
||||
# билд bruno query
|
||||
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 в подкаталогах
|
||||
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
|
||||
```
|
||||
37
docs/contributing/contributing_tr.md
Normal file
37
docs/contributing/contributing_tr.md
Normal file
@@ -0,0 +1,37 @@
|
||||
[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)
|
||||
|
||||
## 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.
|
||||
|
||||
### Kullanılan Teknolojiler
|
||||
|
||||
Bruno, Next.js ve React kullanılarak oluşturulmuştur. Ayrıca bir masaüstü sürümü (yerel koleksiyonları destekleyen) göndermek için electron kullanıyoruz
|
||||
|
||||
Kullandığımız kütüphaneler
|
||||
|
||||
- CSS - Tailwind
|
||||
- Kod Düzenleyiciler - Codemirror
|
||||
- Durum Yönetimi - Redux
|
||||
- Iconlar - Tabler Simgeleri
|
||||
- Formlar - formik
|
||||
- Şema Doğrulama - Yup
|
||||
- İstek İstemcisi - axios
|
||||
- Dosya Sistemi İzleyicisi - chokidar
|
||||
|
||||
### Bağımlılıklar
|
||||
|
||||
[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
|
||||
|
||||
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.
|
||||
|
||||
### Pull Request Oluşturma
|
||||
|
||||
- Lütfen PR'ları küçük tutun ve tek bir şeye odaklanın
|
||||
- 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
|
||||
- Örnek bugfix/bug-1
|
||||
91
docs/contributing/contributing_ua.md
Normal file
91
docs/contributing/contributing_ua.md
Normal file
@@ -0,0 +1,91 @@
|
||||
[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)
|
||||
|
||||
## Давайте зробимо Bruno краще, разом !!
|
||||
|
||||
Я дуже радий що Ви бажаєте покращити Bruno. Нижче наведені вказівки як розпочати розробку Bruno на Вашому комп'ютері.
|
||||
|
||||
### Стек технологій
|
||||
|
||||
Bruno побудований на Next.js та React. Також для десктопної версії (яка підтримує локальні колекції) використовується Electron
|
||||
|
||||
Бібліотеки, які ми використовуємо
|
||||
|
||||
- CSS - Tailwind
|
||||
- Редактори коду - Codemirror
|
||||
- Керування станом - Redux
|
||||
- Іконки - Tabler Icons
|
||||
- Форми - formik
|
||||
- Валідація по схемі - Yup
|
||||
- Клієнт запитів - axios
|
||||
- Спостерігач за файловою системою - chokidar
|
||||
|
||||
### Залежності
|
||||
|
||||
Вам знадобиться [Node v18.x або остання LTS версія](https://nodejs.org/en/) та npm 8.x. Ми використовуєм npm workspaces в цьому проекті
|
||||
|
||||
### Починаєм писати код
|
||||
|
||||
Будь ласка, зверніться до [development_ua.md](docs/development_ua.md) за інструкціями щодо запуску локального середовища розробки.
|
||||
|
||||
### Створення Pull Request-ів
|
||||
|
||||
- Будь ласка, робіть PR-и маленькими і сфокусованими на одній речі
|
||||
- Будь ласка, слідуйте формату назв гілок
|
||||
- feature/[назва feature]: Така гілка має містити зміни лише щодо конкретної feature
|
||||
- Приклад: feature/dark-mode
|
||||
- bugfix/[назва баґу]: Така гілка має містити лише виправлення конкретного багу
|
||||
- Приклад: bugfix/bug-1
|
||||
|
||||
## Розробка
|
||||
|
||||
Bruno розробляється як декстопний застосунок. Вам потрібно запустити Next.js в одній сесії терміналу, та запустити застосунок Electron в іншій сесії терміналу.
|
||||
|
||||
### Залежності
|
||||
|
||||
- NodeJS v18
|
||||
|
||||
### Локальна розробка
|
||||
|
||||
```bash
|
||||
# Використовуйте nodejs 18-ї версії
|
||||
nvm use
|
||||
|
||||
# встановіть залежності
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# зберіть документацію graphql
|
||||
npm run build:graphql-docs
|
||||
|
||||
# зберіть bruno query
|
||||
npm run build:bruno-query
|
||||
|
||||
# запустіть додаток next (термінал 1)
|
||||
npm run dev:web
|
||||
|
||||
# запустіть додаток електрон (термінал 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### Усунення несправностей
|
||||
|
||||
Ви можете зтикнутись із помилкою `Unsupported platform` коли запускаєте `npm install`. Щоб усунути цю проблему, вам потрібно видалити `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
|
||||
```
|
||||
@@ -1,53 +0,0 @@
|
||||
## Development
|
||||
|
||||
Bruno is deing developed as a desktop app. You need to load the app by running the nextjs app in one terminal and then run the electron app in another terminal.
|
||||
|
||||
### Dependencies
|
||||
* NodeJS v18
|
||||
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
# use nodejs 18 version
|
||||
nvm use
|
||||
|
||||
# install deps
|
||||
npm i --legacy-peer-deps
|
||||
|
||||
# build graphql docs
|
||||
# note: you can for now ignore the error thrown while building the graphql docs
|
||||
npm run build:graphql-docs
|
||||
|
||||
# build bruno query
|
||||
npm run build:bruno-query
|
||||
|
||||
# run next app (terminal 1)
|
||||
npm run dev:web
|
||||
|
||||
# run electron app (terminal 2)
|
||||
npm run dev:electron
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
You might encounter a `Unsupported platform` error when you run `npm install`. To fix this, you will need to delete `node_modules` and `package-lock.json` and run `npm install`. This should install all the necessary packages needed to run the app.
|
||||
|
||||
```shell
|
||||
# Delete node_modules in sub-directories
|
||||
find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do
|
||||
rm -rf "$dir"
|
||||
done
|
||||
|
||||
# Delete package-lock in sub-directories
|
||||
find . -type f -name "package-lock.json" -delete
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
# bruno-schema
|
||||
npm test --workspace=packages/bruno-schema
|
||||
|
||||
# bruno-lang
|
||||
npm test --workspace=packages/bruno-lang
|
||||
```
|
||||
5
docs/publishing/publishing_pt_br.md
Normal file
5
docs/publishing/publishing_pt_br.md
Normal file
@@ -0,0 +1,5 @@
|
||||
### 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.
|
||||
|
||||
Embora a maioria de nossas funcionalidades seja gratuita e de código aberto (o que abrange API's REST e GraphQL), buscamos alcançar um equilíbrio harmonioso entre os princípios de código aberto e sustentabilidade. - https://github.com/usebruno/bruno/discussions/269
|
||||
8
docs/publishing/publishing_ro.md
Normal file
8
docs/publishing/publishing_ro.md
Normal file
@@ -0,0 +1,8 @@
|
||||
[English](/publishing.md) | [Português (BR)](/docs/publishing/publishing_pt_br.md) | **Română**
|
||||
|
||||
### Publicarea lui Bruno la un gestionar de pachete nou
|
||||
|
||||
Deși codul nostru este cu sursă deschisă și disponibil pentru utilizare pentru toată lumea, vă rugăm să ne contactați înainte de a considera publicarea pe gestionari de pachete noi. În calitate de creator al lui Bruno, dețin marca comercială `Bruno` pentru acest proiect și aș dori să gestionez distribuția acestuia. Dacă doriți să-l vedeți pe Bruno pe un gestionar de pachete nou, vă rugăm să creați un issue pe GitHub.
|
||||
|
||||
În timp ce majoritatea funcțiilor noastre sunt gratuite și cu sursă deschisă (ceea ce acoperă API-uri REST și GraphQL),
|
||||
ne străduim să găsim un echilibru armonios între principiile de sursă deschisă și sustenabilitate - https://github.com/usebruno/bruno/discussions/269
|
||||
123
docs/readme/readme_bn.md
Normal file
123
docs/readme/readme_bn.md
Normal file
@@ -0,0 +1,123 @@
|
||||
<br />
|
||||
<img src="../../assets/images/logo-transparent.png" width="80"/>
|
||||
|
||||
### ব্রুনো - 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) | [Українська](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) | **বাংলা**
|
||||
|
||||
ব্রুনো হল একটি নতুন এবং উদ্ভাবনী API ক্লায়েন্ট, যার লক্ষ্য পোস্টম্যান এবং অনুরূপ সরঞ্জাম দ্বারা প্রতিনিধিত্ব করা স্থিতাবস্থায় বিপ্লব ঘটানো।
|
||||
|
||||
ব্রুনো আপনার সংগ্রহগুলি সরাসরি আপনার ফাইল সিস্টেমের একটি ফোল্ডারে সঞ্চয় করে। আমরা API অনুরোধ সম্পর্কে তথ্য সংরক্ষণ করতে একটি প্লেইন টেক্সট মার্কআপ ভাষা, ব্রু ব্যবহার করি।
|
||||
|
||||
আপনি আপনার API সংগ্রহে সহযোগিতা করতে গিট বা আপনার পছন্দের যেকোনো সংস্করণ নিয়ন্ত্রণ ব্যবহার করতে পারেন।
|
||||
|
||||
ব্রুনো শুধুমাত্র অফলাইন। ব্রুনোতে ক্লাউড-সিঙ্ক যোগ করার কোন পরিকল্পনা নেই, কখনও। আমরা আপনার ডেটা গোপনীয়তার মূল্য দিই এবং বিশ্বাস করি এটি আপনার ডিভাইসে থাকা উচিত। আমাদের দীর্ঘমেয়াদী দৃষ্টি পড়ুন। [এখানে ](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
📢 ইন্ডিয়া FOSS 3.0 সম্মেলনে আমাদের সাম্প্রতিক আলোচনা দেখুন [এখানে](https://www.youtube.com/watch?v=7bSMFpbcPiY)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### স্থাপন
|
||||
|
||||
ব্রুনো বাইনারি ডাউনলোড হিসাবে উপলব্ধ [আমাদের ওয়েবসাইটে](https://www.usebruno.com/downloads) ম্যাক, উইন্ডোজ এবং লিনাক্সের জন্য।
|
||||
|
||||
আপনি Homebrew, Chocolatey, Snap এবং Apt এর মত প্যাকেজ ম্যানেজারদের মাধ্যমে ব্রুনো ইনস্টল করতে পারেন।
|
||||
|
||||
```sh
|
||||
# Homebrew এর মাধ্যমে Mac-এ
|
||||
brew install bruno
|
||||
|
||||
# চকোলেটির মাধ্যমে উইন্ডোজে
|
||||
choco install bruno
|
||||
|
||||
# স্ন্যাপ এর মাধ্যমে লিনাক্সে
|
||||
snap install bruno
|
||||
|
||||
# Apt এর মাধ্যমে লিনাক্সে
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266
|
||||
|
||||
echo "deb [signed-by=/etc/apt/keyrings/bruno.gpg] http://debian.usebruno.com/ bruno stable" | sudo tee /etc/apt/sources.list.d/bruno.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install bruno
|
||||
```
|
||||
|
||||
### একাধিক প্ল্যাটফর্মে চালান 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Git এর মাধ্যমে সহযোগিতা করুন 👩💻🧑💻
|
||||
|
||||
অথবা আপনার পছন্দের যেকোনো সংস্করণ নিয়ন্ত্রণ ব্যবস্থা
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### গুরুত্বপূর্ণ লিংক 📌
|
||||
|
||||
- [আমাদের দীর্ঘমেয়াদী দৃষ্টি](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [রোডম্যাপ](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [ডকুমেন্টেশন](https://docs.usebruno.com)
|
||||
- [ওয়েবসাইট](https://www.usebruno.com)
|
||||
- [মূল্য](https://www.usebruno.com/pricing)
|
||||
- [ডাউনলোড করুন](https://www.usebruno.com/downloads)
|
||||
|
||||
### শোকেস 🎥
|
||||
|
||||
- [প্রশংসাপত্র](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [নলেজ হাব](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [স্ক্রিপ্টম্যানিয়া](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### সমর্থন ❤️
|
||||
|
||||
উফ ! আপনি যদি প্রকল্পটি পছন্দ করেন তবে ⭐ বোতামটি টিপুন !!
|
||||
|
||||
### প্রশংসাপত্র শেয়ার করুন 📣
|
||||
|
||||
যদি ব্রুনো আপনাকে কর্মক্ষেত্রে এবং আপনার দলগুলিতে সাহায্য করে থাকে, অনুগ্রহ করে আপনার [আমাদের গিটহাব আলোচনায় প্রশংসাপত্রগুলি](https://github.com/usebruno/bruno/discussions/343) শেয়ার করতে ভুলবেন না
|
||||
|
||||
### নতুন প্যাকেজ পরিচালকদের কাছে প্রকাশ করা হচ্ছে
|
||||
|
||||
আরও তথ্যের জন্য অনুগ্রহ করে [এখানে](publishing.md) দেখুন।
|
||||
|
||||
### অবদান 👩💻🧑💻
|
||||
|
||||
আমি খুশি যে আপনি ব্রুনোর উন্নতি করতে চাইছেন। অনুগ্রহ করে [অবদানকারী নির্দেশিকা](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>
|
||||
|
||||
### সাথে থাকুন 🌐
|
||||
|
||||
[𝕏 (টুইটার)](https://twitter.com/use_bruno) <br />
|
||||
[ওয়েবসাইট](https://www.usebruno.com) <br />
|
||||
[ডিসকর্ড](https://discord.com/invite/KgcZUncpjq) <br />
|
||||
[লিঙ্কডইন](https://www.linkedin.com/company/usebruno)
|
||||
|
||||
### ট্রেডমার্ক
|
||||
|
||||
**নাম**
|
||||
|
||||
`Bruno` হল একটি ট্রেডমার্ক [Anoop M D](https://www.helloanoop.com/)
|
||||
|
||||
**লোগো**
|
||||
|
||||
লোগোটি [OpenMoji](https://openmoji.org/library/emoji-1F436/) থেকে নেওয়া হয়েছে। লাইসেন্স: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
### লাইসেন্স 📄
|
||||
|
||||
[MIT](license.md)
|
||||
95
docs/readme/readme_de.md
Normal file
95
docs/readme/readme_de.md
Normal file
@@ -0,0 +1,95 @@
|
||||
<br />
|
||||
<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/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)
|
||||
|
||||
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.
|
||||
|
||||
Du kannst Git oder eine andere Versionskontrolle deiner Wahl verwenden, um an deinen API-Sammlungen gemeinsam mit anderen 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).
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Einsatz auf verschiedensten Plattformen 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Zusammenarbeiten mit Git 👩💻🧑💻
|
||||
|
||||
oder eine Versionskontrolle Deiner Wahl
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Wichtige Links 📌
|
||||
|
||||
- [Unsere Langzeit-Vision](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [Roadmap](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [Dokumentation](https://docs.usebruno.com)
|
||||
- [Webseite](https://www.usebruno.com)
|
||||
- [Preise](https://www.usebruno.com/pricing)
|
||||
- [Download](https://www.usebruno.com/downloads)
|
||||
|
||||
### Showcase 🎥
|
||||
|
||||
- [Erfahrungsberichte](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Wissenswertes](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Scriptmania](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### Unterstützung ❤️
|
||||
|
||||
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.
|
||||
|
||||
### Veröffentlichung in neuen Paketmanagern
|
||||
|
||||
Bitte [hier](/publishing.md) für mehr Informationen lesen.
|
||||
|
||||
### Mitmachen 👩💻🧑💻
|
||||
|
||||
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.
|
||||
|
||||
### Autoren
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### In Verbindung bleiben 🌐
|
||||
|
||||
[Twitter](https://twitter.com/use_bruno) <br />
|
||||
[Webseite](https://www.usebruno.com) <br />
|
||||
[Discord](https://discord.com/invite/KgcZUncpjq) <br />
|
||||
[LinkedIn](https://www.linkedin.com/company/usebruno)
|
||||
|
||||
### Markenzeichen
|
||||
|
||||
**Name**
|
||||
|
||||
`Bruno` ist ein Markenzeichen von [Anoop M D](https://www.helloanoop.com/)
|
||||
|
||||
**Logo**
|
||||
|
||||
Das Logo stammt von [OpenMoji](https://openmoji.org/library/emoji-1F436/). Lizenz: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
### Lizenz 📄
|
||||
|
||||
[MIT](/license.md)
|
||||
93
docs/readme/readme_es.md
Normal file
93
docs/readme/readme_es.md
Normal file
@@ -0,0 +1,93 @@
|
||||
<br />
|
||||
<img src="../../assets/images/logo-transparent.png" width="80"/>
|
||||
|
||||
### 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/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.
|
||||
|
||||
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)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Ejecútalo en múltiples plataformas 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Colabora vía Git 👩💻🧑💻
|
||||
|
||||
O cualquier otro sistema de control de versiones que prefieras
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Enlaces importantes 📌
|
||||
|
||||
- [Nuestra Visión a Largo Plazo](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [Hoja de Ruta](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [Documentación](https://docs.usebruno.com)
|
||||
- [Sitio Web](https://www.usebruno.com)
|
||||
- [Precios](https://www.usebruno.com/pricing)
|
||||
- [Descargas](https://www.usebruno.com/downloads)
|
||||
|
||||
### Casos de uso 🎥
|
||||
|
||||
- [Testimonios](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Centro de Conocimiento](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Scripts de la Comunidad](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### Apoya el proyecto ❤️
|
||||
|
||||
¡Guau! Si te gusta el proyecto, ¡dale al botón de ⭐!
|
||||
|
||||
### Comparte tus testimonios 📣
|
||||
|
||||
Si Bruno te ha ayudado en tu trabajo y con tus equipos, por favor, no olvides compartir tus testimonios en [nuestras discusiones de GitHub](https://github.com/usebruno/bruno/discussions/343)
|
||||
|
||||
### Publicar en nuevos gestores de paquetes
|
||||
|
||||
Por favor, consulta [aquí](publishing.md) para más información.
|
||||
|
||||
### Contribuye 👩💻🧑💻
|
||||
|
||||
Estamos encantados de que quieras ayudar a mejorar Bruno. Por favor, consulta la [guía de contribución](contributing_es.md) para más información.
|
||||
|
||||
Incluso si no puedes contribuir con código, no dudes en reportar errores y solicitar nuevas funcionalidades que necesites para resolver tu caso de uso.
|
||||
|
||||
### Colaboradores
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Mantente en contacto 🌐
|
||||
|
||||
[X](https://twitter.com/use_bruno) <br />
|
||||
[Sitio Web](https://www.usebruno.com) <br />
|
||||
[Discord](https://discord.com/invite/KgcZUncpjq) <br />
|
||||
[LinkedIn](https://www.linkedin.com/company/usebruno)
|
||||
|
||||
### Marca
|
||||
|
||||
**Nombre**
|
||||
|
||||
`Bruno` es una marca propiedad de [Anoop M D](https://www.helloanoop.com/).
|
||||
|
||||
**Logo**
|
||||
|
||||
El logo fue obtenido de [OpenMoji](https://openmoji.org/library/emoji-1F436/). Licencia: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
### Licencia 📄
|
||||
|
||||
[MIT](license.md)
|
||||
97
docs/readme/readme_fr.md
Normal file
97
docs/readme/readme_fr.md
Normal file
@@ -0,0 +1,97 @@
|
||||
<br />
|
||||
<img src="../../assets/images/logo-transparent.png" width="80"/>
|
||||
|
||||
### Bruno - IDE Opensource pour explorer et tester des 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](/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 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).
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Fonctionne sur de multiples platformes 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Collaborer via Git 👩💻🧑💻
|
||||
|
||||
Ou n'importe quel système de gestion de sources
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Liens importants 📌
|
||||
|
||||
- [Notre vision à long terme (en anglais)](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [Roadmap](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [Documentation](https://docs.usebruno.com)
|
||||
- [Site web](https://www.usebruno.com)
|
||||
- [Prix](https://www.usebruno.com/pricing)
|
||||
- [Téléchargement](https://www.usebruno.com/downloads)
|
||||
|
||||
### Showcase 🎥
|
||||
|
||||
- [Témoignages](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Centre de connaissance](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Scriptmania](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### Soutien ❤️
|
||||
|
||||
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)
|
||||
|
||||
### Publier Bruno sur un nouveau gestionnaire de paquets
|
||||
|
||||
Veuillez regarder [ici](/publishing.md) pour plus d'information.
|
||||
|
||||
### Contribuer 👩💻🧑💻
|
||||
|
||||
Je suis heureux de voir que vous cherchez à améliorer Bruno. Merci de consulter le [guide de contribution](../contributing/contributing_fr.md)
|
||||
|
||||
Même si vous n'êtes pas en mesure de contribuer directement via du code, n'hésitez pas à consigner les bogues et les demandes de nouvelles fonctionnalités pour résoudre vos cas d'usage !
|
||||
|
||||
### Auteurs
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Restons en contact 🌐
|
||||
|
||||
[Twitter](https://twitter.com/use_bruno) <br />
|
||||
[Website](https://www.usebruno.com) <br />
|
||||
[Discord](https://discord.com/invite/KgcZUncpjq) <br />
|
||||
[LinkedIn](https://www.linkedin.com/company/usebruno)
|
||||
|
||||
### Marque
|
||||
|
||||
**Nom**
|
||||
|
||||
`Bruno` est une marque appartenant à [Anoop M D](https://www.helloanoop.com/)
|
||||
|
||||
**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 📄
|
||||
|
||||
[MIT](/license.md)
|
||||
121
docs/readme/readme_it.md
Normal file
121
docs/readme/readme_it.md
Normal file
@@ -0,0 +1,121 @@
|
||||
<br />
|
||||
<img src="../../assets/images/logo-transparent.png" width="80"/>
|
||||
|
||||
### Bruno - Opensource IDE per esplorare e testare gli 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)
|
||||
|
||||
Bruno è un nuovo ed innovativo API client, mirato a rivoluzionare lo status quo rappresentato da Postman e strumenti simili disponibili.
|
||||
|
||||
Bruno memorizza le tue raccolte direttamente in una cartella del tuo filesystem. Utilizziamo un linguaggio di markup in testo semplice chiamato Bru per salvare informazioni sulle richeste API.
|
||||
|
||||
Puoi utilizzare Git o qualsiasi sistema di controllo che preferisci per collaborare sulle tue raccolte di API.
|
||||
|
||||
Bruno funziona solo in modalità offline. Non ci sono piani per aggiungere la sincronizzazione su cloud a Bruno in futuro. Valorizziamo la privacy dei tuoi dati e crediamo che dovrebbero rimanere sul tuo dispositivo. Puoi leggere la nostra visione a lungo termine [qui (in inglese)](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
📢 Guarda la nostra presentazione più recente alla conferenza India FOSS 3.0 [qui](https://www.youtube.com/watch?v=7bSMFpbcPiY)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Installazione
|
||||
|
||||
Bruno è disponisible 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.
|
||||
|
||||
```sh
|
||||
# Su Mac come Homebrew
|
||||
brew install bruno
|
||||
|
||||
# Su Windows come Chocolatey
|
||||
choco install bruno
|
||||
|
||||
# Su Linux tramite Snap
|
||||
snap install bruno
|
||||
|
||||
# Su Linux tramite Apt
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266
|
||||
|
||||
echo "deb [signed-by=/etc/apt/keyrings/bruno.gpg] http://debian.usebruno.com/ bruno stable" | sudo tee /etc/apt/sources.list.d/bruno.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install bruno
|
||||
```
|
||||
|
||||
### Funziona su diverse piattaforme 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Collabora tramite Git 👩💻🧑💻
|
||||
|
||||
O con qualsiasi sistema di controllo di versioni a tua scelta
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Collegamenti importanti 📌
|
||||
|
||||
- [La nostra visione a lungo termine](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [Roadmap](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [Documentazione](https://docs.usebruno.com)
|
||||
- [Sito internet](https://www.usebruno.com)
|
||||
- [Prezzo](https://www.usebruno.com/pricing)
|
||||
- [Download](https://www.usebruno.com/downloads)
|
||||
|
||||
### Showcase 🎥
|
||||
|
||||
- [Testimonianze](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Centro di conoscenza](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Scriptmania](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### Supporto ❤️
|
||||
|
||||
Woof! se ti piace il progetto, premi quel ⭐ pulsante !!
|
||||
|
||||
### Testimonianze condivise 📣
|
||||
|
||||
Se Bruno ti ha aiutato con il tuo lavoro ed il tuo team, per favore non dimenticare di condividere le tue [testimonianze nella nostra discussione su GitHub](https://github.com/usebruno/bruno/discussions/343)
|
||||
|
||||
### Pubblica Bruno su un nuovo gestore di pacchetti
|
||||
|
||||
Per favore vedi [qui](publishing.md) per accedere a più informazioni.
|
||||
|
||||
### Contribuire 👩💻🧑💻
|
||||
|
||||
Sono felice che vuoi migliorare Bruno. Per favore controlla la [guida per la partecipazione](contributing.md)
|
||||
|
||||
Anche se non sei in grado di contribuire tramite il codice, non esitare a segnalare bug e richieste di funzionalità che devono essere implementati per risolvere il tuo caso d'uso.
|
||||
|
||||
### Autori
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Resta in contatto 🌐
|
||||
|
||||
[𝕏 (Twitter)](https://twitter.com/use_bruno) <br />
|
||||
[Sito internet](https://www.usebruno.com) <br />
|
||||
[Discord](https://discord.com/invite/KgcZUncpjq) <br />
|
||||
[LinkedIn](https://www.linkedin.com/company/usebruno)
|
||||
|
||||
### Marchio
|
||||
|
||||
**Nome**
|
||||
|
||||
`Bruno` è un marchio registrato appartenente a [Anoop M D](https://www.helloanoop.com/)
|
||||
|
||||
**Logo**
|
||||
|
||||
Il logo è stato creato da [OpenMoji](https://openmoji.org/library/emoji-1F436/). Licenza: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
### Licenza 📄
|
||||
|
||||
[MIT](license.md)
|
||||
121
docs/readme/readme_kr.md
Normal file
121
docs/readme/readme_kr.md
Normal file
@@ -0,0 +1,121 @@
|
||||
<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)
|
||||
|
||||
Bruno는 새롭고 혁신적인 API 클라이언트로, Postman과 유사한 툴들을 혁신하는 것을 목표로 합니다.
|
||||
|
||||
Bruno는 사용자의 컬렉션을 파일 시스템의 폴더에 직접 저장합니다. 일반 텍스트 마크업 언어인 Bru를 사용해 API 요청에 대한 정보를 저장합니다.
|
||||
|
||||
Git 또는 원하는 버전 관리 도구를 사용하여 API 컬렉션을 연동할 수 있습니다.
|
||||
|
||||
브루는 오프라인 전용입니다. 브루노에 클라우드 동기화 기능을 추가할 계획은 없습니다. 저희는 사용자의 데이터 프라이버시를 소중히 여기며, 데이터는 사용자의 기기에 남아 있어야 한다고 믿습니다. 장기 비전 읽기 [링크](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
📢 Watch our recent talk at India FOSS 3.0 Conference [here](https://www.youtube.com/watch?v=7bSMFpbcPiY)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### 설치
|
||||
|
||||
Bruno 는 여기에서 다운로드 받을 수 있습니다.[링크](https://www.usebruno.com/downloads) (맥, 윈도우, 리눅스)
|
||||
|
||||
Homebrew, Chocolatey, Snap, Apt 같은 패키지 관리자를 통해서도 Bruno를 설치할 수 있습니다.
|
||||
|
||||
```sh
|
||||
# On Mac via Homebrew
|
||||
brew install bruno
|
||||
|
||||
# On Windows via Chocolatey
|
||||
choco install bruno
|
||||
|
||||
# On Linux via Snap
|
||||
snap install bruno
|
||||
|
||||
# On Linux via Apt
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266
|
||||
|
||||
echo "deb [signed-by=/etc/apt/keyrings/bruno.gpg] http://debian.usebruno.com/ bruno stable" | sudo tee /etc/apt/sources.list.d/bruno.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install bruno
|
||||
```
|
||||
|
||||
### 여러 플랫폼에서 실행하세요. 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Git과 연동하세요. 👩💻🧑💻
|
||||
|
||||
또는 원하는 버전 관리 시스템을 선택하세요.
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### 중요 링크 📌
|
||||
|
||||
- [Our Long Term Vision](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [Roadmap](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [Documentation](https://docs.usebruno.com)
|
||||
- [Website](https://www.usebruno.com)
|
||||
- [Pricing](https://www.usebruno.com/pricing)
|
||||
- [Download](https://www.usebruno.com/downloads)
|
||||
|
||||
### 쇼케이스 🎥
|
||||
|
||||
- [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 discussion 공유 링크](https://github.com/usebruno/bruno/discussions/343)
|
||||
|
||||
### 새 패키지 관리자에게 게시
|
||||
|
||||
더 많은 정보를 확인하시려명 링크를 클릭해 주세요.[배포 가이드](publishing.md)
|
||||
|
||||
### 컨트리뷰트 👩💻🧑💻
|
||||
|
||||
컨트리뷰트에 관심이 있으시면 링크를 참고해 주세요. [컨트리뷰트 가이드](contributing.md)
|
||||
|
||||
코드를 통해 기여할 수 없더라도 사용 사례를 해결하기 위해 구현이 필요한 버그나 기능 요청을 주저하지 마시고 제출해 주세요.
|
||||
|
||||
### Authors
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Stay in touch 🌐
|
||||
|
||||
[𝕏 (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)
|
||||
|
||||
### Trademark
|
||||
|
||||
**Name**
|
||||
|
||||
`Bruno` is a trademark held by [Anoop M D](https://www.helloanoop.com/)
|
||||
|
||||
**Logo**
|
||||
|
||||
The logo is sourced from [OpenMoji](https://openmoji.org/library/emoji-1F436/). License: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
### License 📄
|
||||
|
||||
[MIT](license.md)
|
||||
121
docs/readme/readme_pt_br.md
Normal file
121
docs/readme/readme_pt_br.md
Normal file
@@ -0,0 +1,121 @@
|
||||
<br />
|
||||
<img src="../../assets/images/logo-transparent.png" width="80"/>
|
||||
|
||||
### 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/pulse)
|
||||
[](https://twitter.com/use_bruno)
|
||||
[](https://www.usebruno.com)
|
||||
[](https://www.usebruno.com/downloads)
|
||||
|
||||
Bruno é um novo e inovador cliente de API, com o objetivo de revolucionar o status quo representado por ferramentas como o Postman e outras semelhantes.
|
||||
|
||||
Bruno armazena suas coleções diretamente em uma pasta no seu sistema de arquivos. Utilizamos uma linguagem de marcação de texto simples, chamada Bru, para salvar informações sobre requisições de API.
|
||||
|
||||
Você pode usar o Git ou qualquer sistema de controle de versão de sua escolha para colaborar em suas coleções de API.
|
||||
|
||||
Bruno é totalmente offline. Não há planos de adicionar sincronização em nuvem ao Bruno, nunca. Valorizamos a privacidade de seus dados e acreditamos que eles devem permanecer em seu dispositivo. Saiba mais sobre nossa visão a longo prazo [aqui](https://github.com/usebruno/bruno/discussions/269).
|
||||
|
||||
📢 Assista à nossa palestra recente na India FOSS 3.0 Conference [aqui](https://www.youtube.com/watch?v=7bSMFpbcPiY).
|
||||
|
||||
 <br /><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.
|
||||
|
||||
Você também pode instalar o Bruno via gerenciadores de pacotes como Homebrew, Chocolatey, Snap e Apt.
|
||||
|
||||
```sh
|
||||
# Mac via Homebrew
|
||||
brew install bruno
|
||||
|
||||
# Windows via Chocolatey
|
||||
choco 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
|
||||
```
|
||||
|
||||
### Execute em várias plataformas 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Colaboração via Git 👩💻🧑💻
|
||||
|
||||
Ou qualquer sistema de controle de versão de sua escolha.
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### 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)
|
||||
- [Website](https://www.usebruno.com)
|
||||
- [Preços](https://www.usebruno.com/pricing)
|
||||
- [Download](https://www.usebruno.com/downloads)
|
||||
|
||||
### Showcase 🎥
|
||||
|
||||
- [Depoimentos](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Hub de Conhecimento](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Scriptmania](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### Apoie ❤️
|
||||
|
||||
Au-au! Se você gosta do projeto, clique no botão ⭐!!
|
||||
|
||||
### Compartilhe sua experiência 📣
|
||||
|
||||
Se o Bruno ajudou no seu trabalho e/ou no trabalho de sua equipe, por favor, não se esqueça de compartilhar seu [depoimento em nossas discussões no GitHub](https://github.com/usebruno/bruno/discussions/343).
|
||||
|
||||
### Publicando em Novos Gerenciadores de Pacotes
|
||||
|
||||
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 />
|
||||
[Website](https://www.usebruno.com) <br />
|
||||
[Discord](https://discord.com/invite/KgcZUncpjq) <br />
|
||||
[LinkedIn](https://www.linkedin.com/company/usebruno)
|
||||
|
||||
### Trademark
|
||||
|
||||
**Nome**
|
||||
|
||||
`Bruno` é uma marca registrada de [Anoop M D](https://www.helloanoop.com/).
|
||||
|
||||
**Logo**
|
||||
|
||||
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/).
|
||||
|
||||
### Licença 📄
|
||||
|
||||
[MIT](license.md)
|
||||
125
docs/readme/readme_ro.md
Normal file
125
docs/readme/readme_ro.md
Normal file
@@ -0,0 +1,125 @@
|
||||
<br />
|
||||
<img src="../../assets/images/logo-transparent.png" width="80"/>
|
||||
|
||||
### Bruno - Mediu integrat de dezvoltare cu sursă deschisă pentru explorarea și testarea API-urilor.
|
||||
|
||||
[](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) | [Українська](/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ă**
|
||||
|
||||
Bruno este un client API nou și inovativ, care vizează să revoluționeze status quo-ul reprezentat de Postman și alte instrumente similare.
|
||||
|
||||
Bruno salvează colecțiile voastre direct într-o mapă din sistemul dvs. de fișiere. Folosim un limbaj de marcare cu text simplu, Bru, pentru a salva informații despre cererile API.
|
||||
|
||||
Puteți folosi Git sau orice altă unealtă de control al versiunii la alegere pentru a colabora la colecțiile API voastre.
|
||||
|
||||
Bruno este numai offline. Nu va exista niciodată vreun plan pentru a adăuga sincronizarea cloud la Bruno. Noi valorăm confidențialitatea datelor voastre și credem că ar trebui să rămână pe dispozitivul vostru. Citiți viziunea noastră pe termen lung [aici](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
📢 Priviți prezentarea noastră recentă de la India FOSS 3.0 Conference [aici](https://www.youtube.com/watch?v=7bSMFpbcPiY)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Instalarea
|
||||
|
||||
Bruno este disponibil ca descărcare binară [pe website-ul nostru](https://www.usebruno.com/downloads) pentru Mac, Windows și Linux.
|
||||
|
||||
De asemenea, puteţi instala Bruno cu un gestionar de pachete precum Homebrew, Chocolatey, Snap şi Apt.
|
||||
|
||||
```sh
|
||||
# Pe Mac cu Homebrew
|
||||
brew install bruno
|
||||
|
||||
# Pe Windows cu Chocolatey
|
||||
choco install bruno
|
||||
|
||||
# Pe Linux cu Snap
|
||||
snap install bruno
|
||||
|
||||
# Pe Linux cu Apt
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
sudo gpg --no-default-keyring --keyring /etc/apt/keyrings/bruno.gpg --keyserver keyserver.ubuntu.com --recv-keys 9FA6017ECABE0266
|
||||
|
||||
echo "deb [signed-by=/etc/apt/keyrings/bruno.gpg] http://debian.usebruno.com/ bruno stable" | sudo tee /etc/apt/sources.list.d/bruno.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install bruno
|
||||
```
|
||||
|
||||
### Utilizați pe mai multe platforme 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Colaborați cu Git 👩💻🧑💻
|
||||
|
||||
Sau orice unealtă de control al versiunii la alegere
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Linkuri importante 📌
|
||||
|
||||
- [Viziunea noastră pe termen lung](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [Roadmap](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [Documentație](https://docs.usebruno.com)
|
||||
- [Stack Overflow](https://stackoverflow.com/questions/tagged/bruno)
|
||||
- [Website](https://www.usebruno.com)
|
||||
- [Prețuri](https://www.usebruno.com/pricing)
|
||||
- [Descărcări](https://www.usebruno.com/downloads)
|
||||
- [Sponsori GitHub](https://github.com/sponsors/helloanoop).
|
||||
|
||||
### Vitrina 🎥
|
||||
|
||||
- [Recenzii](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Centrul de cunoștințe](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Scriptmania](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### Sprijiniți ❤️
|
||||
|
||||
Dacă vă place Bruno și doriți să sprijiniți munca noastră de sursă deschisă, puteți considera să ne sponsorizați [pe GitHub](https://github.com/sponsors/helloanoop).
|
||||
|
||||
### Distribuiți recenziile 📣
|
||||
|
||||
Dacă Bruno va ajutat la locul de muncă și la echipele dvs., vă rugăm să nu uitați să distribuiți [recenziile în discuția noastră GitHub](https://github.com/usebruno/bruno/discussions/343)
|
||||
|
||||
### Publicarea la gestionari de pachete noi
|
||||
|
||||
Vă rugăm să citiţi [aici](/docs/publishing/publishing_ro.md) pentru mai multă informaţie.
|
||||
|
||||
### Contribuiți 👩💻🧑💻
|
||||
|
||||
Mă bucur că doriți să îmbunătățiți Bruno. Vă rugăm să consultați [ghidul pentru contribuire](/docs/contributing/contributing_ro.md)
|
||||
|
||||
Chiar dacă nu puteți face contribuții prin cod, vă rugăm să nu ezitați să raportați erori și să solicitați funcții care trebuie implementate pentru a rezolva cazul dvs. de utilizare.
|
||||
|
||||
### Autori
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Păstrați legătura 🌐
|
||||
|
||||
[𝕏 (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)
|
||||
|
||||
### Marcă comercială
|
||||
|
||||
**Nume**
|
||||
|
||||
`Bruno` este o marcă deținută de [Anoop M D](https://www.helloanoop.com/)
|
||||
|
||||
**Logo**
|
||||
|
||||
Logo-ul provine de la [OpenMoji](https://openmoji.org/library/emoji-1F436/). Licența: CC [BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
### Licența 📄
|
||||
|
||||
[MIT](license.md)
|
||||
80
docs/readme/readme_ru.md
Normal file
80
docs/readme/readme_ru.md
Normal file
@@ -0,0 +1,80 @@
|
||||
<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) | **Русский** | [Türkçe](/readme_tr.md) | [Deutsch](/readme_de.md) | [Français](/readme_fr.md) | [বাংলা](docs/readme/readme_bn.md)
|
||||
|
||||
Bruno - новый и инновационный клиент API, направленный на революцию в установившейся ситуации, представленной Postman и подобными инструментами.
|
||||
|
||||
Bruno хранит ваши коллекции непосредственно в папке в вашей файловой системе. Для сохранения информации об API-запросах мы используем язык Bru.
|
||||
|
||||
Для совместной работы над коллекциями API можно использовать git или любой другой контроль версий по вашему выбору.
|
||||
|
||||
Bruno работает только в автономном режиме. Добавление облачной синхронизации в Bruno не планируется. Мы ценим конфиденциальность ваших данных и считаем, что они должны оставаться на вашем устройстве. Ознакомьтесь с нашим долгосрочным видением [здесь](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Работа на нескольких платформах 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Совместная работа через Git 👩💻🧑💻
|
||||
|
||||
Или другая система контроля версий по вашему выбору
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Важные ссылки 📌
|
||||
|
||||
- [Наше долгосрочное видение](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [Roadmap](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [Документация](https://docs.usebruno.com)
|
||||
- [Сайт](https://www.usebruno.com)
|
||||
- [Скачать Bruno](https://www.usebruno.com/downloads)
|
||||
|
||||
### Витрина 🎥
|
||||
|
||||
- [Отзывы](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Центр знаний](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Скриптомания](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### Поддержка ❤️
|
||||
|
||||
Гав! Если вам нравится проект, нажмите на звездочку ⭐ !!!
|
||||
|
||||
### Поделись отзывами 📣
|
||||
|
||||
Если Бруно помог вам в работе и в ваших командах, пожалуйста, не забудьте поделиться своим [отзывом на нашем обсуждении в github](https://github.com/usebruno/bruno/discussions/343)
|
||||
|
||||
### Внести вклад 👩💻🧑💻
|
||||
|
||||
Я рад, что Вы хотите улучшить Бруно. Пожалуйста, ознакомьтесь с [этим гайдом](../contributing/contributing_ru.md)
|
||||
|
||||
Даже если вы не можете внести свой вклад с помощью кода, пожалуйста, не стесняйтесь сообщать об ошибках и пожеланиях к функциям, которые необходимо реализовать для решения вашей задачи.
|
||||
|
||||
### Авторы
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Оставайтесь на связи 🌐
|
||||
|
||||
[X ( Twitter )](https://twitter.com/use_bruno) <br />
|
||||
[Наш сайт](https://www.usebruno.com) <br />
|
||||
[Discord](https://discord.com/invite/KgcZUncpjq)
|
||||
|
||||
### Лицензия 📄
|
||||
|
||||
[MIT](/license.md)
|
||||
80
docs/readme/readme_tr.md
Normal file
80
docs/readme/readme_tr.md
Normal file
@@ -0,0 +1,80 @@
|
||||
<br />
|
||||
<img src="../../assets/images/logo-transparent.png" width="80"/>
|
||||
|
||||
### Bruno - API'leri keşfetmek ve test etmek için açık kaynaklı 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** | [Deutsch](/readme_de.md) | [Français](/readme_fr.md) | [বাংলা](docs/readme/readme_bn.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.
|
||||
|
||||
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)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Birden fazla platformda çalıştırın 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Git üzerinden işbirliği yapın 👩💻🧑💻
|
||||
|
||||
Veya seçtiğiniz herhangi bir sürüm kontrol sistemi
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Önemli Bağlantılar 📌
|
||||
|
||||
- [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)
|
||||
- [Web sitesi](https://www.usebruno.com)
|
||||
- [İndir](https://www.usebruno.com/downloads)
|
||||
|
||||
### Vitrin 🎥
|
||||
|
||||
- [Görüşler](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Bilgi Merkezi](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Scriptmania](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### Destek ❤️
|
||||
|
||||
Woof! Projeyi beğendiyseniz, şu ⭐ düğmesine bası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
|
||||
|
||||
### Katkıda Bulunun 👩💻🧑💻
|
||||
|
||||
Bruno'yu geliştirmek istemenize sevindim. Lütfen [katkıda bulunma kılavuzu](../contributing/contributing.md)'na 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.
|
||||
|
||||
### Katkıda Bulunanlar
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/usebruno/bruno/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=usebruno/bruno" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### İletişimde Kalın 🌐
|
||||
|
||||
[Twitter](https://twitter.com/use_bruno) <br />
|
||||
[Website](https://www.usebruno.com) <br />
|
||||
[Discord](https://discord.com/invite/KgcZUncpjq)
|
||||
[LinkedIn](https://www.linkedin.com/company/usebruno)
|
||||
|
||||
### Lisans 📄
|
||||
|
||||
[MIT](/license.md)
|
||||
80
docs/readme/readme_ua.md
Normal file
80
docs/readme/readme_ua.md
Normal file
@@ -0,0 +1,80 @@
|
||||
<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_ru.md) | [Türkçe](/readme_tr.md) | [Deutsch](/readme_de.md) | [Français](/readme_fr.md) | [বাংলা](docs/readme/readme_bn.md)
|
||||
|
||||
Bruno це новий та іноваційний API клієнт, націлений на революційну зміну статус кво, запровадженого інструментами на кшталт Postman.
|
||||
|
||||
Bruno зберігає ваші колекції напряму у теці на вашому диску. Він використовує текстову мову розмітки Bru для збереження інформації про ваші API запити.
|
||||
|
||||
Ви можете використовувати git або будь-яку іншу систему контролю версій щоб спільно працювати над вашими колекціями API запитів.
|
||||
|
||||
Bruno є повністю автономним. Немає жодних планів додавати будь-які синхронізації через хмару, ніколи. Ми цінуємо приватність ваших даних, і вважаєм, що вони мають залишитись лише на вашому комп'ютері. Взнати більше про наше бачення у довготривалій перспективі можна [тут](https://github.com/usebruno/bruno/discussions/269)
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Кросплатформенність 🖥️
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Спільна робота через Git 👩💻🧑💻
|
||||
|
||||
Або будь-яку іншу систему контролю версій на ваш вибір
|
||||
|
||||
 <br /><br />
|
||||
|
||||
### Важливі посилання 📌
|
||||
|
||||
- [Наше бачення довготривалої перспективи проекту](https://github.com/usebruno/bruno/discussions/269)
|
||||
- [Дорожня карта проекту](https://github.com/usebruno/bruno/discussions/384)
|
||||
- [Документація](https://docs.usebruno.com)
|
||||
- [Сайт](https://www.usebruno.com)
|
||||
- [Завантаження](https://www.usebruno.com/downloads)
|
||||
|
||||
### Вітрина 🎥
|
||||
|
||||
- [Відгуки](https://github.com/usebruno/bruno/discussions/343)
|
||||
- [Хаб знань](https://github.com/usebruno/bruno/discussions/386)
|
||||
- [Scriptmania](https://github.com/usebruno/bruno/discussions/385)
|
||||
|
||||
### Підтримка ❤️
|
||||
|
||||
Гав! Якщо вам сподобався проект, тисніть на ⭐ !!
|
||||
|
||||
### Поділитись відгуками 📣
|
||||
|
||||
Якщо Bruno допоміг вам у вашій роботі і вашим командам, будь ласка не забудьте поділитись вашими [відгуками у github дискусії](https://github.com/usebruno/bruno/discussions/343)
|
||||
|
||||
### Зробити свій внесок 👩💻🧑💻
|
||||
|
||||
Я радий що ви бажаєте покращити Bruno. Будь ласка переглянте [інструкцію по контрибуції](../contributing/contributing_ua.md)
|
||||
|
||||
Навіть якщо ви не можете зробити свій внесок пишучи програмний код, будь ласка не соромтесь рапортувати про помилки і писати запити на новий функціонал, який потрібен вам у вашій роботі.
|
||||
|
||||
### Автори
|
||||
|
||||
<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 />
|
||||
[Сайт](https://www.usebruno.com) <br />
|
||||
[Discord](https://discord.com/invite/KgcZUncpjq) <br />
|
||||
[LinkedIn](https://www.linkedin.com/company/usebruno)
|
||||
|
||||
### Ліцензія 📄
|
||||
|
||||
[MIT](/license.md)
|
||||
30185
package-lock.json
generated
Normal file
30185
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@@ -5,7 +5,6 @@
|
||||
"packages/bruno-app",
|
||||
"packages/bruno-electron",
|
||||
"packages/bruno-cli",
|
||||
"packages/bruno-tauri",
|
||||
"packages/bruno-schema",
|
||||
"packages/bruno-query",
|
||||
"packages/bruno-js",
|
||||
@@ -13,13 +12,17 @@
|
||||
"packages/bruno-testbench",
|
||||
"packages/bruno-graphql-docs"
|
||||
],
|
||||
"homepage": "https://usebruno.com",
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^7.6.0",
|
||||
"@jest/globals": "^29.2.0",
|
||||
"@playwright/test": "^1.27.1",
|
||||
"husky": "^8.0.3",
|
||||
"jest": "^29.2.0",
|
||||
"pretty-quick": "^3.1.3",
|
||||
"randomstring": "^1.2.2",
|
||||
"ts-jest": "^29.0.5"
|
||||
"ts-jest": "^29.0.5",
|
||||
"fs-extra": "^11.1.1"
|
||||
},
|
||||
"scripts": {
|
||||
"dev:web": "npm run dev --workspace=packages/bruno-app",
|
||||
@@ -28,11 +31,19 @@
|
||||
"dev:electron": "npm run dev --workspace=packages/bruno-electron",
|
||||
"build:bruno-query": "npm run build --workspace=packages/bruno-query",
|
||||
"build:graphql-docs": "npm run build --workspace=packages/bruno-graphql-docs",
|
||||
"build:electron": "./scripts/build-electron.sh",
|
||||
"build:electron": "node ./scripts/build-electron.js",
|
||||
"build:electron:mac": "./scripts/build-electron.sh mac",
|
||||
"build:electron:win": "./scripts/build-electron.sh win",
|
||||
"build:electron:linux": "./scripts/build-electron.sh linux",
|
||||
"build:electron:deb": "./scripts/build-electron.sh deb",
|
||||
"build:electron:rpm": "./scripts/build-electron.sh rpm",
|
||||
"build:electron:snap": "./scripts/build-electron.sh snap",
|
||||
"test:e2e": "npx playwright test",
|
||||
"test:report": "npx playwright show-report"
|
||||
"test:report": "npx playwright show-report",
|
||||
"test:prettier:web": "npm run test:prettier --workspace=packages/bruno-app",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"overrides": {
|
||||
"rollup": "3.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"printWidth": 180
|
||||
"printWidth": 120
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
"version": "0.3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "cross-env ENV=dev next dev",
|
||||
"dev": "cross-env ENV=dev next dev -p 3000",
|
||||
"build": "next build && next export",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"test": "jest",
|
||||
"test:prettier": "prettier --check \"./src/**/*.{js,jsx,json,ts,tsx}\"",
|
||||
"prettier": "prettier --write \"./src/**/*.{js,jsx,json,ts,tsx}\""
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -18,40 +19,59 @@
|
||||
"@tabler/icons": "^1.46.0",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"@usebruno/graphql-docs": "0.1.0",
|
||||
"@usebruno/schema": "0.3.1",
|
||||
"axios": "^0.26.0",
|
||||
"@usebruno/schema": "0.6.0",
|
||||
"axios": "^1.5.1",
|
||||
"classnames": "^2.3.1",
|
||||
"codemirror": "^5.65.2",
|
||||
"codemirror-graphql": "^1.2.5",
|
||||
"cookie": "^0.6.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"file": "^0.2.2",
|
||||
"file-dialog": "^0.0.8",
|
||||
"file-saver": "^2.0.5",
|
||||
"formik": "^2.2.9",
|
||||
"github-markdown-css": "^5.2.0",
|
||||
"graphiql": "^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",
|
||||
"jsonlint": "^1.6.3",
|
||||
"know-your-http-well": "^0.5.0",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-it": "^13.0.1",
|
||||
"markdown-it": "^13.0.2",
|
||||
"mousetrap": "^1.6.5",
|
||||
"nanoid": "3.3.4",
|
||||
"next": "12.3.3",
|
||||
"path": "^0.12.7",
|
||||
"pdfjs-dist": "^3.11.174",
|
||||
"platform": "^1.3.6",
|
||||
"posthog-node": "^2.1.0",
|
||||
"qs": "^6.11.0",
|
||||
"query-string": "^7.0.1",
|
||||
"react": "18.2.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dom": "18.2.0",
|
||||
"react-github-btn": "^1.4.0",
|
||||
"react-hot-toast": "^2.4.0",
|
||||
"react-inspector": "^6.0.2",
|
||||
"react-pdf": "^7.5.1",
|
||||
"react-redux": "^7.2.6",
|
||||
"react-tooltip": "^5.5.2",
|
||||
"sass": "^1.46.0",
|
||||
"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",
|
||||
"yup": "^0.32.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -14,7 +14,11 @@ const Bruno = ({ width }) => {
|
||||
stroke="none"
|
||||
points="36,47.2521 32.9167,49.6688 30.4167,49.6688 30.3333,53.5021 31.0833,57.0021 32.1667,58.9188 35,60.4188 39.5833,59.8355 41.1667,58.0855 42.1667,53.8355 41.9167,49.8355 39.9167,50.0855"
|
||||
/>
|
||||
<polygon fill="#3F3F3F" stroke="none" points="32.5,36.9188 30.9167,40.6688 33.0833,41.9188 34.3333,42.4188 38.6667,42.5855 41.5833,40.3355 39.8333,37.0855" />
|
||||
<polygon
|
||||
fill="#3F3F3F"
|
||||
stroke="none"
|
||||
points="32.5,36.9188 30.9167,40.6688 33.0833,41.9188 34.3333,42.4188 38.6667,42.5855 41.5833,40.3355 39.8333,37.0855"
|
||||
/>
|
||||
</g>
|
||||
<g id="hair" />
|
||||
<g id="skin" />
|
||||
@@ -84,8 +88,27 @@ const Bruno = ({ width }) => {
|
||||
strokeWidth="2"
|
||||
d="M52.6309,46.4628c0,0-3.0781,6.7216-7.8049,8.2712"
|
||||
/>
|
||||
<path fill="none" stroke="#000000" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2" d="M19.437,46.969c0,0,3.0781,6.0823,7.8049,7.632" />
|
||||
<line x1="36.2078" x2="36.2078" y1="47.3393" y2="44.3093" fill="none" stroke="#000000" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2" />
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000000"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit="10"
|
||||
strokeWidth="2"
|
||||
d="M19.437,46.969c0,0,3.0781,6.0823,7.8049,7.632"
|
||||
/>
|
||||
<line
|
||||
x1="36.2078"
|
||||
x2="36.2078"
|
||||
y1="47.3393"
|
||||
y2="44.3093"
|
||||
fill="none"
|
||||
stroke="#000000"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit="10"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -29,7 +29,7 @@ const BrunoSupport = ({ onClose }) => {
|
||||
<div className="mt-2">
|
||||
<a href="https://github.com/usebruno/bruno" target="_blank" className="flex items-end">
|
||||
<IconBrandGithub size={18} strokeWidth={2} />
|
||||
<span className="label ml-2">Github</span>
|
||||
<span className="label ml-2">GitHub</span>
|
||||
</a>
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
|
||||
@@ -4,9 +4,12 @@ const StyledWrapper = styled.div`
|
||||
div.CodeMirror {
|
||||
background: ${(props) => props.theme.codemirror.bg};
|
||||
border: solid 1px ${(props) => props.theme.codemirror.border};
|
||||
font-family: ${(props) => (props.font ? props.font : 'default')};
|
||||
line-break: anywhere;
|
||||
}
|
||||
|
||||
.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {
|
||||
.CodeMirror-overlayscroll-horizontal div,
|
||||
.CodeMirror-overlayscroll-vertical div {
|
||||
background: #d2d7db;
|
||||
}
|
||||
|
||||
@@ -17,12 +20,14 @@ const StyledWrapper = styled.div`
|
||||
// Todo: dark mode temporary fix
|
||||
// Clean this
|
||||
.CodeMirror.cm-s-monokai {
|
||||
.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {
|
||||
.CodeMirror-overlayscroll-horizontal div,
|
||||
.CodeMirror-overlayscroll-vertical div {
|
||||
background: #444444;
|
||||
}
|
||||
}
|
||||
|
||||
.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {
|
||||
.cm-s-monokai span.cm-property,
|
||||
.cm-s-monokai span.cm-attribute {
|
||||
color: #9cdcfe !important;
|
||||
}
|
||||
|
||||
@@ -30,16 +35,20 @@ const StyledWrapper = styled.div`
|
||||
color: #ce9178 !important;
|
||||
}
|
||||
|
||||
.cm-s-monokai span.cm-number{
|
||||
.cm-s-monokai span.cm-number {
|
||||
color: #b5cea8 !important;
|
||||
}
|
||||
|
||||
.cm-s-monokai span.cm-atom{
|
||||
.cm-s-monokai span.cm-atom {
|
||||
color: #569cd6 !important;
|
||||
}
|
||||
|
||||
.cm-variable-valid{color: green}
|
||||
.cm-variable-invalid{color: red}
|
||||
.cm-variable-valid {
|
||||
color: green;
|
||||
}
|
||||
.cm-variable-invalid {
|
||||
color: red;
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
|
||||
@@ -10,12 +10,88 @@ import isEqual from 'lodash/isEqual';
|
||||
import { getEnvironmentVariables } from 'utils/collections';
|
||||
import { defineCodeMirrorBrunoVariablesMode } from 'utils/common/codemirror';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import jsonlint from 'jsonlint';
|
||||
import { JSHINT } from 'jshint';
|
||||
import stripJsonComments from 'strip-json-comments';
|
||||
|
||||
let CodeMirror;
|
||||
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
|
||||
|
||||
if (!SERVER_RENDERED) {
|
||||
CodeMirror = require('codemirror');
|
||||
window.jsonlint = jsonlint;
|
||||
window.JSHINT = JSHINT;
|
||||
//This should be done dynamically if possible
|
||||
const hintWords = [
|
||||
'res',
|
||||
'res.status',
|
||||
'res.statusText',
|
||||
'res.headers',
|
||||
'res.body',
|
||||
'res.responseTime',
|
||||
'res.getStatus()',
|
||||
'res.getHeader(name)',
|
||||
'res.getHeaders()',
|
||||
'res.getBody()',
|
||||
'res.getResponseTime()',
|
||||
'req',
|
||||
'req.url',
|
||||
'req.method',
|
||||
'req.headers',
|
||||
'req.body',
|
||||
'req.timeout',
|
||||
'req.getUrl()',
|
||||
'req.setUrl(url)',
|
||||
'req.getMethod()',
|
||||
'req.setMethod(method)',
|
||||
'req.getHeader(name)',
|
||||
'req.getHeaders()',
|
||||
'req.setHeader(name, value)',
|
||||
'req.setHeaders(data)',
|
||||
'req.getBody()',
|
||||
'req.setBody(data)',
|
||||
'req.setMaxRedirects(maxRedirects)',
|
||||
'req.getTimeout()',
|
||||
'req.setTimeout(timeout)',
|
||||
'bru',
|
||||
'bru.cwd()',
|
||||
'bru.getEnvName(key)',
|
||||
'bru.getProcessEnv(key)',
|
||||
'bru.getEnvVar(key)',
|
||||
'bru.setEnvVar(key,value)',
|
||||
'bru.getVar(key)',
|
||||
'bru.setVar(key,value)'
|
||||
];
|
||||
CodeMirror.registerHelper('hint', 'brunoJS', (editor, options) => {
|
||||
const cursor = editor.getCursor();
|
||||
const currentLine = editor.getLine(cursor.line);
|
||||
let startBru = cursor.ch;
|
||||
let endBru = startBru;
|
||||
while (endBru < currentLine.length && /[\w.]/.test(currentLine.charAt(endBru))) ++endBru;
|
||||
while (startBru && /[\w.]/.test(currentLine.charAt(startBru - 1))) --startBru;
|
||||
let curWordBru = startBru != endBru && currentLine.slice(startBru, endBru);
|
||||
|
||||
let start = cursor.ch;
|
||||
let end = start;
|
||||
while (end < currentLine.length && /[\w]/.test(currentLine.charAt(end))) ++end;
|
||||
while (start && /[\w]/.test(currentLine.charAt(start - 1))) --start;
|
||||
const jsHinter = CodeMirror.hint.javascript;
|
||||
let result = jsHinter(editor) || { list: [] };
|
||||
result.to = CodeMirror.Pos(cursor.line, end);
|
||||
result.from = CodeMirror.Pos(cursor.line, start);
|
||||
if (curWordBru) {
|
||||
hintWords.forEach((h) => {
|
||||
if (h.includes('.') == curWordBru.includes('.') && h.startsWith(curWordBru)) {
|
||||
result.list.push(curWordBru.includes('.') ? h.split('.')[1] : h);
|
||||
}
|
||||
});
|
||||
result.list?.sort();
|
||||
}
|
||||
return result;
|
||||
});
|
||||
CodeMirror.commands.autocomplete = (cm, hint, options) => {
|
||||
cm.showHint({ hint, ...options });
|
||||
};
|
||||
}
|
||||
|
||||
export default class CodeEditor extends React.Component {
|
||||
@@ -41,9 +117,10 @@ export default class CodeEditor extends React.Component {
|
||||
matchBrackets: true,
|
||||
showCursorWhenSelecting: true,
|
||||
foldGutter: true,
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'],
|
||||
lint: { esversion: 11 },
|
||||
readOnly: this.props.readOnly,
|
||||
scrollbarStyle: "overlay",
|
||||
scrollbarStyle: 'overlay',
|
||||
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
|
||||
extraKeys: {
|
||||
'Cmd-Enter': () => {
|
||||
@@ -68,19 +145,98 @@ export default class CodeEditor extends React.Component {
|
||||
},
|
||||
'Cmd-F': 'findPersistent',
|
||||
'Ctrl-F': 'findPersistent',
|
||||
'Cmd-H': 'replace',
|
||||
'Ctrl-H': 'replace',
|
||||
Tab: function (cm) {
|
||||
cm.replaceSelection(' ', 'end');
|
||||
cm.getSelection().includes('\n') || editor.getLine(cm.getCursor().line) == cm.getSelection()
|
||||
? cm.execCommand('indentMore')
|
||||
: cm.replaceSelection(' ', 'end');
|
||||
},
|
||||
'Shift-Tab': 'indentLess',
|
||||
'Ctrl-Space': 'autocomplete',
|
||||
'Cmd-Space': 'autocomplete',
|
||||
'Ctrl-Y': 'foldAll',
|
||||
'Cmd-Y': 'foldAll',
|
||||
'Ctrl-I': 'unfoldAll',
|
||||
'Cmd-I': 'unfoldAll'
|
||||
},
|
||||
foldOptions: {
|
||||
widget: (from, to) => {
|
||||
var count = undefined;
|
||||
var internal = this.editor.getRange(from, to);
|
||||
if (this.props.mode == 'application/ld+json') {
|
||||
if (this.editor.getLine(from.line).endsWith('[')) {
|
||||
var toParse = '[' + internal + ']';
|
||||
} else var toParse = '{' + internal + '}';
|
||||
try {
|
||||
count = Object.keys(JSON.parse(toParse)).length;
|
||||
} catch (e) {}
|
||||
} else if (this.props.mode == 'application/xml') {
|
||||
var doc = new DOMParser();
|
||||
try {
|
||||
//add header element and remove prefix namespaces for DOMParser
|
||||
var dcm = doc.parseFromString(
|
||||
'<a> ' + internal.replace(/(?<=\<|<\/)\w+:/g, '') + '</a>',
|
||||
'application/xml'
|
||||
);
|
||||
count = dcm.documentElement.children.length;
|
||||
} catch (e) {}
|
||||
}
|
||||
return count ? `\u21A4${count}\u21A6` : '\u2194';
|
||||
}
|
||||
}
|
||||
}));
|
||||
CodeMirror.registerHelper('lint', 'json', function (text) {
|
||||
let found = [];
|
||||
if (!window.jsonlint) {
|
||||
if (window.console) {
|
||||
window.console.error('Error: window.jsonlint not defined, CodeMirror JSON linting cannot run.');
|
||||
}
|
||||
return found;
|
||||
}
|
||||
let jsonlint = window.jsonlint.parser || window.jsonlint;
|
||||
jsonlint.parseError = function (str, hash) {
|
||||
let loc = hash.loc;
|
||||
found.push({
|
||||
from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),
|
||||
to: CodeMirror.Pos(loc.last_line - 1, loc.last_column),
|
||||
message: str
|
||||
});
|
||||
};
|
||||
try {
|
||||
jsonlint.parse(stripJsonComments(text.replace(/(?<!"[^":{]*){{[^}]*}}(?![^"},]*")/g, '1')));
|
||||
} catch (e) {}
|
||||
return found;
|
||||
});
|
||||
if (editor) {
|
||||
editor.setOption('lint', this.props.mode && editor.getValue().trim().length > 0 ? { esversion: 11 } : false);
|
||||
editor.on('change', this._onEdit);
|
||||
this.addOverlay();
|
||||
}
|
||||
if (this.props.mode == 'javascript') {
|
||||
editor.on('keyup', function (cm, event) {
|
||||
const cursor = editor.getCursor();
|
||||
const currentLine = editor.getLine(cursor.line);
|
||||
let start = cursor.ch;
|
||||
let end = start;
|
||||
while (end < currentLine.length && /[^{}();\s\[\]\,]/.test(currentLine.charAt(end))) ++end;
|
||||
while (start && /[^{}();\s\[\]\,]/.test(currentLine.charAt(start - 1))) --start;
|
||||
let curWord = start != end && currentLine.slice(start, end);
|
||||
//Qualify if autocomplete will be shown
|
||||
if (
|
||||
/^(?!Shift|Tab|Enter|ArrowUp|ArrowDown|ArrowLeft|ArrowRight|\s)\w*/.test(event.key) &&
|
||||
curWord.length > 0 &&
|
||||
!/\/\/|\/\*|.*{{|`[^$]*{|`[^{]*$/.test(currentLine.slice(0, end)) &&
|
||||
/(?<!\d)[a-zA-Z\._]$/.test(curWord)
|
||||
) {
|
||||
CodeMirror.commands.autocomplete(cm, CodeMirror.hint.brunoJS, { completeSingle: false });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
// Ensure the changes caused by this update are not interpretted as
|
||||
// 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;
|
||||
@@ -96,7 +252,7 @@ export default class CodeEditor extends React.Component {
|
||||
this.editor.setValue(this.props.value);
|
||||
}
|
||||
|
||||
if(this.editor) {
|
||||
if (this.editor) {
|
||||
let variables = getEnvironmentVariables(this.props.collection);
|
||||
if (!isEqual(variables, this.variables)) {
|
||||
this.addOverlay();
|
||||
@@ -117,10 +273,14 @@ export default class CodeEditor extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.editor) {
|
||||
this.editor.refresh();
|
||||
}
|
||||
return (
|
||||
<StyledWrapper
|
||||
className="h-full"
|
||||
className="h-full w-full"
|
||||
aria-label="Code Editor"
|
||||
font={this.props.font}
|
||||
ref={(node) => {
|
||||
this._node = node;
|
||||
}}
|
||||
@@ -135,10 +295,11 @@ export default class CodeEditor extends React.Component {
|
||||
|
||||
defineCodeMirrorBrunoVariablesMode(variables, mode);
|
||||
this.editor.setOption('mode', 'brunovariables');
|
||||
}
|
||||
};
|
||||
|
||||
_onEdit = () => {
|
||||
if (!this.ignoreChangeEvent && this.editor) {
|
||||
this.editor.setOption('lint', this.editor.getValue().trim().length > 0 ? { esversion: 11 } : false);
|
||||
this.cachedValue = this.editor.getValue();
|
||||
if (this.props.onEdit) {
|
||||
this.props.onEdit(this.cachedValue);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
font-size: 0.8125rem;
|
||||
|
||||
.auth-mode-selector {
|
||||
background: transparent;
|
||||
|
||||
.auth-mode-label {
|
||||
color: ${(props) => props.theme.colors.text.yellow};
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
@@ -0,0 +1,87 @@
|
||||
import React, { useRef, forwardRef } from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { IconCaretDown } from '@tabler/icons';
|
||||
import Dropdown from 'components/Dropdown';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { updateCollectionAuthMode } from 'providers/ReduxStore/slices/collections';
|
||||
import { humanizeRequestAuthMode } from 'utils/collections';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const AuthMode = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const dropdownTippyRef = useRef();
|
||||
const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
|
||||
const authMode = get(collection, 'root.request.auth.mode');
|
||||
|
||||
const Icon = forwardRef((props, ref) => {
|
||||
return (
|
||||
<div ref={ref} className="flex items-center justify-center auth-mode-label select-none">
|
||||
{humanizeRequestAuthMode(authMode)} <IconCaretDown className="caret ml-1 mr-1" size={14} strokeWidth={2} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const onModeChange = (value) => {
|
||||
dispatch(
|
||||
updateCollectionAuthMode({
|
||||
collectionUid: collection.uid,
|
||||
mode: value
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<div className="inline-flex items-center cursor-pointer auth-mode-selector">
|
||||
<Dropdown onCreate={onDropdownCreate} icon={<Icon />} placement="bottom-end">
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
dropdownTippyRef.current.hide();
|
||||
onModeChange('awsv4');
|
||||
}}
|
||||
>
|
||||
AWS Sig v4
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
dropdownTippyRef.current.hide();
|
||||
onModeChange('basic');
|
||||
}}
|
||||
>
|
||||
Basic Auth
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
dropdownTippyRef.current.hide();
|
||||
onModeChange('bearer');
|
||||
}}
|
||||
>
|
||||
Bearer Token
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
dropdownTippyRef.current.hide();
|
||||
onModeChange('digest');
|
||||
}}
|
||||
>
|
||||
Digest Auth
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item"
|
||||
onClick={() => {
|
||||
dropdownTippyRef.current.hide();
|
||||
onModeChange('none');
|
||||
}}
|
||||
>
|
||||
No Auth
|
||||
</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
export default AuthMode;
|
||||
@@ -0,0 +1,16 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.single-line-editor-wrapper {
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
border: solid 1px ${(props) => props.theme.input.border};
|
||||
background-color: ${(props) => props.theme.input.bg};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
@@ -0,0 +1,191 @@
|
||||
import React from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { useTheme } from 'providers/Theme';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import SingleLineEditor from 'components/SingleLineEditor';
|
||||
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const AwsV4Auth = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
|
||||
const awsv4Auth = get(collection, 'root.request.auth.awsv4', {});
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
const handleAccessKeyIdChange = (accessKeyId) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'awsv4',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
accessKeyId: accessKeyId,
|
||||
secretAccessKey: awsv4Auth.secretAccessKey,
|
||||
sessionToken: awsv4Auth.sessionToken,
|
||||
service: awsv4Auth.service,
|
||||
region: awsv4Auth.region,
|
||||
profileName: awsv4Auth.profileName
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleSecretAccessKeyChange = (secretAccessKey) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'awsv4',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
accessKeyId: awsv4Auth.accessKeyId,
|
||||
secretAccessKey: secretAccessKey,
|
||||
sessionToken: awsv4Auth.sessionToken,
|
||||
service: awsv4Auth.service,
|
||||
region: awsv4Auth.region,
|
||||
profileName: awsv4Auth.profileName
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleSessionTokenChange = (sessionToken) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'awsv4',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
accessKeyId: awsv4Auth.accessKeyId,
|
||||
secretAccessKey: awsv4Auth.secretAccessKey,
|
||||
sessionToken: sessionToken,
|
||||
service: awsv4Auth.service,
|
||||
region: awsv4Auth.region,
|
||||
profileName: awsv4Auth.profileName
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleServiceChange = (service) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'awsv4',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
accessKeyId: awsv4Auth.accessKeyId,
|
||||
secretAccessKey: awsv4Auth.secretAccessKey,
|
||||
sessionToken: awsv4Auth.sessionToken,
|
||||
service: service,
|
||||
region: awsv4Auth.region,
|
||||
profileName: awsv4Auth.profileName
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleRegionChange = (region) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'awsv4',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
accessKeyId: awsv4Auth.accessKeyId,
|
||||
secretAccessKey: awsv4Auth.secretAccessKey,
|
||||
sessionToken: awsv4Auth.sessionToken,
|
||||
service: awsv4Auth.service,
|
||||
region: region,
|
||||
profileName: awsv4Auth.profileName
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleProfileNameChange = (profileName) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'awsv4',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
accessKeyId: awsv4Auth.accessKeyId,
|
||||
secretAccessKey: awsv4Auth.secretAccessKey,
|
||||
sessionToken: awsv4Auth.sessionToken,
|
||||
service: awsv4Auth.service,
|
||||
region: awsv4Auth.region,
|
||||
profileName: profileName
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="mt-2 w-full">
|
||||
<label className="block font-medium mb-2">Access Key ID</label>
|
||||
<div className="single-line-editor-wrapper mb-2">
|
||||
<SingleLineEditor
|
||||
value={awsv4Auth.accessKeyId || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleAccessKeyIdChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="block font-medium mb-2">Secret Access Key</label>
|
||||
<div className="single-line-editor-wrapper mb-2">
|
||||
<SingleLineEditor
|
||||
value={awsv4Auth.secretAccessKey || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleSecretAccessKeyChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="block font-medium mb-2">Session Token</label>
|
||||
<div className="single-line-editor-wrapper mb-2">
|
||||
<SingleLineEditor
|
||||
value={awsv4Auth.sessionToken || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleSessionTokenChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="block font-medium mb-2">Service</label>
|
||||
<div className="single-line-editor-wrapper mb-2">
|
||||
<SingleLineEditor
|
||||
value={awsv4Auth.service || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleServiceChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="block font-medium mb-2">Region</label>
|
||||
<div className="single-line-editor-wrapper mb-2">
|
||||
<SingleLineEditor
|
||||
value={awsv4Auth.region || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleRegionChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="block font-medium mb-2">Profile Name</label>
|
||||
<div className="single-line-editor-wrapper mb-2">
|
||||
<SingleLineEditor
|
||||
value={awsv4Auth.profileName || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleProfileNameChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default AwsV4Auth;
|
||||
@@ -0,0 +1,16 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.single-line-editor-wrapper {
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
border: solid 1px ${(props) => props.theme.input.border};
|
||||
background-color: ${(props) => props.theme.input.bg};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
@@ -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 { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const BasicAuth = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
|
||||
const basicAuth = get(collection, 'root.request.auth.basic', {});
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
const handleUsernameChange = (username) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'basic',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
username: username,
|
||||
password: basicAuth.password
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handlePasswordChange = (password) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'basic',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
username: basicAuth.username,
|
||||
password: password
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="mt-2 w-full">
|
||||
<label className="block font-medium mb-2">Username</label>
|
||||
<div className="single-line-editor-wrapper mb-2">
|
||||
<SingleLineEditor
|
||||
value={basicAuth.username || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleUsernameChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="block font-medium mb-2">Password</label>
|
||||
<div className="single-line-editor-wrapper">
|
||||
<SingleLineEditor
|
||||
value={basicAuth.password || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handlePasswordChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default BasicAuth;
|
||||
@@ -0,0 +1,16 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.single-line-editor-wrapper {
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
border: solid 1px ${(props) => props.theme.input.border};
|
||||
background-color: ${(props) => props.theme.input.bg};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { useTheme } from 'providers/Theme';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import SingleLineEditor from 'components/SingleLineEditor';
|
||||
import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const BearerAuth = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
|
||||
const bearerToken = get(collection, 'root.request.auth.bearer.token');
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
const handleTokenChange = (token) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'bearer',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
token: token
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="mt-2 w-full">
|
||||
<label className="block font-medium mb-2">Token</label>
|
||||
<div className="single-line-editor-wrapper">
|
||||
<SingleLineEditor
|
||||
value={bearerToken}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleTokenChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default BearerAuth;
|
||||
@@ -0,0 +1,16 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
label {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.single-line-editor-wrapper {
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
border: solid 1px ${(props) => props.theme.input.border};
|
||||
background-color: ${(props) => props.theme.input.bg};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
@@ -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 { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const DigestAuth = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
|
||||
const digestAuth = get(collection, 'root.request.auth.digest', {});
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
const handleUsernameChange = (username) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'digest',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
username: username,
|
||||
password: digestAuth.password
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handlePasswordChange = (password) => {
|
||||
dispatch(
|
||||
updateCollectionAuth({
|
||||
mode: 'digest',
|
||||
collectionUid: collection.uid,
|
||||
content: {
|
||||
username: digestAuth.username,
|
||||
password: password
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="mt-2 w-full">
|
||||
<label className="block font-medium mb-2">Username</label>
|
||||
<div className="single-line-editor-wrapper mb-2">
|
||||
<SingleLineEditor
|
||||
value={digestAuth.username || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handleUsernameChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="block font-medium mb-2">Password</label>
|
||||
<div className="single-line-editor-wrapper">
|
||||
<SingleLineEditor
|
||||
value={digestAuth.password || ''}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(val) => handlePasswordChange(val)}
|
||||
collection={collection}
|
||||
/>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default DigestAuth;
|
||||
@@ -0,0 +1,5 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div``;
|
||||
|
||||
export default Wrapper;
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import AuthMode from './AuthMode';
|
||||
import AwsV4Auth from './AwsV4Auth';
|
||||
import BearerAuth from './BearerAuth';
|
||||
import BasicAuth from './BasicAuth';
|
||||
import DigestAuth from './DigestAuth';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const Auth = ({ collection }) => {
|
||||
const authMode = get(collection, 'root.request.auth.mode');
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
const getAuthView = () => {
|
||||
switch (authMode) {
|
||||
case 'awsv4': {
|
||||
return <AwsV4Auth collection={collection} />;
|
||||
}
|
||||
case 'basic': {
|
||||
return <BasicAuth collection={collection} />;
|
||||
}
|
||||
case 'bearer': {
|
||||
return <BearerAuth collection={collection} />;
|
||||
}
|
||||
case 'digest': {
|
||||
return <DigestAuth collection={collection} />;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="w-full mt-2">
|
||||
<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
|
||||
</button>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
export default Auth;
|
||||
@@ -0,0 +1,43 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
.settings-label {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.certificate-icon {
|
||||
color: ${(props) => props.theme.colors.text.yellow};
|
||||
}
|
||||
|
||||
input {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.available-certificates {
|
||||
background-color: ${(props) => props.theme.requestTabPanel.url.bg};
|
||||
|
||||
button.remove-certificate {
|
||||
color: ${(props) => props.theme.colors.text.danger};
|
||||
}
|
||||
}
|
||||
|
||||
.textbox {
|
||||
border: 1px solid #ccc;
|
||||
padding: 0.15rem 0.45rem;
|
||||
box-shadow: none;
|
||||
border-radius: 0px;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
transition: border-color ease-in-out 0.1s;
|
||||
border-radius: 3px;
|
||||
background-color: ${(props) => props.theme.modal.input.bg};
|
||||
border: 1px solid ${(props) => props.theme.modal.input.border};
|
||||
|
||||
&:focus {
|
||||
border: solid 1px ${(props) => props.theme.modal.input.focusBorder} !important;
|
||||
outline: none !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
@@ -0,0 +1,130 @@
|
||||
import React from 'react';
|
||||
import { IconCertificate, IconTrash, IconWorld } from '@tabler/icons';
|
||||
import { useFormik } from 'formik';
|
||||
import { uuid } from 'utils/common';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const ClientCertSettings = ({ clientCertConfig, onUpdate, onRemove }) => {
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
domain: '',
|
||||
certFilePath: '',
|
||||
keyFilePath: '',
|
||||
passphrase: ''
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
domain: Yup.string().required(),
|
||||
certFilePath: Yup.string().required(),
|
||||
keyFilePath: Yup.string().required(),
|
||||
passphrase: Yup.string()
|
||||
}),
|
||||
onSubmit: (values) => {
|
||||
onUpdate(values);
|
||||
}
|
||||
});
|
||||
|
||||
const getFile = (e) => {
|
||||
formik.values[e.name] = e.files[0].path;
|
||||
};
|
||||
|
||||
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>
|
||||
<ul className="mt-4">
|
||||
{!clientCertConfig.length
|
||||
? 'None'
|
||||
: clientCertConfig.map((clientCert) => (
|
||||
<li key={uuid()} className="flex items-center available-certificates p-2 rounded-lg mb-2">
|
||||
<div className="flex items-center w-full justify-between">
|
||||
<div className="flex items-center">
|
||||
<IconWorld className="mr-2" size={18} strokeWidth={1.5} />
|
||||
{clientCert.domain}
|
||||
</div>
|
||||
<button onClick={() => onRemove(clientCert)} className="remove-certificate ml-2">
|
||||
<IconTrash size={18} strokeWidth={1.5} />
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<h1 className="font-semibold mt-8 mb-2">Add Client Certicate</h1>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label" htmlFor="domain">
|
||||
Domain
|
||||
</label>
|
||||
<input
|
||||
id="domain"
|
||||
type="text"
|
||||
name="domain"
|
||||
placeholder="*.example.org"
|
||||
className="block textbox"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.domain || ''}
|
||||
/>
|
||||
{formik.touched.domain && formik.errors.domain ? (
|
||||
<div className="ml-1 text-red-500">{formik.errors.domain}</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label" htmlFor="certFilePath">
|
||||
Cert file
|
||||
</label>
|
||||
<input
|
||||
id="certFilePath"
|
||||
type="file"
|
||||
name="certFilePath"
|
||||
className="block"
|
||||
onChange={(e) => getFile(e.target)}
|
||||
/>
|
||||
{formik.touched.certFilePath && formik.errors.certFilePath ? (
|
||||
<div className="ml-1 text-red-500">{formik.errors.certFilePath}</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label" htmlFor="keyFilePath">
|
||||
Key file
|
||||
</label>
|
||||
<input
|
||||
id="keyFilePath"
|
||||
type="file"
|
||||
name="keyFilePath"
|
||||
className="block"
|
||||
onChange={(e) => getFile(e.target)}
|
||||
/>
|
||||
{formik.touched.keyFilePath && formik.errors.keyFilePath ? (
|
||||
<div className="ml-1 text-red-500">{formik.errors.keyFilePath}</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mb-3 flex items-center">
|
||||
<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 || ''}
|
||||
/>
|
||||
{formik.touched.passphrase && formik.errors.passphrase ? (
|
||||
<div className="ml-1 text-red-500">{formik.errors.passphrase}</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<button type="submit" className="submit btn btn-sm btn-secondary">
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ClientCertSettings;
|
||||
@@ -0,0 +1,18 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
div.CodeMirror {
|
||||
/* todo: find a better way */
|
||||
height: calc(100vh - 240px);
|
||||
|
||||
.CodeMirror-scroll {
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
}
|
||||
.editing-mode {
|
||||
cursor: pointer;
|
||||
color: ${(props) => props.theme.colors.text.yellow};
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
@@ -0,0 +1,55 @@
|
||||
import 'github-markdown-css/github-markdown.css';
|
||||
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 { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import Markdown from 'components/MarkDown';
|
||||
import CodeEditor from 'components/CodeEditor';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const Docs = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const docs = get(collection, 'root.docs', '');
|
||||
|
||||
const toggleViewMode = () => {
|
||||
setIsEditing((prev) => !prev);
|
||||
};
|
||||
|
||||
const onEdit = (value) => {
|
||||
dispatch(
|
||||
updateCollectionDocs({
|
||||
collectionUid: collection.uid,
|
||||
docs: value
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const onSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
return (
|
||||
<StyledWrapper className="mt-1 h-full w-full relative">
|
||||
<div className="editing-mode mb-2" role="tab" onClick={toggleViewMode}>
|
||||
{isEditing ? 'Preview' : 'Edit'}
|
||||
</div>
|
||||
|
||||
{isEditing ? (
|
||||
<CodeEditor
|
||||
collection={collection}
|
||||
theme={storedTheme}
|
||||
value={docs || ''}
|
||||
onEdit={onEdit}
|
||||
onSave={onSave}
|
||||
mode="application/text"
|
||||
/>
|
||||
) : (
|
||||
<Markdown onDoubleClick={toggleViewMode} content={docs} />
|
||||
)}
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Docs;
|
||||
@@ -0,0 +1,56 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-weight: 600;
|
||||
table-layout: fixed;
|
||||
|
||||
thead,
|
||||
td {
|
||||
border: 1px solid ${(props) => props.theme.table.border};
|
||||
}
|
||||
|
||||
thead {
|
||||
color: ${(props) => props.theme.table.thead.color};
|
||||
font-size: 0.8125rem;
|
||||
user-select: none;
|
||||
}
|
||||
td {
|
||||
padding: 6px 10px;
|
||||
|
||||
&:nth-child(1) {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
width: 70px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-add-header {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
input[type='text'] {
|
||||
width: 100%;
|
||||
border: solid 1px transparent;
|
||||
outline: none !important;
|
||||
background-color: inherit;
|
||||
|
||||
&:focus {
|
||||
outline: none !important;
|
||||
border: solid 1px transparent;
|
||||
}
|
||||
}
|
||||
|
||||
input[type='checkbox'] {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
@@ -0,0 +1,151 @@
|
||||
import React from 'react';
|
||||
import get from 'lodash/get';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { IconTrash } from '@tabler/icons';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useTheme } from 'providers/Theme';
|
||||
import {
|
||||
addCollectionHeader,
|
||||
updateCollectionHeader,
|
||||
deleteCollectionHeader
|
||||
} from 'providers/ReduxStore/slices/collections';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import SingleLineEditor from 'components/SingleLineEditor';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { headers as StandardHTTPHeaders } from 'know-your-http-well';
|
||||
const headerAutoCompleteList = StandardHTTPHeaders.map((e) => e.header);
|
||||
|
||||
const Headers = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
const headers = get(collection, 'root.request.headers', []);
|
||||
|
||||
const addHeader = () => {
|
||||
dispatch(
|
||||
addCollectionHeader({
|
||||
collectionUid: collection.uid
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
const handleHeaderValueChange = (e, _header, type) => {
|
||||
const header = cloneDeep(_header);
|
||||
switch (type) {
|
||||
case 'name': {
|
||||
header.name = e.target.value;
|
||||
break;
|
||||
}
|
||||
case 'value': {
|
||||
header.value = e.target.value;
|
||||
break;
|
||||
}
|
||||
case 'enabled': {
|
||||
header.enabled = e.target.checked;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dispatch(
|
||||
updateCollectionHeader({
|
||||
header: header,
|
||||
collectionUid: collection.uid
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleRemoveHeader = (header) => {
|
||||
dispatch(
|
||||
deleteCollectionHeader({
|
||||
headerUid: header.uid,
|
||||
collectionUid: collection.uid
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="w-full">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>Value</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{headers && headers.length
|
||||
? headers.map((header) => {
|
||||
return (
|
||||
<tr key={header.uid}>
|
||||
<td>
|
||||
<SingleLineEditor
|
||||
value={header.name}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(newValue) =>
|
||||
handleHeaderValueChange(
|
||||
{
|
||||
target: {
|
||||
value: newValue
|
||||
}
|
||||
},
|
||||
header,
|
||||
'name'
|
||||
)
|
||||
}
|
||||
autocomplete={headerAutoCompleteList}
|
||||
collection={collection}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<SingleLineEditor
|
||||
value={header.value}
|
||||
theme={storedTheme}
|
||||
onSave={handleSave}
|
||||
onChange={(newValue) =>
|
||||
handleHeaderValueChange(
|
||||
{
|
||||
target: {
|
||||
value: newValue
|
||||
}
|
||||
},
|
||||
header,
|
||||
'value'
|
||||
)
|
||||
}
|
||||
collection={collection}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={header.enabled}
|
||||
tabIndex="-1"
|
||||
className="mr-3 mousetrap"
|
||||
onChange={(e) => handleHeaderValueChange(e, header, 'enabled')}
|
||||
/>
|
||||
<button tabIndex="-1" onClick={() => handleRemoveHeader(header)}>
|
||||
<IconTrash strokeWidth={1.5} size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
</tbody>
|
||||
</table>
|
||||
<button className="btn-add-header text-link pr-2 py-3 mt-2 select-none" onClick={addHeader}>
|
||||
+ Add Header
|
||||
</button>
|
||||
|
||||
<div className="mt-6">
|
||||
<button type="submit" className="submit btn btn-sm btn-secondary" onClick={handleSave}>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
export default Headers;
|
||||
@@ -0,0 +1,13 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
table {
|
||||
td {
|
||||
&:first-child {
|
||||
width: 120px;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
function countRequests(items) {
|
||||
let count = 0;
|
||||
|
||||
function recurse(item) {
|
||||
if (item && typeof item === 'object') {
|
||||
if (item.type !== 'folder') {
|
||||
count++;
|
||||
}
|
||||
if (Array.isArray(item.items)) {
|
||||
item.items.forEach(recurse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items.forEach(recurse);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
const Info = ({ collection }) => {
|
||||
return (
|
||||
<StyledWrapper className="w-full flex flex-col h-full">
|
||||
<table className="w-full border-collapse">
|
||||
<tbody>
|
||||
<tr className="">
|
||||
<td className="py-2 px-2 text-right">Name :</td>
|
||||
<td className="py-2 px-2">{collection.name}</td>
|
||||
</tr>
|
||||
<tr className="">
|
||||
<td className="py-2 px-2 text-right">Location :</td>
|
||||
<td className="py-2 px-2 break-all">{collection.pathname}</td>
|
||||
</tr>
|
||||
<tr className="">
|
||||
<td className="py-2 px-2 text-right">Environments :</td>
|
||||
<td className="py-2 px-2">{collection.environments?.length || 0}</td>
|
||||
</tr>
|
||||
<tr className="">
|
||||
<td className="py-2 px-2 text-right">Requests :</td>
|
||||
<td className="py-2 px-2">{countRequests(collection.items)}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Info;
|
||||
@@ -0,0 +1,27 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
.settings-label {
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.textbox {
|
||||
border: 1px solid #ccc;
|
||||
padding: 0.15rem 0.45rem;
|
||||
box-shadow: none;
|
||||
border-radius: 0px;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
transition: border-color ease-in-out 0.1s;
|
||||
border-radius: 3px;
|
||||
background-color: ${(props) => props.theme.modal.input.bg};
|
||||
border: 1px solid ${(props) => props.theme.modal.input.border};
|
||||
|
||||
&:focus {
|
||||
border: solid 1px ${(props) => props.theme.modal.input.focusBorder} !important;
|
||||
outline: none !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
@@ -0,0 +1,96 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useFormik } from 'formik';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import toast from 'react-hot-toast';
|
||||
import { updateBrunoConfig } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
|
||||
const PresetsSettings = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
brunoConfig: { presets: presets = {} }
|
||||
} = collection;
|
||||
|
||||
const formik = useFormik({
|
||||
enableReinitialize: true,
|
||||
initialValues: {
|
||||
requestType: presets.requestType || 'http',
|
||||
requestUrl: presets.requestUrl || ''
|
||||
},
|
||||
onSubmit: (newPresets) => {
|
||||
const brunoConfig = cloneDeep(collection.brunoConfig);
|
||||
brunoConfig.presets = newPresets;
|
||||
dispatch(updateBrunoConfig(brunoConfig, collection.uid));
|
||||
toast.success('Collection presets updated');
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<h1 className="font-medium mb-3">Collection Presets</h1>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label flex items-center" htmlFor="enabled">
|
||||
Request Type
|
||||
</label>
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
id="http"
|
||||
className="cursor-pointer"
|
||||
type="radio"
|
||||
name="requestType"
|
||||
onChange={formik.handleChange}
|
||||
value="http"
|
||||
checked={formik.values.requestType === 'http'}
|
||||
/>
|
||||
<label htmlFor="http" className="ml-1 cursor-pointer select-none">
|
||||
HTTP
|
||||
</label>
|
||||
|
||||
<input
|
||||
id="graphql"
|
||||
className="ml-4 cursor-pointer"
|
||||
type="radio"
|
||||
name="requestType"
|
||||
onChange={formik.handleChange}
|
||||
value="graphql"
|
||||
checked={formik.values.requestType === 'graphql'}
|
||||
/>
|
||||
<label htmlFor="graphql" className="ml-1 cursor-pointer select-none">
|
||||
GraphQL
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label" htmlFor="requestUrl">
|
||||
Base URL
|
||||
</label>
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center flex-grow input-container h-full">
|
||||
<input
|
||||
id="request-url"
|
||||
type="text"
|
||||
name="requestUrl"
|
||||
className="block textbox"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.requestUrl || ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<button type="submit" className="submit btn btn-sm btn-secondary">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default PresetsSettings;
|
||||
@@ -0,0 +1,27 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
.settings-label {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.textbox {
|
||||
border: 1px solid #ccc;
|
||||
padding: 0.15rem 0.45rem;
|
||||
box-shadow: none;
|
||||
border-radius: 0px;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
transition: border-color ease-in-out 0.1s;
|
||||
border-radius: 3px;
|
||||
background-color: ${(props) => props.theme.modal.input.bg};
|
||||
border: 1px solid ${(props) => props.theme.modal.input.border};
|
||||
|
||||
&:focus {
|
||||
border: solid 1px ${(props) => props.theme.modal.input.focusBorder} !important;
|
||||
outline: none !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
@@ -0,0 +1,327 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useFormik } from 'formik';
|
||||
import Tooltip from 'components/Tooltip';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import * as Yup from 'yup';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
const ProxySettings = ({ proxyConfig, onUpdate }) => {
|
||||
const proxySchema = Yup.object({
|
||||
enabled: Yup.string().oneOf(['global', 'true', 'false']),
|
||||
protocol: Yup.string().oneOf(['http', 'https', 'socks4', 'socks5']),
|
||||
hostname: Yup.string()
|
||||
.when('enabled', {
|
||||
is: 'true',
|
||||
then: (hostname) => hostname.required('Specify the hostname for your proxy.'),
|
||||
otherwise: (hostname) => hostname.nullable()
|
||||
})
|
||||
.max(1024),
|
||||
port: Yup.number()
|
||||
.min(1)
|
||||
.max(65535)
|
||||
.typeError('Specify port between 1 and 65535')
|
||||
.nullable()
|
||||
.transform((_, val) => (val ? Number(val) : null)),
|
||||
auth: Yup.object()
|
||||
.when('enabled', {
|
||||
is: 'true',
|
||||
then: Yup.object({
|
||||
enabled: Yup.boolean(),
|
||||
username: Yup.string()
|
||||
.when('enabled', {
|
||||
is: true,
|
||||
then: (username) => username.required('Specify username for proxy authentication.')
|
||||
})
|
||||
.max(1024),
|
||||
password: Yup.string()
|
||||
.when('enabled', {
|
||||
is: true,
|
||||
then: (password) => password.required('Specify password for proxy authentication.')
|
||||
})
|
||||
.max(1024)
|
||||
})
|
||||
})
|
||||
.optional(),
|
||||
bypassProxy: Yup.string().optional().max(1024)
|
||||
});
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
enabled: proxyConfig.enabled || 'global',
|
||||
protocol: proxyConfig.protocol || 'http',
|
||||
hostname: proxyConfig.hostname || '',
|
||||
port: proxyConfig.port || '',
|
||||
auth: {
|
||||
enabled: proxyConfig.auth ? proxyConfig.auth.enabled || false : false,
|
||||
username: proxyConfig.auth ? proxyConfig.auth.username || '' : '',
|
||||
password: proxyConfig.auth ? proxyConfig.auth.password || '' : ''
|
||||
},
|
||||
bypassProxy: proxyConfig.bypassProxy || ''
|
||||
},
|
||||
validationSchema: proxySchema,
|
||||
onSubmit: (values) => {
|
||||
proxySchema
|
||||
.validate(values, { abortEarly: true })
|
||||
.then((validatedProxy) => {
|
||||
// serialize 'enabled' to boolean
|
||||
if (validatedProxy.enabled === 'true') {
|
||||
validatedProxy.enabled = true;
|
||||
} else if (validatedProxy.enabled === 'false') {
|
||||
validatedProxy.enabled = false;
|
||||
}
|
||||
|
||||
onUpdate(validatedProxy);
|
||||
})
|
||||
.catch((error) => {
|
||||
let errMsg = error.message || 'Preferences validation error';
|
||||
toast.error(errMsg);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.setValues({
|
||||
enabled: proxyConfig.enabled === true ? 'true' : proxyConfig.enabled === false ? 'false' : 'global',
|
||||
protocol: proxyConfig.protocol || 'http',
|
||||
hostname: proxyConfig.hostname || '',
|
||||
port: proxyConfig.port || '',
|
||||
auth: {
|
||||
enabled: proxyConfig.auth ? proxyConfig.auth.enabled || false : false,
|
||||
username: proxyConfig.auth ? proxyConfig.auth.username || '' : '',
|
||||
password: proxyConfig.auth ? proxyConfig.auth.password || '' : ''
|
||||
},
|
||||
bypassProxy: proxyConfig.bypassProxy || ''
|
||||
});
|
||||
}, [proxyConfig]);
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<h1 className="font-medium mb-3">Proxy Settings</h1>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label flex items-center" htmlFor="enabled">
|
||||
Config
|
||||
<Tooltip
|
||||
text={`
|
||||
<div>
|
||||
<ul>
|
||||
<li><span style="width: 50px;display:inline-block;">global</span> - use global proxy config</li>
|
||||
<li><span style="width: 50px;display:inline-block;">enabled</span> - use collection proxy config</li>
|
||||
<li><span style="width: 50px;display:inline-block;">disable</span> - disable proxy</li>
|
||||
</ul>
|
||||
</div>
|
||||
`}
|
||||
tooltipId="request-var"
|
||||
/>
|
||||
</label>
|
||||
<div className="flex items-center">
|
||||
<label className="flex items-center">
|
||||
<input
|
||||
type="radio"
|
||||
name="enabled"
|
||||
value="global"
|
||||
checked={formik.values.enabled === 'global'}
|
||||
onChange={formik.handleChange}
|
||||
className="mr-1"
|
||||
/>
|
||||
global
|
||||
</label>
|
||||
<label className="flex items-center ml-4">
|
||||
<input
|
||||
type="radio"
|
||||
name="enabled"
|
||||
value={'true'}
|
||||
checked={formik.values.enabled === 'true'}
|
||||
onChange={formik.handleChange}
|
||||
className="mr-1"
|
||||
/>
|
||||
enabled
|
||||
</label>
|
||||
<label className="flex items-center ml-4">
|
||||
<input
|
||||
type="radio"
|
||||
name="enabled"
|
||||
value={'false'}
|
||||
checked={formik.values.enabled === 'false'}
|
||||
onChange={formik.handleChange}
|
||||
className="mr-1"
|
||||
/>
|
||||
disabled
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label" htmlFor="protocol">
|
||||
Protocol
|
||||
</label>
|
||||
<div className="flex items-center">
|
||||
<label className="flex items-center">
|
||||
<input
|
||||
type="radio"
|
||||
name="protocol"
|
||||
value="http"
|
||||
checked={formik.values.protocol === 'http'}
|
||||
onChange={formik.handleChange}
|
||||
className="mr-1"
|
||||
/>
|
||||
http
|
||||
</label>
|
||||
<label className="flex items-center ml-4">
|
||||
<input
|
||||
type="radio"
|
||||
name="protocol"
|
||||
value="https"
|
||||
checked={formik.values.protocol === 'https'}
|
||||
onChange={formik.handleChange}
|
||||
className="mr-1"
|
||||
/>
|
||||
https
|
||||
</label>
|
||||
<label className="flex items-center ml-4">
|
||||
<input
|
||||
type="radio"
|
||||
name="protocol"
|
||||
value="socks5"
|
||||
checked={formik.values.protocol === 'socks4'}
|
||||
onChange={formik.handleChange}
|
||||
className="mr-1"
|
||||
/>
|
||||
socks4
|
||||
</label>
|
||||
<label className="flex items-center ml-4">
|
||||
<input
|
||||
type="radio"
|
||||
name="protocol"
|
||||
value="socks5"
|
||||
checked={formik.values.protocol === 'socks5'}
|
||||
onChange={formik.handleChange}
|
||||
className="mr-1"
|
||||
/>
|
||||
socks5
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label" htmlFor="hostname">
|
||||
Hostname
|
||||
</label>
|
||||
<input
|
||||
id="hostname"
|
||||
type="text"
|
||||
name="hostname"
|
||||
className="block textbox"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.hostname || ''}
|
||||
/>
|
||||
{formik.touched.hostname && formik.errors.hostname ? (
|
||||
<div className="ml-3 text-red-500">{formik.errors.hostname}</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label" htmlFor="port">
|
||||
Port
|
||||
</label>
|
||||
<input
|
||||
id="port"
|
||||
type="number"
|
||||
name="port"
|
||||
className="block textbox"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.port}
|
||||
/>
|
||||
{formik.touched.port && formik.errors.port ? (
|
||||
<div className="ml-3 text-red-500">{formik.errors.port}</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label" htmlFor="auth.enabled">
|
||||
Auth
|
||||
</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="auth.enabled"
|
||||
checked={formik.values.auth.enabled}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label" htmlFor="auth.username">
|
||||
Username
|
||||
</label>
|
||||
<input
|
||||
id="auth.username"
|
||||
type="text"
|
||||
name="auth.username"
|
||||
className="block textbox"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
value={formik.values.auth.username}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
{formik.touched.auth?.username && formik.errors.auth?.username ? (
|
||||
<div className="ml-3 text-red-500">{formik.errors.auth.username}</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mb-3 flex items-center">
|
||||
<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}
|
||||
/>
|
||||
{formik.touched.auth?.password && formik.errors.auth?.password ? (
|
||||
<div className="ml-3 text-red-500">{formik.errors.auth.password}</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-3 flex items-center">
|
||||
<label className="settings-label" htmlFor="bypassProxy">
|
||||
Proxy Bypass
|
||||
</label>
|
||||
<input
|
||||
id="bypassProxy"
|
||||
type="text"
|
||||
name="bypassProxy"
|
||||
className="block textbox"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.bypassProxy || ''}
|
||||
/>
|
||||
{formik.touched.bypassProxy && formik.errors.bypassProxy ? (
|
||||
<div className="ml-3 text-red-500">{formik.errors.bypassProxy}</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<button type="submit" className="submit btn btn-sm btn-secondary">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProxySettings;
|
||||
@@ -0,0 +1,13 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
div.CodeMirror {
|
||||
height: inherit;
|
||||
}
|
||||
|
||||
div.title {
|
||||
color: var(--color-tab-inactive);
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
@@ -0,0 +1,73 @@
|
||||
import React from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import CodeEditor from 'components/CodeEditor';
|
||||
import { updateCollectionRequestScript, updateCollectionResponseScript } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { useTheme } from 'providers/Theme';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const Script = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const requestScript = get(collection, 'root.request.script.req', '');
|
||||
const responseScript = get(collection, 'root.request.script.res', '');
|
||||
|
||||
const { storedTheme } = useTheme();
|
||||
|
||||
const onRequestScriptEdit = (value) => {
|
||||
dispatch(
|
||||
updateCollectionRequestScript({
|
||||
script: value,
|
||||
collectionUid: collection.uid
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const onResponseScriptEdit = (value) => {
|
||||
dispatch(
|
||||
updateCollectionResponseScript({
|
||||
script: value,
|
||||
collectionUid: collection.uid
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
dispatch(saveCollectionRoot(collection.uid));
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="w-full flex flex-col">
|
||||
<div className="flex-1 mt-2">
|
||||
<div className="mb-1 title text-xs">Pre Request</div>
|
||||
<CodeEditor
|
||||
collection={collection}
|
||||
value={requestScript || ''}
|
||||
theme={storedTheme}
|
||||
onEdit={onRequestScriptEdit}
|
||||
mode="javascript"
|
||||
onSave={handleSave}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 mt-6">
|
||||
<div className="mt-1 mb-1 title text-xs">Post Response</div>
|
||||
<CodeEditor
|
||||
collection={collection}
|
||||
value={responseScript || ''}
|
||||
theme={storedTheme}
|
||||
onEdit={onResponseScriptEdit}
|
||||
mode="javascript"
|
||||
onSave={handleSave}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-12">
|
||||
<button type="submit" className="submit btn btn-sm btn-secondary" onClick={handleSave}>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Script;
|
||||
@@ -0,0 +1,46 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
max-width: 800px;
|
||||
|
||||
div.tabs {
|
||||
div.tab {
|
||||
padding: 6px 0px;
|
||||
border: none;
|
||||
border-bottom: solid 2px transparent;
|
||||
margin-right: 1.25rem;
|
||||
color: var(--color-tab-inactive);
|
||||
cursor: pointer;
|
||||
|
||||
&:focus,
|
||||
&:active,
|
||||
&:focus-within,
|
||||
&:focus-visible,
|
||||
&:target {
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: ${(props) => props.theme.tabs.active.color} !important;
|
||||
border-bottom: solid 2px ${(props) => props.theme.tabs.active.border} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
table {
|
||||
thead,
|
||||
td {
|
||||
border: 1px solid ${(props) => props.theme.table.border};
|
||||
|
||||
li {
|
||||
background-color: ${(props) => props.theme.bg} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: ${(props) => props.theme.colors.text.muted};
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
@@ -0,0 +1,5 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div``;
|
||||
|
||||
export default StyledWrapper;
|
||||
@@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import CodeEditor from 'components/CodeEditor';
|
||||
import { updateCollectionTests } from 'providers/ReduxStore/slices/collections';
|
||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { useTheme } from 'providers/Theme';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const Tests = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const tests = get(collection, 'root.request.tests', '');
|
||||
|
||||
const { storedTheme } = useTheme();
|
||||
|
||||
const onEdit = (value) => {
|
||||
dispatch(
|
||||
updateCollectionTests({
|
||||
tests: value,
|
||||
collectionUid: collection.uid
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||
|
||||
return (
|
||||
<StyledWrapper className="w-full flex flex-col h-full">
|
||||
<CodeEditor
|
||||
collection={collection}
|
||||
value={tests || ''}
|
||||
theme={storedTheme}
|
||||
onEdit={onEdit}
|
||||
mode="javascript"
|
||||
onSave={handleSave}
|
||||
/>
|
||||
|
||||
<div className="mt-6">
|
||||
<button type="submit" className="submit btn btn-sm btn-secondary" onClick={handleSave}>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tests;
|
||||
157
packages/bruno-app/src/components/CollectionSettings/index.js
Normal file
157
packages/bruno-app/src/components/CollectionSettings/index.js
Normal file
@@ -0,0 +1,157 @@
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import get from 'lodash/get';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import toast from 'react-hot-toast';
|
||||
import { updateBrunoConfig } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { updateSettingsSelectedTab } from 'providers/ReduxStore/slices/collections';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import ProxySettings from './ProxySettings';
|
||||
import ClientCertSettings from './ClientCertSettings';
|
||||
import Headers from './Headers';
|
||||
import Auth from './Auth';
|
||||
import Script from './Script';
|
||||
import Test from './Tests';
|
||||
import Docs from './Docs';
|
||||
import Presets from './Presets';
|
||||
import Info from './Info';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const CollectionSettings = ({ collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const tab = collection.settingsSelectedTab;
|
||||
const setTab = (tab) => {
|
||||
dispatch(
|
||||
updateSettingsSelectedTab({
|
||||
collectionUid: collection.uid,
|
||||
tab
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const proxyConfig = get(collection, 'brunoConfig.proxy', {});
|
||||
|
||||
const clientCertConfig = get(collection, 'brunoConfig.clientCertificates.certs', []);
|
||||
|
||||
const onProxySettingsUpdate = (config) => {
|
||||
const brunoConfig = cloneDeep(collection.brunoConfig);
|
||||
brunoConfig.proxy = config;
|
||||
dispatch(updateBrunoConfig(brunoConfig, collection.uid))
|
||||
.then(() => {
|
||||
toast.success('Collection settings updated successfully.');
|
||||
})
|
||||
.catch((err) => console.log(err) && toast.error('Failed to update collection settings'));
|
||||
};
|
||||
|
||||
const onClientCertSettingsUpdate = (config) => {
|
||||
const brunoConfig = cloneDeep(collection.brunoConfig);
|
||||
if (!brunoConfig.clientCertificates) {
|
||||
brunoConfig.clientCertificates = {
|
||||
enabled: true,
|
||||
certs: [config]
|
||||
};
|
||||
} else {
|
||||
brunoConfig.clientCertificates.certs.push(config);
|
||||
}
|
||||
dispatch(updateBrunoConfig(brunoConfig, collection.uid))
|
||||
.then(() => {
|
||||
toast.success('Collection settings updated successfully');
|
||||
})
|
||||
.catch((err) => console.log(err) && toast.error('Failed to update collection settings'));
|
||||
};
|
||||
|
||||
const onClientCertSettingsRemove = (config) => {
|
||||
const brunoConfig = cloneDeep(collection.brunoConfig);
|
||||
brunoConfig.clientCertificates.certs = brunoConfig.clientCertificates.certs.filter(
|
||||
(item) => item.domain != config.domain
|
||||
);
|
||||
dispatch(updateBrunoConfig(brunoConfig, collection.uid))
|
||||
.then(() => {
|
||||
toast.success('Collection settings updated successfully');
|
||||
})
|
||||
.catch((err) => console.log(err) && toast.error('Failed to update collection settings'));
|
||||
};
|
||||
|
||||
const getTabPanel = (tab) => {
|
||||
switch (tab) {
|
||||
case 'headers': {
|
||||
return <Headers collection={collection} />;
|
||||
}
|
||||
case 'auth': {
|
||||
return <Auth collection={collection} />;
|
||||
}
|
||||
case 'script': {
|
||||
return <Script collection={collection} />;
|
||||
}
|
||||
case 'tests': {
|
||||
return <Test collection={collection} />;
|
||||
}
|
||||
case 'presets': {
|
||||
return <Presets collection={collection} />;
|
||||
}
|
||||
case 'proxy': {
|
||||
return <ProxySettings proxyConfig={proxyConfig} onUpdate={onProxySettingsUpdate} />;
|
||||
}
|
||||
case 'clientCert': {
|
||||
return (
|
||||
<ClientCertSettings
|
||||
clientCertConfig={clientCertConfig}
|
||||
onUpdate={onClientCertSettingsUpdate}
|
||||
onRemove={onClientCertSettingsRemove}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case 'docs': {
|
||||
return <Docs collection={collection} />;
|
||||
}
|
||||
case 'info': {
|
||||
return <Info collection={collection} />;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getTabClassname = (tabName) => {
|
||||
return classnames(`tab select-none ${tabName}`, {
|
||||
active: tabName === tab
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="flex flex-col h-full relative px-4 py-4">
|
||||
<div className="flex flex-wrap items-center tabs" role="tablist">
|
||||
<div className={getTabClassname('headers')} role="tab" onClick={() => setTab('headers')}>
|
||||
Headers
|
||||
</div>
|
||||
<div className={getTabClassname('auth')} role="tab" onClick={() => setTab('auth')}>
|
||||
Auth
|
||||
</div>
|
||||
<div className={getTabClassname('script')} role="tab" onClick={() => setTab('script')}>
|
||||
Script
|
||||
</div>
|
||||
<div className={getTabClassname('tests')} role="tab" onClick={() => setTab('tests')}>
|
||||
Tests
|
||||
</div>
|
||||
<div className={getTabClassname('presets')} role="tab" onClick={() => setTab('presets')}>
|
||||
Presets
|
||||
</div>
|
||||
<div className={getTabClassname('proxy')} role="tab" onClick={() => setTab('proxy')}>
|
||||
Proxy
|
||||
</div>
|
||||
<div className={getTabClassname('clientCert')} role="tab" onClick={() => setTab('clientCert')}>
|
||||
Client Certificates
|
||||
</div>
|
||||
<div className={getTabClassname('docs')} role="tab" onClick={() => setTab('docs')}>
|
||||
Docs
|
||||
</div>
|
||||
<div className={getTabClassname('info')} role="tab" onClick={() => setTab('info')}>
|
||||
Info
|
||||
</div>
|
||||
</div>
|
||||
<section className={`flex ${['auth', 'script', 'docs', 'clientCert'].includes(tab) ? '' : 'mt-4'}`}>
|
||||
{getTabPanel(tab)}
|
||||
</section>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default CollectionSettings;
|
||||
16
packages/bruno-app/src/components/Cookies/StyledWrapper.js
Normal file
16
packages/bruno-app/src/components/Cookies/StyledWrapper.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
table {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
|
||||
thead {
|
||||
color: ${(props) => props.theme.table.thead.color};
|
||||
font-size: 0.8125rem;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
54
packages/bruno-app/src/components/Cookies/index.js
Normal file
54
packages/bruno-app/src/components/Cookies/index.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import Modal from 'components/Modal';
|
||||
import { IconTrash } from '@tabler/icons';
|
||||
import { deleteCookiesForDomain } from 'providers/ReduxStore/slices/app';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const CollectionProperties = ({ onClose }) => {
|
||||
const dispatch = useDispatch();
|
||||
const cookies = useSelector((state) => state.app.cookies) || [];
|
||||
|
||||
const handleDeleteDomain = (domain) => {
|
||||
dispatch(deleteCookiesForDomain(domain))
|
||||
.then(() => {
|
||||
toast.success('Domain deleted successfully');
|
||||
})
|
||||
.catch((err) => console.log(err) && toast.error('Failed to delete domain'));
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal size="md" title="Cookies" hideFooter={true} handleCancel={onClose}>
|
||||
<StyledWrapper>
|
||||
<table className="w-full border-collapse" style={{ marginTop: '-1rem' }}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="py-2 px-2 text-left">Domain</th>
|
||||
<th className="py-2 px-2 text-left">Cookie</th>
|
||||
<th className="py-2 px-2 text-center" style={{ width: 80 }}>
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{cookies.map((cookie) => (
|
||||
<tr key={cookie.domain}>
|
||||
<td className="py-2 px-2">{cookie.domain}</td>
|
||||
<td className="py-2 px-2 break-all">{cookie.cookieString}</td>
|
||||
<td className="text-center">
|
||||
<button tabIndex="-1" onClick={() => handleDeleteDomain(cookie.domain)}>
|
||||
<IconTrash strokeWidth={1.5} size={20} />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</StyledWrapper>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default CollectionProperties;
|
||||
@@ -0,0 +1,18 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
div.CodeMirror {
|
||||
/* todo: find a better way */
|
||||
height: calc(100vh - 240px);
|
||||
|
||||
.CodeMirror-scroll {
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
}
|
||||
.editing-mode {
|
||||
cursor: pointer;
|
||||
color: ${(props) => props.theme.colors.text.yellow};
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
60
packages/bruno-app/src/components/Documentation/index.js
Normal file
60
packages/bruno-app/src/components/Documentation/index.js
Normal file
@@ -0,0 +1,60 @@
|
||||
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 { useState } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import Markdown from 'components/MarkDown';
|
||||
import CodeEditor from 'components/CodeEditor';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const Documentation = ({ item, collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { storedTheme } = useTheme();
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const docs = item.draft ? get(item, 'draft.request.docs') : get(item, 'request.docs');
|
||||
|
||||
const toggleViewMode = () => {
|
||||
setIsEditing((prev) => !prev);
|
||||
};
|
||||
|
||||
const onEdit = (value) => {
|
||||
dispatch(
|
||||
updateRequestDocs({
|
||||
itemUid: item.uid,
|
||||
collectionUid: collection.uid,
|
||||
docs: value
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const onSave = () => dispatch(saveRequest(item.uid, collection.uid));
|
||||
|
||||
if (!item) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledWrapper className="mt-1 h-full w-full relative">
|
||||
<div className="editing-mode mb-2" role="tab" onClick={toggleViewMode}>
|
||||
{isEditing ? 'Preview' : 'Edit'}
|
||||
</div>
|
||||
|
||||
{isEditing ? (
|
||||
<CodeEditor
|
||||
collection={collection}
|
||||
theme={storedTheme}
|
||||
value={docs || ''}
|
||||
onEdit={onEdit}
|
||||
onSave={onSave}
|
||||
mode="application/text"
|
||||
/>
|
||||
) : (
|
||||
<Markdown onDoubleClick={toggleViewMode} content={docs} />
|
||||
)}
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Documentation;
|
||||
@@ -14,6 +14,8 @@ const Wrapper = styled.div`
|
||||
background-color: ${(props) => props.theme.dropdown.bg};
|
||||
box-shadow: ${(props) => props.theme.dropdown.shadow};
|
||||
border-radius: 3px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
|
||||
.tippy-content {
|
||||
padding-left: 0;
|
||||
@@ -43,7 +45,7 @@ const Wrapper = styled.div`
|
||||
}
|
||||
|
||||
&.border-top {
|
||||
border-top: solid 1px ${(props) => props.theme.dropdown.seperator};
|
||||
border-top: solid 1px ${(props) => props.theme.dropdown.separator};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,16 @@ import StyledWrapper from './StyledWrapper';
|
||||
const Dropdown = ({ icon, children, onCreate, placement }) => {
|
||||
return (
|
||||
<StyledWrapper className="dropdown">
|
||||
<Tippy content={children} placement={placement || 'bottom-end'} animation={false} arrow={false} onCreate={onCreate} interactive={true} trigger="click" appendTo="parent">
|
||||
<Tippy
|
||||
content={children}
|
||||
placement={placement || 'bottom-end'}
|
||||
animation={false}
|
||||
arrow={false}
|
||||
onCreate={onCreate}
|
||||
interactive={true}
|
||||
trigger="click"
|
||||
appendTo="parent"
|
||||
>
|
||||
{icon}
|
||||
</Tippy>
|
||||
</StyledWrapper>
|
||||
|
||||
@@ -2,7 +2,7 @@ import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
.current-enviroment {
|
||||
background-color: ${(props) => props.theme.sidebar.badge.bg};
|
||||
background-color: ${(props) => props.theme.sidebar.badge.bg};
|
||||
border-radius: 15px;
|
||||
|
||||
.caret {
|
||||
|
||||
@@ -35,7 +35,7 @@ const EnvironmentSelector = ({ collection }) => {
|
||||
toast.success(`No Environments are active now`);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.log(err) && toast.error('An error occured while selecting the environment'));
|
||||
.catch((err) => console.log(err) && toast.error('An error occurred while selecting the environment'));
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -64,7 +64,7 @@ const EnvironmentSelector = ({ collection }) => {
|
||||
}}
|
||||
>
|
||||
<IconDatabaseOff size={18} strokeWidth={1.5} />
|
||||
<span className='ml-2'>No Environment</span>
|
||||
<span className="ml-2">No Environment</span>
|
||||
</div>
|
||||
<div className="dropdown-item border-top" onClick={() => setOpenSettingsModal(true)}>
|
||||
<div className="pr-2 text-gray-600">
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import Modal from 'components/Modal/index';
|
||||
import Portal from 'components/Portal/index';
|
||||
import { useFormik } from 'formik';
|
||||
import { copyEnvironment } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
const CopyEnvironment = ({ collection, environment, onClose }) => {
|
||||
const dispatch = useDispatch();
|
||||
const inputRef = useRef();
|
||||
const formik = useFormik({
|
||||
enableReinitialize: true,
|
||||
initialValues: {
|
||||
name: environment.name + ' - Copy'
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
name: Yup.string()
|
||||
.min(1, 'must be at least 1 character')
|
||||
.max(50, 'must be 50 characters or less')
|
||||
.required('name is required')
|
||||
}),
|
||||
onSubmit: (values) => {
|
||||
dispatch(copyEnvironment(values.name, environment.uid, collection.uid))
|
||||
.then(() => {
|
||||
toast.success('Environment created in collection');
|
||||
onClose();
|
||||
})
|
||||
.catch(() => toast.error('An error occurred while created the environment'));
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (inputRef && inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
}, [inputRef]);
|
||||
|
||||
const onSubmit = () => {
|
||||
formik.handleSubmit();
|
||||
};
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Modal size="sm" title={'Copy Environment'} confirmText="Copy" handleConfirm={onSubmit} handleCancel={onClose}>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div>
|
||||
<label htmlFor="name" className="block font-semibold">
|
||||
New Environment Name
|
||||
</label>
|
||||
<input
|
||||
id="environment-name"
|
||||
type="text"
|
||||
name="name"
|
||||
ref={inputRef}
|
||||
className="block textbox mt-2 w-full"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.name || ''}
|
||||
/>
|
||||
{formik.touched.name && formik.errors.name ? (
|
||||
<div className="text-red-500">{formik.errors.name}</div>
|
||||
) : null}
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
|
||||
export default CopyEnvironment;
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import Portal from 'components/Portal/index';
|
||||
import Modal from 'components/Modal/index';
|
||||
import Portal from 'components/Portal';
|
||||
import Modal from 'components/Modal';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useFormik } from 'formik';
|
||||
import { addEnvironment } from 'providers/ReduxStore/slices/collections/actions';
|
||||
@@ -16,7 +16,10 @@ const CreateEnvironment = ({ collection, onClose }) => {
|
||||
name: ''
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
name: Yup.string().min(1, 'must be atleast 1 characters').max(50, 'must be 50 characters or less').required('name is required')
|
||||
name: Yup.string()
|
||||
.min(1, 'must be at least 1 character')
|
||||
.max(50, 'must be 50 characters or less')
|
||||
.required('name is required')
|
||||
}),
|
||||
onSubmit: (values) => {
|
||||
dispatch(addEnvironment(values.name, collection.uid))
|
||||
@@ -24,7 +27,7 @@ const CreateEnvironment = ({ collection, onClose }) => {
|
||||
toast.success('Environment created in collection');
|
||||
onClose();
|
||||
})
|
||||
.catch(() => toast.error('An error occured while created the environment'));
|
||||
.catch(() => toast.error('An error occurred while created the environment'));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -40,7 +43,13 @@ const CreateEnvironment = ({ collection, onClose }) => {
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Modal size="sm" title={'Create Environment'} confirmText="Create" handleConfirm={onSubmit} handleCancel={onClose}>
|
||||
<Modal
|
||||
size="sm"
|
||||
title={'Create Environment'}
|
||||
confirmText="Create"
|
||||
handleConfirm={onSubmit}
|
||||
handleCancel={onClose}
|
||||
>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div>
|
||||
<label htmlFor="name" className="block font-semibold">
|
||||
@@ -59,7 +68,9 @@ const CreateEnvironment = ({ collection, onClose }) => {
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.name || ''}
|
||||
/>
|
||||
{formik.touched.name && formik.errors.name ? <div className="text-red-500">{formik.errors.name}</div> : null}
|
||||
{formik.touched.name && formik.errors.name ? (
|
||||
<div className="text-red-500">{formik.errors.name}</div>
|
||||
) : null}
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
@@ -14,13 +14,19 @@ const DeleteEnvironment = ({ onClose, environment, collection }) => {
|
||||
toast.success('Environment deleted successfully');
|
||||
onClose();
|
||||
})
|
||||
.catch(() => toast.error('An error occured while deleting the environment'));
|
||||
.catch(() => toast.error('An error occurred while deleting the environment'));
|
||||
};
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<StyledWrapper>
|
||||
<Modal size="sm" title={'Delete Environment'} confirmText="Delete" handleConfirm={onConfirm} handleCancel={onClose}>
|
||||
<Modal
|
||||
size="sm"
|
||||
title={'Delete Environment'}
|
||||
confirmText="Delete"
|
||||
handleConfirm={onConfirm}
|
||||
handleCancel={onClose}
|
||||
>
|
||||
Are you sure you want to delete <span className="font-semibold">{environment.name}</span> ?
|
||||
</Modal>
|
||||
</StyledWrapper>
|
||||
|
||||
@@ -5,18 +5,32 @@ const Wrapper = styled.div`
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-weight: 600;
|
||||
table-layout: fixed;
|
||||
|
||||
thead,
|
||||
td {
|
||||
border: 1px solid ${(props) => props.theme.collection.environment.settings.gridBorder};
|
||||
padding: 4px 10px;
|
||||
|
||||
&:nth-child(1),
|
||||
&:nth-child(4) {
|
||||
width: 70px;
|
||||
}
|
||||
&:nth-child(5) {
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
thead {
|
||||
color: ${(props) => props.theme.table.thead.color};;
|
||||
color: ${(props) => props.theme.table.thead.color};
|
||||
font-size: 0.8125rem;
|
||||
user-select: none;
|
||||
}
|
||||
td {
|
||||
thead td {
|
||||
padding: 6px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +1,82 @@
|
||||
import React, { useReducer } from 'react';
|
||||
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 reducer from './reducer';
|
||||
import SingleLineEditor from 'components/SingleLineEditor';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { useFormik } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import { uuid } from 'utils/common';
|
||||
import { variableNameRegex } from 'utils/common/regex';
|
||||
|
||||
const EnvironmentVariables = ({ environment, collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [state, reducerDispatch] = useReducer(reducer, { hasChanges: false, variables: environment.variables || [] });
|
||||
const { variables, hasChanges } = state;
|
||||
const { storedTheme } = useTheme();
|
||||
|
||||
const saveChanges = () => {
|
||||
dispatch(saveEnvironment(cloneDeep(variables), environment.uid, collection.uid))
|
||||
.then(() => {
|
||||
toast.success('Changes saved successfully');
|
||||
reducerDispatch({
|
||||
type: 'CHANGES_SAVED'
|
||||
});
|
||||
const formik = useFormik({
|
||||
enableReinitialize: true,
|
||||
initialValues: environment.variables || [],
|
||||
validationSchema: Yup.array().of(
|
||||
Yup.object({
|
||||
enabled: Yup.boolean(),
|
||||
name: Yup.string()
|
||||
.required('Name cannot be empty')
|
||||
.matches(
|
||||
variableNameRegex,
|
||||
'Name contains invalid characters. Must only contain alphanumeric characters, "-", "_", "." and cannot start with a digit.'
|
||||
)
|
||||
.trim(),
|
||||
secret: Yup.boolean(),
|
||||
type: Yup.string(),
|
||||
uid: Yup.string(),
|
||||
value: Yup.string().trim().nullable()
|
||||
})
|
||||
.catch(() => toast.error('An error occured while saving the changes'));
|
||||
),
|
||||
onSubmit: (values) => {
|
||||
if (!formik.dirty) {
|
||||
toast.error('Nothing to save');
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(saveEnvironment(cloneDeep(values), environment.uid, collection.uid))
|
||||
.then(() => {
|
||||
toast.success('Changes saved successfully');
|
||||
formik.resetForm({ values });
|
||||
})
|
||||
.catch(() => toast.error('An error occurred while saving the changes'));
|
||||
}
|
||||
});
|
||||
|
||||
const ErrorMessage = ({ name }) => {
|
||||
const meta = formik.getFieldMeta(name);
|
||||
if (!meta.error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<label htmlFor={name} className="text-red-500">
|
||||
{meta.error}
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
||||
const addVariable = () => {
|
||||
reducerDispatch({
|
||||
type: 'ADD_VAR'
|
||||
});
|
||||
const newVariable = {
|
||||
uid: uuid(),
|
||||
name: '',
|
||||
value: '',
|
||||
type: 'text',
|
||||
secret: false,
|
||||
enabled: true
|
||||
};
|
||||
formik.setFieldValue(formik.values.length, newVariable, false);
|
||||
};
|
||||
|
||||
const handleVarChange = (e, _variable, type) => {
|
||||
const variable = cloneDeep(_variable);
|
||||
switch (type) {
|
||||
case 'name': {
|
||||
variable.name = e.target.value;
|
||||
break;
|
||||
}
|
||||
case 'value': {
|
||||
variable.value = e.target.value;
|
||||
break;
|
||||
}
|
||||
case 'enabled': {
|
||||
variable.enabled = e.target.checked;
|
||||
break;
|
||||
}
|
||||
}
|
||||
reducerDispatch({
|
||||
type: 'UPDATE_VAR',
|
||||
variable
|
||||
});
|
||||
};
|
||||
|
||||
const handleRemoveVars = (variable) => {
|
||||
reducerDispatch({
|
||||
type: 'DELETE_VAR',
|
||||
variable
|
||||
});
|
||||
const handleRemoveVar = (id) => {
|
||||
formik.setValues(formik.values.filter((variable) => variable.uid !== id));
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -63,52 +84,65 @@ const EnvironmentVariables = ({ environment, collection }) => {
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Enabled</td>
|
||||
<td>Name</td>
|
||||
<td>Value</td>
|
||||
<td>Secret</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{variables && variables.length
|
||||
? variables.map((variable, index) => {
|
||||
return (
|
||||
<tr key={variable.uid}>
|
||||
<td>
|
||||
<input
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
value={variable.name}
|
||||
className="mousetrap"
|
||||
onChange={(e) => handleVarChange(e, variable, 'name')}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
value={variable.value}
|
||||
className="mousetrap"
|
||||
onChange={(e) => handleVarChange(e, variable, 'value')}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<div className="flex items-center">
|
||||
<input type="checkbox" checked={variable.enabled} className="mr-3 mousetrap" onChange={(e) => handleVarChange(e, variable, 'enabled')} />
|
||||
<button onClick={() => handleRemoveVars(variable)}>
|
||||
<IconTrash strokeWidth={1.5} size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
{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>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -119,7 +153,7 @@ const EnvironmentVariables = ({ environment, collection }) => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button type="submit" className="submit btn btn-md btn-secondary mt-2" disabled={!hasChanges} onClick={saveChanges}>
|
||||
<button type="submit" className="submit btn btn-md btn-secondary mt-2" onClick={formik.handleSubmit}>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
import produce from 'immer';
|
||||
import find from 'lodash/find';
|
||||
import filter from 'lodash/filter';
|
||||
import { uuid } from 'utils/common';
|
||||
|
||||
const reducer = (state, action) => {
|
||||
switch (action.type) {
|
||||
case 'ADD_VAR': {
|
||||
return produce(state, (draft) => {
|
||||
draft.variables.push({
|
||||
uid: uuid(),
|
||||
name: '',
|
||||
value: '',
|
||||
type: 'text',
|
||||
enabled: true
|
||||
});
|
||||
draft.hasChanges = true;
|
||||
});
|
||||
}
|
||||
|
||||
case 'UPDATE_VAR': {
|
||||
return produce(state, (draft) => {
|
||||
const variable = find(draft.variables, (v) => v.uid === action.variable.uid);
|
||||
variable.name = action.variable.name;
|
||||
variable.value = action.variable.value;
|
||||
variable.enabled = action.variable.enabled;
|
||||
draft.hasChanges = true;
|
||||
});
|
||||
}
|
||||
|
||||
case 'DELETE_VAR': {
|
||||
return produce(state, (draft) => {
|
||||
draft.variables = filter(draft.variables, (v) => v.uid !== action.variable.uid);
|
||||
draft.hasChanges = true;
|
||||
});
|
||||
}
|
||||
|
||||
case 'CHANGES_SAVED': {
|
||||
return produce(state, (draft) => {
|
||||
draft.hasChanges = false;
|
||||
});
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default reducer;
|
||||
@@ -1,17 +1,30 @@
|
||||
import React, { useState } from 'react';
|
||||
import { IconEdit, IconTrash, IconDatabase } from '@tabler/icons';
|
||||
import EnvironmentVariables from './EnvironmentVariables';
|
||||
import RenameEnvironment from '../../RenameEnvironment';
|
||||
import { IconCopy, IconDatabase, IconEdit, IconTrash } from '@tabler/icons';
|
||||
import { useState } from 'react';
|
||||
import CopyEnvironment from '../../CopyEnvironment';
|
||||
import DeleteEnvironment from '../../DeleteEnvironment';
|
||||
import RenameEnvironment from '../../RenameEnvironment';
|
||||
import EnvironmentVariables from './EnvironmentVariables';
|
||||
|
||||
const EnvironmentDetails = ({ environment, collection }) => {
|
||||
const [openEditModal, setOpenEditModal] = useState(false);
|
||||
const [openDeleteModal, setOpenDeleteModal] = useState(false);
|
||||
const [openCopyModal, setOpenCopyModal] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="px-6 flex-grow flex flex-col pt-6" style={{ maxWidth: '700px' }}>
|
||||
{openEditModal && <RenameEnvironment onClose={() => setOpenEditModal(false)} environment={environment} collection={collection} />}
|
||||
{openDeleteModal && <DeleteEnvironment onClose={() => setOpenDeleteModal(false)} environment={environment} collection={collection} />}
|
||||
{openEditModal && (
|
||||
<RenameEnvironment onClose={() => setOpenEditModal(false)} environment={environment} collection={collection} />
|
||||
)}
|
||||
{openDeleteModal && (
|
||||
<DeleteEnvironment
|
||||
onClose={() => setOpenDeleteModal(false)}
|
||||
environment={environment}
|
||||
collection={collection}
|
||||
/>
|
||||
)}
|
||||
{openCopyModal && (
|
||||
<CopyEnvironment onClose={() => setOpenCopyModal(false)} environment={environment} collection={collection} />
|
||||
)}
|
||||
<div className="flex">
|
||||
<div className="flex flex-grow items-center">
|
||||
<IconDatabase className="cursor-pointer" size={20} strokeWidth={1.5} />
|
||||
@@ -19,6 +32,7 @@ const EnvironmentDetails = ({ environment, collection }) => {
|
||||
</div>
|
||||
<div className="flex gap-x-4 pl-4">
|
||||
<IconEdit className="cursor-pointer" size={20} strokeWidth={1.5} onClick={() => setOpenEditModal(true)} />
|
||||
<IconCopy className="cursor-pointer" size={20} strokeWidth={1.5} onClick={() => setOpenCopyModal(true)} />
|
||||
<IconTrash className="cursor-pointer" size={20} strokeWidth={1.5} onClick={() => setOpenDeleteModal(true)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,9 @@ const StyledWrapper = styled.div`
|
||||
background-color: ${(props) => props.theme.collection.environment.settings.sidebar.bg};
|
||||
border-right: solid 1px ${(props) => props.theme.collection.environment.settings.sidebar.borderRight};
|
||||
min-height: 400px;
|
||||
height: 100%;
|
||||
max-height: 85vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.environment-item {
|
||||
@@ -35,18 +38,21 @@ const StyledWrapper = styled.div`
|
||||
}
|
||||
}
|
||||
|
||||
.btn-create-environment {
|
||||
.btn-create-environment,
|
||||
.btn-import-environment {
|
||||
padding: 8px 10px;
|
||||
cursor: pointer;
|
||||
border-bottom: none;
|
||||
color: ${(props) => props.theme.textLink};
|
||||
|
||||
&:hover {
|
||||
span {
|
||||
text-decoration: underline;
|
||||
}
|
||||
span:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-import-environment {
|
||||
color: ${(props) => props.theme.colors.text.muted};
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
|
||||
@@ -2,24 +2,29 @@ import React, { useEffect, useState, forwardRef, useRef } from 'react';
|
||||
import { findEnvironmentInCollection } from 'utils/collections';
|
||||
import usePrevious from 'hooks/usePrevious';
|
||||
import EnvironmentDetails from './EnvironmentDetails';
|
||||
import CreateEnvironment from '../CreateEnvironment/index';
|
||||
import CreateEnvironment from '../CreateEnvironment';
|
||||
import { IconDownload, IconShieldLock } from '@tabler/icons';
|
||||
import ImportEnvironment from '../ImportEnvironment';
|
||||
import ManageSecrets from '../ManageSecrets';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const EnvironmentList = ({ collection }) => {
|
||||
const { environments } = collection;
|
||||
const [selectedEnvironment, setSelectedEnvironment] = useState(null);
|
||||
const [openCreateModal, setOpenCreateModal] = useState(false);
|
||||
const [openImportModal, setOpenImportModal] = useState(false);
|
||||
const [openManageSecretsModal, setOpenManageSecretsModal] = useState(false);
|
||||
|
||||
const envUids = environments ? environments.map((env) => env.uid) : [];
|
||||
const prevEnvUids = usePrevious(envUids);
|
||||
|
||||
useEffect(() => {
|
||||
if(selectedEnvironment) {
|
||||
if (selectedEnvironment) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
|
||||
if(environment) {
|
||||
if (environment) {
|
||||
setSelectedEnvironment(environment);
|
||||
} else {
|
||||
setSelectedEnvironment(environments && environments.length ? environments[0] : null);
|
||||
@@ -28,9 +33,9 @@ const EnvironmentList = ({ collection }) => {
|
||||
|
||||
useEffect(() => {
|
||||
// check env add
|
||||
if (prevEnvUids && prevEnvUids.length && envUids.length > prevEnvUids.length) {
|
||||
if (prevEnvUids && prevEnvUids.length && envUids.length > prevEnvUids.length) {
|
||||
const newEnv = environments.find((env) => !prevEnvUids.includes(env.uid));
|
||||
if(newEnv){
|
||||
if (newEnv) {
|
||||
setSelectedEnvironment(newEnv);
|
||||
}
|
||||
}
|
||||
@@ -38,7 +43,7 @@ const EnvironmentList = ({ collection }) => {
|
||||
// check env delete
|
||||
if (prevEnvUids && prevEnvUids.length && envUids.length < prevEnvUids.length) {
|
||||
setSelectedEnvironment(environments && environments.length ? environments[0] : null);
|
||||
}
|
||||
}
|
||||
}, [envUids, environments, prevEnvUids]);
|
||||
|
||||
if (!selectedEnvironment) {
|
||||
@@ -48,9 +53,11 @@ const EnvironmentList = ({ collection }) => {
|
||||
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>
|
||||
<div className="environments-sidebar">
|
||||
<div className="environments-sidebar flex flex-col">
|
||||
{environments &&
|
||||
environments.length &&
|
||||
environments.map((env) => (
|
||||
@@ -65,6 +72,17 @@ const EnvironmentList = ({ collection }) => {
|
||||
<div className="btn-create-environment" onClick={() => setOpenCreateModal(true)}>
|
||||
+ <span>Create</span>
|
||||
</div>
|
||||
|
||||
<div className="mt-auto btn-import-environment">
|
||||
<div className="flex items-center" onClick={() => setOpenImportModal(true)}>
|
||||
<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)}>
|
||||
<IconShieldLock size={12} strokeWidth={2} />
|
||||
<span className="label ml-1 text-xs">Managing Secrets</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<EnvironmentDetails environment={selectedEnvironment} collection={collection} />
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
import Portal from 'components/Portal';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import importPostmanEnvironment from 'utils/importers/postman-environment';
|
||||
import { importEnvironment } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { toastError } from 'utils/common/error';
|
||||
import Modal from 'components/Modal';
|
||||
|
||||
const ImportEnvironment = ({ onClose, collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleImportPostmanEnvironment = () => {
|
||||
importPostmanEnvironment()
|
||||
.then((environment) => {
|
||||
dispatch(importEnvironment(environment.name, environment.variables, collection.uid))
|
||||
.then(() => {
|
||||
toast.success('Environment imported successfully');
|
||||
onClose();
|
||||
})
|
||||
.catch(() => toast.error('An error occurred while importing the environment'));
|
||||
})
|
||||
.catch((err) => toastError(err, 'Postman Import environment failed'));
|
||||
};
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Modal size="sm" title="Import Environment" hideFooter={true} handleConfirm={onClose} handleCancel={onClose}>
|
||||
<div>
|
||||
<div className="text-link hover:underline cursor-pointer" onClick={handleImportPostmanEnvironment}>
|
||||
Postman Environment
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImportEnvironment;
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import Portal from 'components/Portal';
|
||||
import Modal from 'components/Modal';
|
||||
|
||||
const ManageSecrets = ({ onClose }) => {
|
||||
return (
|
||||
<Portal>
|
||||
<Modal size="sm" title="Manage Secrets" hideFooter={true} handleConfirm={onClose} handleCancel={onClose}>
|
||||
<div>
|
||||
<p>In any collection, there are secrets that need to be managed.</p>
|
||||
<p className="mt-2">These secrets can be anything such as API keys, passwords, or tokens.</p>
|
||||
<p className="mt-4">Bruno offers two approaches to manage secrets in collections.</p>
|
||||
<p className="mt-2">
|
||||
Read more about it in our{' '}
|
||||
<a
|
||||
href="https://docs.usebruno.com/secrets-management/overview.html"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-link hover:underline"
|
||||
>
|
||||
docs
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</Modal>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ManageSecrets;
|
||||
@@ -16,7 +16,10 @@ const RenameEnvironment = ({ onClose, environment, collection }) => {
|
||||
name: environment.name
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
name: Yup.string().min(1, 'must be atleast 1 characters').max(50, 'must be 50 characters or less').required('name is required')
|
||||
name: Yup.string()
|
||||
.min(1, 'must be at least 1 character')
|
||||
.max(50, 'must be 50 characters or less')
|
||||
.required('name is required')
|
||||
}),
|
||||
onSubmit: (values) => {
|
||||
dispatch(renameEnvironment(values.name, environment.uid, collection.uid))
|
||||
@@ -24,7 +27,7 @@ const RenameEnvironment = ({ onClose, environment, collection }) => {
|
||||
toast.success('Environment renamed successfully');
|
||||
onClose();
|
||||
})
|
||||
.catch(() => toast.error('An error occured while renaming the environment'));
|
||||
.catch(() => toast.error('An error occurred while renaming the environment'));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -40,7 +43,13 @@ const RenameEnvironment = ({ onClose, environment, collection }) => {
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Modal size="sm" title={'Rename Environment'} confirmText="Rename" handleConfirm={onSubmit} handleCancel={onClose}>
|
||||
<Modal
|
||||
size="sm"
|
||||
title={'Rename Environment'}
|
||||
confirmText="Rename"
|
||||
handleConfirm={onSubmit}
|
||||
handleCancel={onClose}
|
||||
>
|
||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||
<div>
|
||||
<label htmlFor="name" className="block font-semibold">
|
||||
@@ -59,7 +68,9 @@ const RenameEnvironment = ({ onClose, environment, collection }) => {
|
||||
onChange={formik.handleChange}
|
||||
value={formik.values.name || ''}
|
||||
/>
|
||||
{formik.touched.name && formik.errors.name ? <div className="text-red-500">{formik.errors.name}</div> : null}
|
||||
{formik.touched.name && formik.errors.name ? (
|
||||
<div className="text-red-500">{formik.errors.name}</div>
|
||||
) : null}
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
@@ -3,20 +3,42 @@ import React, { useState } from 'react';
|
||||
import CreateEnvironment from './CreateEnvironment';
|
||||
import EnvironmentList from './EnvironmentList';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import ImportEnvironment from './ImportEnvironment';
|
||||
|
||||
const EnvironmentSettings = ({ collection, onClose }) => {
|
||||
const { environments } = collection;
|
||||
const [openCreateModal, setOpenCreateModal] = useState(false);
|
||||
const [openImportModal, setOpenImportModal] = useState(false);
|
||||
|
||||
if (!environments || !environments.length) {
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<Modal size="md" title="Environments" confirmText={'Close'} handleConfirm={onClose} handleCancel={onClose} hideCancel={true}>
|
||||
<Modal
|
||||
size="md"
|
||||
title="Environments"
|
||||
confirmText={'Close'}
|
||||
handleConfirm={onClose}
|
||||
handleCancel={onClose}
|
||||
hideCancel={true}
|
||||
>
|
||||
{openCreateModal && <CreateEnvironment collection={collection} onClose={() => setOpenCreateModal(false)} />}
|
||||
<div className="text-center">
|
||||
{openImportModal && <ImportEnvironment collection={collection} onClose={() => setOpenImportModal(false)} />}
|
||||
<div className="text-center flex flex-col">
|
||||
<p>No environments found!</p>
|
||||
<button className="btn-create-environment text-link pr-2 py-3 mt-2 select-none" onClick={() => setOpenCreateModal(true)}>
|
||||
+ <span>Create Environment</span>
|
||||
<button
|
||||
className="btn-create-environment text-link pr-2 py-3 mt-2 select-none"
|
||||
onClick={() => setOpenCreateModal(true)}
|
||||
>
|
||||
<span>Create Environment</span>
|
||||
</button>
|
||||
|
||||
<span>Or</span>
|
||||
|
||||
<button
|
||||
className="btn-import-environment text-link pl-2 pr-2 py-3 select-none"
|
||||
onClick={() => setOpenImportModal(true)}
|
||||
>
|
||||
<span>Import Environment</span>
|
||||
</button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
const SendIcon = ({color, width}) => {
|
||||
const SendIcon = ({ color, width }) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={width}
|
||||
height={width}
|
||||
viewBox="0 0 48 48"
|
||||
>
|
||||
<path fill={color} d="M4.02 42l41.98-18-41.98-18-.02 14 30 4-30 4z"/>
|
||||
<path d="M0 0h48v48h-48z" fill="none"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width={width} height={width} viewBox="0 0 48 48">
|
||||
<path fill={color} d="M4.02 42l41.98-18-41.98-18-.02 14 30 4-30 4z" />
|
||||
<path d="M0 0h48v48h-48z" fill="none" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default SendIcon;
|
||||
|
||||
91
packages/bruno-app/src/components/MarkDown/StyledWrapper.js
Normal file
91
packages/bruno-app/src/components/MarkDown/StyledWrapper.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledMarkdownBodyWrapper = styled.div`
|
||||
background: transparent;
|
||||
height: inherit;
|
||||
.markdown-body {
|
||||
background: transparent;
|
||||
overflow-y: auto;
|
||||
color: ${(props) => props.theme.text};
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
padding-top: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
|
||||
h1 {
|
||||
margin: 0.67em 0;
|
||||
font-weight: var(--base-text-weight-semibold, 600);
|
||||
padding-bottom: 0.3em;
|
||||
font-size: 1.3;
|
||||
border-bottom: 1px solid var(--color-border-muted);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: var(--base-text-weight-semibold, 600);
|
||||
padding-bottom: 0.3em;
|
||||
font-size: 1.2;
|
||||
border-bottom: 1px solid var(--color-border-muted);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: var(--base-text-weight-semibold, 600);
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-weight: var(--base-text-weight-semibold, 600);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-weight: var(--base-text-weight-semibold, 600);
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-weight: var(--base-text-weight-semibold, 600);
|
||||
font-size: 0.9em;
|
||||
color: var(--color-fg-muted);
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid var(--color-border-muted);
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: 24px 0;
|
||||
background-color: var(--color-border-default);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: ${(props) => props.theme.sidebar.bg};
|
||||
}
|
||||
|
||||
table {
|
||||
th,
|
||||
td {
|
||||
border: 1px solid ${(props) => props.theme.table.border};
|
||||
background-color: ${(props) => props.theme.bg};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledMarkdownBodyWrapper;
|
||||
32
packages/bruno-app/src/components/MarkDown/index.js
Normal file
32
packages/bruno-app/src/components/MarkDown/index.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const md = new MarkdownIt();
|
||||
|
||||
const Markdown = ({ onDoubleClick, content }) => {
|
||||
const handleOnDoubleClick = (event) => {
|
||||
switch (event.detail) {
|
||||
case 2: {
|
||||
onDoubleClick();
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
const htmlFromMarkdown = md.render(content || '');
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<div
|
||||
className="markdown-body"
|
||||
dangerouslySetInnerHTML={{ __html: htmlFromMarkdown }}
|
||||
onClick={handleOnDoubleClick}
|
||||
/>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Markdown;
|
||||
@@ -1,6 +1,8 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
color: ${(props) => props.theme.text};
|
||||
|
||||
&.modal--animate-out {
|
||||
animation: fade-out 0.5s forwards cubic-bezier(0.19, 1, 0.22, 1);
|
||||
|
||||
@@ -19,7 +21,8 @@ const Wrapper = styled.div`
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
overflow-y: auto;
|
||||
z-index: 1003;
|
||||
z-index: 10;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.bruno-modal-card {
|
||||
@@ -28,7 +31,7 @@ const Wrapper = styled.div`
|
||||
background: var(--color-background-top);
|
||||
border-radius: var(--border-radius);
|
||||
position: relative;
|
||||
z-index: 1003;
|
||||
z-index: 10;
|
||||
max-width: calc(100% - var(--spacing-base-unit));
|
||||
box-shadow: var(--box-shadow-base);
|
||||
display: flex;
|
||||
@@ -100,7 +103,7 @@ const Wrapper = styled.div`
|
||||
border-radius: 0px;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
transition: border-color ease-in-out .1s;
|
||||
transition: border-color ease-in-out 0.1s;
|
||||
border-radius: 3px;
|
||||
background-color: ${(props) => props.theme.modal.input.bg};
|
||||
border: 1px solid ${(props) => props.theme.modal.input.border};
|
||||
|
||||
@@ -3,7 +3,7 @@ import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const ModalHeader = ({ title, handleCancel }) => (
|
||||
<div className="bruno-modal-header">
|
||||
{title ? <div className="bruno-modal-heade-title">{title}</div> : null}
|
||||
{title ? <div className="bruno-modal-header-title">{title}</div> : null}
|
||||
{handleCancel ? (
|
||||
<div className="close cursor-pointer" onClick={handleCancel ? () => handleCancel() : null}>
|
||||
×
|
||||
@@ -14,7 +14,15 @@ const ModalHeader = ({ title, handleCancel }) => (
|
||||
|
||||
const ModalContent = ({ children }) => <div className="bruno-modal-content px-4 py-6">{children}</div>;
|
||||
|
||||
const ModalFooter = ({ confirmText, cancelText, handleSubmit, handleCancel, confirmDisabled, hideCancel, hideFooter }) => {
|
||||
const ModalFooter = ({
|
||||
confirmText,
|
||||
cancelText,
|
||||
handleSubmit,
|
||||
handleCancel,
|
||||
confirmDisabled,
|
||||
hideCancel,
|
||||
hideFooter
|
||||
}) => {
|
||||
confirmText = confirmText || 'Save';
|
||||
cancelText = cancelText || 'Cancel';
|
||||
|
||||
@@ -30,7 +38,12 @@ const ModalFooter = ({ confirmText, cancelText, handleSubmit, handleCancel, conf
|
||||
</button>
|
||||
</span>
|
||||
<span>
|
||||
<button type="submit" className="submit btn btn-md btn-secondary" disabled={confirmDisabled} onClick={handleSubmit}>
|
||||
<button
|
||||
type="submit"
|
||||
className="submit btn btn-md btn-secondary"
|
||||
disabled={confirmDisabled}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
{confirmText}
|
||||
</button>
|
||||
</span>
|
||||
@@ -38,18 +51,30 @@ const ModalFooter = ({ confirmText, cancelText, handleSubmit, handleCancel, conf
|
||||
);
|
||||
};
|
||||
|
||||
const Modal = ({ size, title, confirmText, cancelText, handleCancel, handleConfirm, children, confirmDisabled, hideCancel, hideFooter }) => {
|
||||
const Modal = ({
|
||||
size,
|
||||
title,
|
||||
confirmText,
|
||||
cancelText,
|
||||
handleCancel,
|
||||
handleConfirm,
|
||||
children,
|
||||
confirmDisabled,
|
||||
hideCancel,
|
||||
hideFooter,
|
||||
closeModalFadeTimeout = 500
|
||||
}) => {
|
||||
const [isClosing, setIsClosing] = useState(false);
|
||||
const escFunction = (event) => {
|
||||
const escKeyCode = 27;
|
||||
if (event.keyCode === escKeyCode) {
|
||||
closeModal();
|
||||
closeModal({ type: 'esc' });
|
||||
}
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
const closeModal = (args) => {
|
||||
setIsClosing(true);
|
||||
setTimeout(() => handleCancel(), 500);
|
||||
setTimeout(() => handleCancel(args), closeModalFadeTimeout);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -64,18 +89,18 @@ const Modal = ({ size, title, confirmText, cancelText, handleCancel, handleConfi
|
||||
if (isClosing) {
|
||||
classes += ' modal--animate-out';
|
||||
}
|
||||
if(hideFooter) {
|
||||
if (hideFooter) {
|
||||
classes += ' modal-footer-none';
|
||||
}
|
||||
return (
|
||||
<StyledWrapper className={classes}>
|
||||
<div className={`bruno-modal-card modal-${size}`}>
|
||||
<ModalHeader title={title} handleCancel={() => closeModal()} />
|
||||
<ModalHeader title={title} handleCancel={() => closeModal({ type: 'icon' })} />
|
||||
<ModalContent>{children}</ModalContent>
|
||||
<ModalFooter
|
||||
confirmText={confirmText}
|
||||
cancelText={cancelText}
|
||||
handleCancel={() => closeModal()}
|
||||
handleCancel={() => closeModal({ type: 'button' })}
|
||||
handleSubmit={handleConfirm}
|
||||
confirmDisabled={confirmDisabled}
|
||||
hideCancel={hideCancel}
|
||||
@@ -84,7 +109,12 @@ const Modal = ({ size, title, confirmText, cancelText, handleCancel, handleConfi
|
||||
</div>
|
||||
|
||||
{/* Clicking on backdrop closes the modal */}
|
||||
<div className="bruno-modal-backdrop" onClick={() => closeModal()} />
|
||||
<div
|
||||
className="bruno-modal-backdrop"
|
||||
onClick={() => {
|
||||
closeModal({ type: 'backdrop' });
|
||||
}}
|
||||
/>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user