Compare commits
614 Commits
v1.12.0
...
feat/show-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da368a2d72 | ||
|
|
9698932bde | ||
|
|
44026fcd41 | ||
|
|
d938af0c2c | ||
|
|
fd658400a6 | ||
|
|
dcbb17b164 | ||
|
|
49741875bd | ||
|
|
0fcd9733ff | ||
|
|
62d50169d7 | ||
|
|
1d3d5a1e6a | ||
|
|
d309fa745e | ||
|
|
f7031992d5 | ||
|
|
fcdf68ea15 | ||
|
|
b0a6692179 | ||
|
|
e1e763575d | ||
|
|
4236d1179c | ||
|
|
09365bcabe | ||
|
|
be29ddcbd6 | ||
|
|
522194ca8d | ||
|
|
5af8f584f6 | ||
|
|
adc08f8865 | ||
|
|
0f39d54c3c | ||
|
|
9e6659e842 | ||
|
|
46a0f6e3f8 | ||
|
|
e90b26ebed | ||
|
|
4407f260ae | ||
|
|
d4392416c8 | ||
|
|
2d3cbd26b8 | ||
|
|
98b9660956 | ||
|
|
4e8a4e8914 | ||
|
|
96bcbc80f8 | ||
|
|
1dfc8e2973 | ||
|
|
311886f6c9 | ||
|
|
4a332f40e5 | ||
|
|
93a97a2f4c | ||
|
|
1dee098ca2 | ||
|
|
a07cc7e560 | ||
|
|
c26f7f5ebc | ||
|
|
5d801cf566 | ||
|
|
631b2d869e | ||
|
|
c02f54cc18 | ||
|
|
827a95515d | ||
|
|
9082152f1a | ||
|
|
0efbddeda4 | ||
|
|
b2e186957c | ||
|
|
d855e5cffb | ||
|
|
f3747edaa3 | ||
|
|
752932ef3d | ||
|
|
948cf9dae3 | ||
|
|
b2f93aa549 | ||
|
|
108f228edf | ||
|
|
fe6030140f | ||
|
|
003400cfa8 | ||
|
|
41a02f059d | ||
|
|
b4ed6fd107 | ||
|
|
36246da9e1 | ||
|
|
457b6b982c | ||
|
|
05a07dc4a1 | ||
|
|
85889c2cb9 | ||
|
|
be6ceaab04 | ||
|
|
f1b18688bb | ||
|
|
80c7decb81 | ||
|
|
3ef5a1e21a | ||
|
|
2eb0a4c754 | ||
|
|
10f5af5dda | ||
|
|
8b27ebb96b | ||
|
|
b28f82a881 | ||
|
|
c921606f3f | ||
|
|
c6c08f6c60 | ||
|
|
02cf620090 | ||
|
|
917550ff4d | ||
|
|
4a12cc76fa | ||
|
|
f4f74e223f | ||
|
|
8b4535c131 | ||
|
|
b15fd6c75a | ||
|
|
e1a25fa894 | ||
|
|
2bb3b71a70 | ||
|
|
4c55b9c304 | ||
|
|
639a629809 | ||
|
|
d6e3bd09b4 | ||
|
|
8d67a0d95f | ||
|
|
b9fc0175e7 | ||
|
|
dc5f52cc0d | ||
|
|
602aabdeb8 | ||
|
|
2f8aa79ec1 | ||
|
|
8af90432cf | ||
|
|
61da0733c2 | ||
|
|
33951482d5 | ||
|
|
4e8484ee7c | ||
|
|
071761a61e | ||
|
|
10a11d6725 | ||
|
|
c81178ae26 | ||
|
|
2bafae5397 | ||
|
|
6a1d201e0e | ||
|
|
8de544696d | ||
|
|
66c489da8f | ||
|
|
26c8f35688 | ||
|
|
c3e881ed77 | ||
|
|
2cf55cbb96 | ||
|
|
73f22abf56 | ||
|
|
dbae90a193 | ||
|
|
28aeac4533 | ||
|
|
162b3d6192 | ||
|
|
b016d3fd9d | ||
|
|
f64ff58dbc | ||
|
|
d4d3d96bbb | ||
|
|
a5197ee544 | ||
|
|
8a5fd4f745 | ||
|
|
12cd7940c6 | ||
|
|
0c2cec46a7 | ||
|
|
84457ddc86 | ||
|
|
d6d20e5d49 | ||
|
|
9acdca1059 | ||
|
|
66c4fd4d2f | ||
|
|
f2defb3a31 | ||
|
|
aa66c10608 | ||
|
|
28d20a9c61 | ||
|
|
94fcc0a6a9 | ||
|
|
91abdd5415 | ||
|
|
58e940d193 | ||
|
|
6991dd48f3 | ||
|
|
270a077539 | ||
|
|
ff326acfc8 | ||
|
|
af1446233c | ||
|
|
67d66e2b2f | ||
|
|
753ce5bd6e | ||
|
|
e7d71ef301 | ||
|
|
8430921e4e | ||
|
|
c938abf606 | ||
|
|
3addfe8d4b | ||
|
|
5276556837 | ||
|
|
e47ad94666 | ||
|
|
7065763c7c | ||
|
|
86489d95c2 | ||
|
|
f357c4f171 | ||
|
|
36e34fe667 | ||
|
|
dcc59f42fa | ||
|
|
f6fbff2b42 | ||
|
|
67ce20ef62 | ||
|
|
788e0dc851 | ||
|
|
e2b1c83698 | ||
|
|
15373be63e | ||
|
|
8c9cd079b7 | ||
|
|
6f67a97ade | ||
|
|
ada568cb75 | ||
|
|
b9fa254ab5 | ||
|
|
174ba90fb5 | ||
|
|
de8c7c1ca3 | ||
|
|
407a125533 | ||
|
|
d8881ba6a3 | ||
|
|
755540fb81 | ||
|
|
add358c752 | ||
|
|
91352ade20 | ||
|
|
39fbf4ef33 | ||
|
|
d9547c6654 | ||
|
|
04f9428267 | ||
|
|
ebd8f43219 | ||
|
|
f75b2e26a3 | ||
|
|
2e654c143f | ||
|
|
5bcee265a6 | ||
|
|
647599e5aa | ||
|
|
16b9a2b06e | ||
|
|
7da427c669 | ||
|
|
405e6c1e4e | ||
|
|
efbc21826b | ||
|
|
7a1f1c9df7 | ||
|
|
476bfbaef0 | ||
|
|
8231157cdb | ||
|
|
e397e3fb6f | ||
|
|
8f1cafc80d | ||
|
|
71619cf84b | ||
|
|
a3551c6719 | ||
|
|
e9043e6762 | ||
|
|
6b7d30a701 | ||
|
|
76eab2632e | ||
|
|
bba4d7fcd9 | ||
|
|
46eb7d6786 | ||
|
|
f5c84b57b2 | ||
|
|
0b12901344 | ||
|
|
5e3c303aaf | ||
|
|
f02b1639c3 | ||
|
|
94e0c3ef64 | ||
|
|
17366f5e6e | ||
|
|
f7a6f899d4 | ||
|
|
62205919a3 | ||
|
|
ee44a48994 | ||
|
|
fedc230c9f | ||
|
|
8796cec493 | ||
|
|
b3b76adec4 | ||
|
|
4362760461 | ||
|
|
bc9236c9a7 | ||
|
|
9e16cff62a | ||
|
|
b04d8dde2b | ||
|
|
2a23c95f34 | ||
|
|
cb9aa33ad0 | ||
|
|
31258b1108 | ||
|
|
6e9f16d8f1 | ||
|
|
d1b2539d67 | ||
|
|
c5f8ab3394 | ||
|
|
12c28f4efc | ||
|
|
f20fed444a | ||
|
|
97b92ba35b | ||
|
|
91df36ccca | ||
|
|
294b1a5a7c | ||
|
|
5f27b59dc0 | ||
|
|
af0efc1e7f | ||
|
|
db25346505 | ||
|
|
1a4fc1f539 | ||
|
|
1bea0a42d7 | ||
|
|
22e73a4d83 | ||
|
|
3ab3c09982 | ||
|
|
0fb0ae1826 | ||
|
|
08fe4ae71f | ||
|
|
883c787c0b | ||
|
|
732dc07ec5 | ||
|
|
c00c8f249e | ||
|
|
77d876d443 | ||
|
|
822e7b4630 | ||
|
|
275a7fc113 | ||
|
|
b08b06c4d4 | ||
|
|
7082eb27db | ||
|
|
a121445b1e | ||
|
|
95547108bf | ||
|
|
fc4e945a7e | ||
|
|
1fdb6488fd | ||
|
|
51142e5c77 | ||
|
|
57ce7ccfdf | ||
|
|
c1ce90dad0 | ||
|
|
ceb8bdf0fd | ||
|
|
b9c233cdf9 | ||
|
|
4f5de51104 | ||
|
|
c949783698 | ||
|
|
6af42e5e08 | ||
|
|
f312ed32be | ||
|
|
91fee8d2d0 | ||
|
|
c23a4bf75d | ||
|
|
e38af0bebe | ||
|
|
b968756be2 | ||
|
|
ed5b4b6dc5 | ||
|
|
956ca44ef0 | ||
|
|
3534e133af | ||
|
|
7744e2eb03 | ||
|
|
078c5e8d8a | ||
|
|
6c3607d7e7 | ||
|
|
c04435108b | ||
|
|
e5c8d05850 | ||
|
|
bf0278aa00 | ||
|
|
33d05eaa77 | ||
|
|
5b074409fc | ||
|
|
bdc3cf2150 | ||
|
|
c3b7d45502 | ||
|
|
2ef4bc1b36 | ||
|
|
2f87549dac | ||
|
|
c596012bb5 | ||
|
|
04c6faf5da | ||
|
|
b2f50547a9 | ||
|
|
e221741a6a | ||
|
|
fe43ae9e81 | ||
|
|
c5d4b9f0ae | ||
|
|
b9156cdf7f | ||
|
|
c6a3b784b5 | ||
|
|
33e2afab7b | ||
|
|
5eb6fb38e0 | ||
|
|
c2ae333a12 | ||
|
|
d462242927 | ||
|
|
c1d2f12e48 | ||
|
|
74d472e76e | ||
|
|
bfc0282e49 | ||
|
|
8c70f83297 | ||
|
|
1e6e826426 | ||
|
|
872ba2d48e | ||
|
|
7acde1c174 | ||
|
|
bb6d9a88ec | ||
|
|
29305a8e1e | ||
|
|
9f639378ec | ||
|
|
92a42269e7 | ||
|
|
691629890f | ||
|
|
2051b8788a | ||
|
|
a129d7eb13 | ||
|
|
e9eee0703d | ||
|
|
11816111ea | ||
|
|
08e3cffff8 | ||
|
|
ab63735a89 | ||
|
|
560c6e0d6a | ||
|
|
f688099f2c | ||
|
|
877f1e343a | ||
|
|
32660c5251 | ||
|
|
a1dc224007 | ||
|
|
55bcb34fd5 | ||
|
|
b18f7af28f | ||
|
|
c273ded97d | ||
|
|
971b35a252 | ||
|
|
dad18aabcb | ||
|
|
0738ad1c15 | ||
|
|
829e116e04 | ||
|
|
384e4ce43e | ||
|
|
da3f55c910 | ||
|
|
87833f1e9f | ||
|
|
ba5d1666d6 | ||
|
|
b612feea41 | ||
|
|
da74fb5241 | ||
|
|
aa8b4231e2 | ||
|
|
6b4bd44807 | ||
|
|
058c1090e3 | ||
|
|
6aa6fb5c0a | ||
|
|
cbf99d2daf | ||
|
|
a71f70644f | ||
|
|
b41d08007a | ||
|
|
0e1900b36a | ||
|
|
e6c503253b | ||
|
|
846c1426cf | ||
|
|
c97f8aa148 | ||
|
|
b99c4fe5c1 | ||
|
|
42d2dd284f | ||
|
|
b7e3f2a4ee | ||
|
|
6599c5f5bf | ||
|
|
13f6e5ff43 | ||
|
|
4d76c83328 | ||
|
|
fee19f3d7a | ||
|
|
200fc738e8 | ||
|
|
05294ac556 | ||
|
|
93dfed74f8 | ||
|
|
3d963a7719 | ||
|
|
92abbc4ce6 | ||
|
|
d111893302 | ||
|
|
967ad773eb | ||
|
|
b036863dda | ||
|
|
ead9c23d9e | ||
|
|
8c60a4c032 | ||
|
|
d08f15430c | ||
|
|
f71d93a684 | ||
|
|
44d1ad7422 | ||
|
|
346ece94b7 | ||
|
|
3a96eb003b | ||
|
|
3bd78869a0 | ||
|
|
4b416586b7 | ||
|
|
20ffbe906f | ||
|
|
b2baeb0a5d | ||
|
|
b524af174a | ||
|
|
a4caeac584 | ||
|
|
b03565a816 | ||
|
|
d0c0a543cf | ||
|
|
17192c898b | ||
|
|
7d913b0ee7 | ||
|
|
db4521db5a | ||
|
|
10b7da0558 | ||
|
|
05f19cbb60 | ||
|
|
6d9ac84859 | ||
|
|
d9834d0fd1 | ||
|
|
d84e2a8e9b | ||
|
|
13dbeaba35 | ||
|
|
b615fe7529 | ||
|
|
8a268ee6de | ||
|
|
2ae2acc003 | ||
|
|
13d89b323e | ||
|
|
6acb9be48c | ||
|
|
d9d61b5b1d | ||
|
|
2ee65e69dc | ||
|
|
fd3b5ecf08 | ||
|
|
6d67b1e51f | ||
|
|
79cea34fac | ||
|
|
b0b758a9c6 | ||
|
|
462d17de17 | ||
|
|
9afe415c2d | ||
|
|
1e4bb65db2 | ||
|
|
fcb194d08a | ||
|
|
7354951d5a | ||
|
|
369bca90fc | ||
|
|
5275d365cb | ||
|
|
e2fc056488 | ||
|
|
98d2b2ee9c | ||
|
|
9441c76a12 | ||
|
|
1ef7b52425 | ||
|
|
d88725b998 | ||
|
|
a48ca25fa2 | ||
|
|
28d636fa0d | ||
|
|
2904084853 | ||
|
|
a1eac2f348 | ||
|
|
203b45f4d5 | ||
|
|
2891da3c74 | ||
|
|
09d552b17a | ||
|
|
b524fa7248 | ||
|
|
e138a5f846 | ||
|
|
82a5f56522 | ||
|
|
4f71e801d5 | ||
|
|
d5cb9f135f | ||
|
|
1a4d3dc91a | ||
|
|
78fccc8583 | ||
|
|
37ad8e08fc | ||
|
|
e60e8545a1 | ||
|
|
5258db345e | ||
|
|
c3921bebf2 | ||
|
|
08d1f01e8e | ||
|
|
8bf9a1e821 | ||
|
|
8debb65d89 | ||
|
|
397cab9032 | ||
|
|
449c87802f | ||
|
|
3862a926ab | ||
|
|
56c2e1094d | ||
|
|
4508e309c2 | ||
|
|
f0aaca2639 | ||
|
|
4c2a9c1229 | ||
|
|
4de55c39dd | ||
|
|
84b94f3091 | ||
|
|
2e94969a41 | ||
|
|
09eabbdcea | ||
|
|
233214cb30 | ||
|
|
f694f1ad36 | ||
|
|
dd004c921e | ||
|
|
8597c04ff1 | ||
|
|
5f5f086dfc | ||
|
|
04cd5b0981 | ||
|
|
22772ac10f | ||
|
|
d4234f0837 | ||
|
|
982f467572 | ||
|
|
f4ffb8e357 | ||
|
|
cd908ae1b2 | ||
|
|
1573ddad1b | ||
|
|
2ace83bcaf | ||
|
|
88ccda8fd1 | ||
|
|
ae8cf656a3 | ||
|
|
68c00433f5 | ||
|
|
f1ad7b9ef5 | ||
|
|
27cf8660d8 | ||
|
|
7105e7a86f | ||
|
|
e52ed7a5ce | ||
|
|
393e6896ec | ||
|
|
6ebfb1f109 | ||
|
|
590c21209c | ||
|
|
e7b58b27e8 | ||
|
|
a2a9bae0e3 | ||
|
|
3ef8e677c7 | ||
|
|
86c9e09782 | ||
|
|
fa8662f17d | ||
|
|
dcf34ea92c | ||
|
|
9ece8adda8 | ||
|
|
c302f7e1a9 | ||
|
|
2907d69dfc | ||
|
|
eeddb6a97e | ||
|
|
7ec8539540 | ||
|
|
5e740a6ed6 | ||
|
|
a4032836c3 | ||
|
|
ffc891f38e | ||
|
|
93ea80a3e3 | ||
|
|
68ff422a5f | ||
|
|
54d21c4950 | ||
|
|
bfd9327e74 | ||
|
|
498d0e18b9 | ||
|
|
b5e524e513 | ||
|
|
c512c8d297 | ||
|
|
2e092d34a6 | ||
|
|
d94c8aec51 | ||
|
|
c7062ad613 | ||
|
|
08d0765cfb | ||
|
|
1f0a3e97ae | ||
|
|
36745d79db | ||
|
|
c6490818d0 | ||
|
|
f1ef403c83 | ||
|
|
cad7ecf760 | ||
|
|
8f7fcfa147 | ||
|
|
a3bde5797a | ||
|
|
a070bed7c9 | ||
|
|
207dc2b6a6 | ||
|
|
fee0a8cec1 | ||
|
|
6635d449a5 | ||
|
|
99b1699ade | ||
|
|
20d38e247b | ||
|
|
7c8ab6fd4a | ||
|
|
7bb570cdc7 | ||
|
|
fc5a5aad8d | ||
|
|
93d373c032 | ||
|
|
fde5b0717d | ||
|
|
069b26bdc4 | ||
|
|
8f3e4cfdba | ||
|
|
ba7f5d3dc3 | ||
|
|
42ce183510 | ||
|
|
977bad2156 | ||
|
|
fd4f49cf8e | ||
|
|
1b540c0e57 | ||
|
|
0e443b3a43 | ||
|
|
eaf0da3d00 | ||
|
|
dd41ac3888 | ||
|
|
a0e26c6c4f | ||
|
|
6ac7ce2c73 | ||
|
|
7b3dd697bb | ||
|
|
48e562dcee | ||
|
|
86bd4aa568 | ||
|
|
ed91486d53 | ||
|
|
913b073ba4 | ||
|
|
b1418c081c | ||
|
|
6b373bee47 | ||
|
|
256d4b3e07 | ||
|
|
dc5a09bebc | ||
|
|
ababd79da2 | ||
|
|
5e21210962 | ||
|
|
3e3da2f27b | ||
|
|
b55439ce44 | ||
|
|
ff791098d8 | ||
|
|
5abf837e95 | ||
|
|
6bcf1a3522 | ||
|
|
b0f055567d | ||
|
|
1ee2fecbc2 | ||
|
|
04b0cd2d3b | ||
|
|
0439e6811b | ||
|
|
a130cfcadb | ||
|
|
77fcc14043 | ||
|
|
fb93db6ad4 | ||
|
|
47cf321eba | ||
|
|
b0ab1b048d | ||
|
|
aaec87d7be | ||
|
|
3198bc6b2c | ||
|
|
60be228c33 | ||
|
|
22c3ffcc02 | ||
|
|
b750ccd46f | ||
|
|
0dd0d262d6 | ||
|
|
9a83938c75 | ||
|
|
9b5b3cc202 | ||
|
|
729f341164 | ||
|
|
d5c5fb7435 | ||
|
|
01b8001d4c | ||
|
|
3992650fd6 | ||
|
|
a2354b5e9e | ||
|
|
43b7e94974 | ||
|
|
cdfce9e2b8 | ||
|
|
9bd86f0564 | ||
|
|
1c0b5b25ed | ||
|
|
6d33132705 | ||
|
|
3e5629e738 | ||
|
|
41eb4f8395 | ||
|
|
6ddff58ba5 | ||
|
|
5bb9b1b675 | ||
|
|
f4f29b8520 | ||
|
|
257e2db651 | ||
|
|
a853c13bcd | ||
|
|
96c23200f7 | ||
|
|
7c2becd3a4 | ||
|
|
a85729b4cf | ||
|
|
bd3cec18d8 | ||
|
|
7dcd96350a | ||
|
|
2e1c0ae77a | ||
|
|
6a6754c7da | ||
|
|
1fb2c35984 | ||
|
|
02d3b45efc | ||
|
|
4ce7f0b487 | ||
|
|
3559d98df1 | ||
|
|
0a4251825b | ||
|
|
499cd9d81b | ||
|
|
10a6b96f13 | ||
|
|
4e3d9187f7 | ||
|
|
0921cccb4c | ||
|
|
07a505c365 | ||
|
|
c3411ba0cf | ||
|
|
5246284e32 | ||
|
|
5fe8fce89d | ||
|
|
0cedc9ed51 | ||
|
|
7cbb61bdf8 | ||
|
|
b357dc8e2f | ||
|
|
f745fef6c2 | ||
|
|
dfe810fff4 | ||
|
|
111a947413 | ||
|
|
85c6932f8f | ||
|
|
ced2f1b911 | ||
|
|
685f9d506d | ||
|
|
34cd604a91 | ||
|
|
2ffd0be03f | ||
|
|
58296505a8 | ||
|
|
779f5e9af4 | ||
|
|
2351f64e6f | ||
|
|
03987da05b | ||
|
|
07e2cb5cd9 | ||
|
|
9b43f9a40c | ||
|
|
43b0225fba | ||
|
|
da491a2967 | ||
|
|
be67986123 | ||
|
|
af9c7e0aff | ||
|
|
27e061c355 | ||
|
|
da94a94d71 | ||
|
|
970c2e56d8 | ||
|
|
766c31fa56 | ||
|
|
50fa1c8f0a | ||
|
|
e361d66c88 | ||
|
|
f1203efa62 | ||
|
|
45b9f2e1bf | ||
|
|
538600354d | ||
|
|
5c9093823b | ||
|
|
7b6c4f71a2 | ||
|
|
7e9ae69f38 | ||
|
|
ddbc9ca61b | ||
|
|
d9aa965069 | ||
|
|
6ea9d16f87 | ||
|
|
5bfeb541fc | ||
|
|
c3f713c0bd | ||
|
|
97979a6ab5 | ||
|
|
055adf9fe0 | ||
|
|
e94adc835d | ||
|
|
50bb8c4fdd | ||
|
|
aa0a340b95 | ||
|
|
41d21bc0ff | ||
|
|
2de4b75b89 | ||
|
|
b52cc9e2b4 | ||
|
|
fea3843714 | ||
|
|
5df5d59f50 | ||
|
|
062dd4f889 | ||
|
|
948b027059 | ||
|
|
4d057a39ed | ||
|
|
68c4efb1d3 | ||
|
|
eda8c7da41 | ||
|
|
ac1937f9be | ||
|
|
5f0f7693bb | ||
|
|
9ad22e2600 | ||
|
|
fe8bbc6cc8 | ||
|
|
795c5f8263 | ||
|
|
66bb9dc42b | ||
|
|
70a350fdac |
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"files": [
|
||||
"README.md"
|
||||
],
|
||||
"imageSize": 100,
|
||||
"commit": false,
|
||||
"contributors": [
|
||||
{
|
||||
"login": "liyasthomas",
|
||||
"name": "Liyas Thomas",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/10395817?v=4",
|
||||
"profile": "https://liyasthomas.web.app",
|
||||
"contributions": [
|
||||
"code",
|
||||
"design"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AndrewBastin",
|
||||
"name": "Andrew Bastin",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/9131943?v=4",
|
||||
"profile": "https://github.com/AndrewBastin",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
"projectName": "hoppscotch",
|
||||
"projectOwner": "hoppscotch",
|
||||
"repoType": "github",
|
||||
"repoHost": "https://github.com",
|
||||
"skipCi": true
|
||||
}
|
||||
2
.github/FUNDING.yml
vendored
@@ -1,4 +1,2 @@
|
||||
github: hoppscotch
|
||||
open_collective: hoppscotch
|
||||
patreon: liyasthomas
|
||||
custom: https://www.paypal.me/liyascthomas
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/custom.md
vendored
@@ -6,5 +6,3 @@ labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
5
.github/semantic.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Always validate the PR title AND all the commits
|
||||
titleAndCommits: true
|
||||
# Allows use of Merge commits (eg on github: "Merge branch 'master' into feature/ride-unicorns")
|
||||
# this is only relevant when using commitsOnly: true (or titleAndCommits: true)
|
||||
allowMergeCommits: true
|
||||
92
.github/workflows/codeql-analysis.yml
vendored
@@ -1,71 +1,61 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
name: "CodeQL"
|
||||
name: "Code Scanning - Action"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [main]
|
||||
schedule:
|
||||
# ┌───────────── minute (0 - 59)
|
||||
# │ ┌───────────── hour (0 - 23)
|
||||
# │ │ ┌───────────── day of the month (1 - 31)
|
||||
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
|
||||
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
|
||||
# │ │ │ │ │
|
||||
# │ │ │ │ │
|
||||
# │ │ │ │ │
|
||||
# * * * * *
|
||||
- cron: '0 0 * * 6'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
CodeQL-Build:
|
||||
# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Override automatic language detection by changing the below list
|
||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||
language: ['javascript']
|
||||
# Learn more...
|
||||
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||
permissions:
|
||||
# required for all workflows
|
||||
security-events: write
|
||||
|
||||
# only required for workflows in private repositories
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
# with:
|
||||
# languages: go, javascript, csharp, python, cpp, java
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below).
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following
|
||||
# three lines and modify them (or add more) to build your code if your
|
||||
# project uses a compiled language
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
||||
18
.github/workflows/deploy-prod.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Deploy to Live Channel
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
deploy_live_website:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: FirebaseExtended/action-hosting-deploy@v0
|
||||
with:
|
||||
repoToken: '${{ secrets.GITHUB_TOKEN }}'
|
||||
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_POSTWOMAN_API }}'
|
||||
channelId: live
|
||||
projectId: postwoman-api
|
||||
39
.github/workflows/publish-docker.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: Publish Docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
push_to_registry:
|
||||
name: Push Docker image to Docker Hub
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
|
||||
with:
|
||||
images: hoppscotch/hoppscotch
|
||||
flavor: |
|
||||
latest=true
|
||||
prefix=
|
||||
suffix=
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
32
.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Node.js CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Cache .pnpm-store
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: ${{ runner.os }}-node${{ matrix.node-version }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
- name: Install pnpm
|
||||
run: curl -f https://get.pnpm.io/v6.14.js | node - add --global pnpm@6
|
||||
- name: Run tests
|
||||
run: pnpm i && pnpm -r test
|
||||
6
.gitignore
vendored
@@ -104,3 +104,9 @@ tests/*/screenshots
|
||||
|
||||
# Tests videos
|
||||
tests/*/videos
|
||||
|
||||
# Local Netlify folder
|
||||
.netlify
|
||||
|
||||
# Andrew's crazy Volar shim generator
|
||||
shims-volar.d.ts
|
||||
|
||||
4
.husky/commit-msg
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx --no-install commitlint --edit ""
|
||||
@@ -8,7 +8,6 @@ module.exports = {
|
||||
{
|
||||
ignoreAtRules: [
|
||||
"extends",
|
||||
"tailwind",
|
||||
"apply",
|
||||
"variants",
|
||||
"responsive",
|
||||
|
||||
34
.travis.yml
@@ -1,34 +0,0 @@
|
||||
# == INSTRUCTIONS FOR SETTING UP TRAVIS ==
|
||||
#
|
||||
# 1. Find this repository in your Travis-CI dashboard.
|
||||
# open settings and add an environment variable called
|
||||
# GITHUB_ACCESS_TOKEN and set it to your personal access token.addons:
|
||||
# See: https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line
|
||||
#
|
||||
# **DO NOT TURN ON 'Display value in build log'!!!!**
|
||||
#
|
||||
# 2. Push the code to the repository.
|
||||
|
||||
language: node_js
|
||||
node_js:
|
||||
- lts/*
|
||||
|
||||
os: linux
|
||||
|
||||
cache: npm
|
||||
|
||||
branches:
|
||||
only:
|
||||
- main
|
||||
|
||||
install:
|
||||
- npm ci
|
||||
|
||||
before_script:
|
||||
- npm run build # use nuxt build and start to run tests
|
||||
|
||||
script:
|
||||
- npm test
|
||||
|
||||
notifications:
|
||||
webhooks: https://www.travisbuddy.com
|
||||
16
Dockerfile
@@ -1,4 +1,4 @@
|
||||
FROM node:12.10.0-alpine
|
||||
FROM node:lts-alpine
|
||||
|
||||
LABEL maintainer="Hoppscotch (support@hoppscotch.io)"
|
||||
|
||||
@@ -9,17 +9,19 @@ RUN apk add --update --no-cache \
|
||||
# Create app directory
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN npm install
|
||||
|
||||
ADD . /app/
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm install -g pnpm
|
||||
|
||||
RUN pnpm i
|
||||
|
||||
ENV HOST 0.0.0.0
|
||||
EXPOSE 3000
|
||||
|
||||
RUN mv .env.example .env
|
||||
RUN mv packages/hoppscotch-app/.env.example packages/hoppscotch-app/.env
|
||||
|
||||
CMD ["npm", "run", "dev"]
|
||||
RUN pnpm run generate
|
||||
|
||||
CMD ["pnpm", "run", "start"]
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
# **GitHub Externship @ Hoppscotch**
|
||||
|
||||
**We ❤️ open source**
|
||||
|
||||
We are super excited to be a ‘Partner Organization’ of GitHub Externship 2021 and look forward to supporting all interested students to participate and contribute to our [open source projects](https://github.com/hoppscotch).
|
||||
|
||||
This document covers the process, expectations and guidelines for any interested student so that we can guide, mentor in the best possible manner and most importantly review your community engagement which is a critical factor along with your project idea to be selected from our organization.
|
||||
|
||||
**This post will be updated from time to time. So please keep an eye on it.**
|
||||
|
||||
Before, any of you jump in and start contributing, here are a few documents from the GitHub Externship Team which we advise every student to read through carefully and thoroughly:
|
||||
|
||||
- [GitHub Externship: Website](https://github-externships.github.io/externship/index.html)
|
||||
- [GitHub Externship: Program Structure](https://github-externships.github.io/externship/structure.html)
|
||||
|
||||
Our awesome community members frequently request for features on our [Discord server](https://hoppscotch.io/discord), [Telegram group](https://hoppscotch.io/externship_telegram), [GitHub issues tab](https://github.com/hoppscotch/hoppscotch/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) and we have a never ending list of awesome ideas. However, keeping in mind the 3 months time span, we have filtered through our stockpile and come up with the following ideas for [GitHub Externship](https://github-externships.github.io/externship/index.html) program.
|
||||
|
||||
## **Ideas**
|
||||
|
||||
If you’re a student interested in working with Hoppscotch during GitHub Externship, we’ve assembled for you a list of 20 ideas under the following three categories:
|
||||
|
||||
### **1. Implement existing feature requests:**
|
||||
|
||||
- [gRPC-Web support](https://github.com/hoppscotch/hoppscotch/issues/402)
|
||||
|
||||
Like swagger, let users view message formats from `.proto` / `URL` and test the server methods by sending any messages from the Hoppscotch.
|
||||
|
||||
[**`Learn more →`**](https://github.com/hoppscotch/hoppscotch/issues/402)
|
||||
|
||||
- [Swagger / OpenAPI support](https://github.com/hoppscotch/hoppscotch/issues/470)
|
||||
|
||||
Like [Swagger Inspector](https://inspector.swagger.io/builder) / [Swagger Editor](https://editor.swagger.io). Let users import `swagger.json` and test the server methods by sending any messages from the Hoppscotch.
|
||||
|
||||
[**`Learn more →`**](https://github.com/hoppscotch/hoppscotch/issues/470)
|
||||
|
||||
- [Mock Server](https://github.com/hoppscotch/hoppscotch/issues/1598)
|
||||
|
||||
Mock server allows users to create mock endpoints that accepts request from the system-under-test or from a `json` file.
|
||||
|
||||
[**`Learn more →`**](https://github.com/hoppscotch/hoppscotch/issues/1598)
|
||||
|
||||
### **2. Implement new features:**
|
||||
|
||||
If you'd like to implement a totally new feature to help developers make API testing easy, feel free to come up with your own feature request or a port of feature from other API testing tools.
|
||||
|
||||
[**Create new feature request →**](https://github.com/hoppscotch/hoppscotch/issues/new?assignees=&labels=&template=feature_request.md&title=Feature%20[GitHub%20Externship]:)
|
||||
|
||||
### **3. Refactor existing features:**
|
||||
|
||||
If you'd like to refactor an already implemented feature / workflow - feel free to open a PR to do that. We appreciate using industry best pratices and latest technologies on all of our open source projects.
|
||||
|
||||
## **Built with**
|
||||
|
||||
- [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML)
|
||||
- [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS), [SCSS](https://sass-lang.com), [Tailwind CSS](https://tailwindcss.com)
|
||||
- [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
||||
- [TypeScript](https://www.typescriptlang.org)
|
||||
- [Vue](https://vuejs.org)
|
||||
- [Nuxt](https://nuxtjs.org)
|
||||
|
||||
## **Contributing**
|
||||
|
||||
Please contribute using [GitHub Flow](https://guides.github.com/introduction/flow). Create a branch, add commits, and [open a pull request](https://github.com/hoppscotch/hoppscotch/compare).
|
||||
|
||||
Please read [`CONTRIBUTING`](CONTRIBUTING.md) for details on our [`CODE OF CONDUCT`](CODE_OF_CONDUCT.md), and the process for submitting pull requests to us.
|
||||
|
||||
## **Quick links**
|
||||
|
||||
[**`Repository →`**](https://github.com/hoppscotch/hoppscotch)
|
||||
|
||||
[**`Web app →`**](https://hoppscotch.io)
|
||||
|
||||
[**`Discord server →`**](https://hoppscotch.io/discord)
|
||||
|
||||
[**`Telegram group →`**](https://hoppscotch.io/externship_telegram)
|
||||
|
||||
## **Discussions channel**
|
||||
|
||||
We use [GitHub Discussions](https://github.com/hoppscotch/hoppscotch/discussions) as the primary channel for anything and everything related to GitHub Externship, ranging from
|
||||
|
||||
- Queries on issues you’re working or thinking about to take up.
|
||||
- Mentor advice on your project ideas [Google Drive document once there is enough clarity for easier collaboration and feedback – check project proposal ideas above]
|
||||
- Helping out your friends to onboard and contribute
|
||||
- Finally even selection updates etc.
|
||||
|
||||
Before asking a question please check this [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask)
|
||||
|
||||
## **Need help?**
|
||||
|
||||
Start a discussion [here](https://github.com/hoppscotch/hoppscotch/discussions) if you’re unable to get a response from the [Telegram](https://hoppscotch.io/externship_telegram), [Discord](https://hoppscotch.io/discord) communities.
|
||||
|
||||
Start a new idea under [discussions](https://github.com/hoppscotch/hoppscotch/discussions) only once you’ve finalized your project proposal.
|
||||
|
||||
Send us an email at support@hoppscotch.io for any administrative or operational concerns regarding the program.
|
||||
|
||||
## **Submit your proposal on time**
|
||||
|
||||
You can find the complete GitHub Externship program timeline [here](https://github-externships.github.io/externship/structure.html). Students can begin registering and submitting project proposals to mentor organizations—including Hoppscotch—on April 22, 2021.
|
||||
|
||||
All proposals must be submitted by May 21, 2021.
|
||||
|
||||
We look forward to seeing your proposals for a happy summer of coding.
|
||||
|
||||
## **Mentors**
|
||||
|
||||
- [Liyas Thomas](https://github.com/liyasthomas)
|
||||
- [Andrew Bastin](https://github.com/andrewbastin)
|
||||
|
||||
If you have any questions or queries please contact us via [Telegram](https://hoppscotch.io/externship_telegram), [Discord](https://hoppscotch.io/discord) or send an email to us at support@hoppscotch.io.
|
||||
523
README.md
@@ -1,58 +1,55 @@
|
||||
<div align="center">
|
||||
<a href="https://hoppscotch.io"><img src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/static/logo.png" alt="hoppscotch.io logo" height="128"></a>
|
||||
<br>
|
||||
<br>
|
||||
<a href="https://hoppscotch.io">
|
||||
<img
|
||||
src="https://avatars.githubusercontent.com/u/56705483"
|
||||
alt="Hoppscotch Logo"
|
||||
height="64"
|
||||
/>
|
||||
</a>
|
||||
<br />
|
||||
<p>
|
||||
<b>Hoppscotch - Open source API development ecosystem</b>
|
||||
<h3>
|
||||
<b>
|
||||
Hoppscotch
|
||||
</b>
|
||||
</h3>
|
||||
</p>
|
||||
<p>
|
||||
<i>Helps you create requests faster, saving precious time on development - <a href="https://eepurl.com/g6n_P5">Subscribe</a></i>
|
||||
<b>
|
||||
Open source API development ecosystem
|
||||
</b>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
[](CODE_OF_CONDUCT.md) [](https://hoppscotch.io) [](https://travis-ci.com/hoppscotch/hoppscotch) [](https://twitter.com/share?text=%F0%9F%91%BD%20Hoppscotch%20%E2%80%A2%20Open%20source%20API%20development%20ecosystem%20-%20Helps%20you%20create%20requests%20faster,%20saving%20precious%20time%20on%20development.&url=https://hoppscotch.io&hashtags=hoppscotch&via=hoppscotch_io)
|
||||
[](CODE_OF_CONDUCT.md) [](https://hoppscotch.io) [](https://github.com/hoppscotch/hoppscotch/actions) [](https://twitter.com/share?text=%F0%9F%91%BD%20Hoppscotch%20%E2%80%A2%20Open%20source%20API%20development%20ecosystem%20-%20Helps%20you%20create%20requests%20faster,%20saving%20precious%20time%20on%20development.&url=https://hoppscotch.io&hashtags=hoppscotch&via=hoppscotch_io)
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<sub>Built with ❤︎ by
|
||||
<a href="https://github.com/liyasthomas">liyasthomas</a> and
|
||||
<a href="https://github.com/hoppscotch/hoppscotch/graphs/contributors">contributors</a>
|
||||
<sub>
|
||||
Built with ❤︎ by
|
||||
<a href="https://github.com/hoppscotch/hoppscotch/graphs/contributors">
|
||||
contributors
|
||||
</a>
|
||||
</sub>
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://hoppscotch.io">
|
||||
<img
|
||||
src="https://tiny.cc/hoppscotch_screenshot_1"
|
||||
alt="Screenshot"
|
||||
width="100%"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<b>Sponsored by</b>
|
||||
<br>
|
||||
<br>
|
||||
<a href="https://appwrite.io/?utm_source=hoppscotch&utm_medium=banner&utm_campaign=hello" title="Appwrite" target="_blank">
|
||||
<img height="60px" src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/assets/images/appwrite-banner.svg" title="Appwrite">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
<a href="https://hoppscotch.io"><img src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/static/images/screenshots/banner_dark.png" alt="Screenshot" width="100%"></a>
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<b>Powered by</b>
|
||||
<br>
|
||||
<br>
|
||||
<a href="https://oss.capital/?ref=hoppscotch" title="OSS Capital" target="_blank">
|
||||
<img height="100px" src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/assets/images/ossc-banner.svg" title="OSS Capital">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
#### **Contact**
|
||||
|
||||
[](https://hoppscotch.io/telegram) [](https://hoppscotch.io/discord)
|
||||
|
||||
#### **Support**
|
||||
|
||||
[](https://github.com/sponsors/hoppscotch) [](https://opencollective.com/hoppscotch) [](https://www.patreon.com/liyasthomas) [](https://www.paypal.me/liyascthomas)
|
||||
[](https://hoppscotch.io/discord) [](https://hoppscotch.io/telegram)
|
||||
|
||||
<details>
|
||||
<summary><i>Table of contents</i></summary>
|
||||
<details open>
|
||||
<summary><b>Table of contents</b></summary>
|
||||
|
||||
---
|
||||
|
||||
@@ -61,21 +58,12 @@
|
||||
- [Usage](#usage)
|
||||
- [Built with](#built-with)
|
||||
- [Developing](#developing)
|
||||
- [Browser based development environment](#browser-based-development-environment)
|
||||
- [Local development environment](#local-development-environment)
|
||||
- [Docker compose](#docker-compose)
|
||||
- [Docker](#docker)
|
||||
- [Releasing](#releasing)
|
||||
- [Contributing](#contributing)
|
||||
- [Continuous Integration](#continuous-integration)
|
||||
- [Changelog](#changelog)
|
||||
- [Authors](#authors)
|
||||
- [Lead Developers](#lead-developers)
|
||||
- [Collaborators](#collaborators-)
|
||||
- [Financial Contributors](#financial-contributors)
|
||||
- [GitHub Sponsors](#github-sponsors)
|
||||
- [Open Collective](#open-collective)
|
||||
- [Code Contributors](#code-contributors)
|
||||
- [License](#license)
|
||||
|
||||
---
|
||||
@@ -88,84 +76,48 @@
|
||||
|
||||
⚡️ **Fast:** Send requests and get/copy responses in real-time.
|
||||
|
||||
<details>
|
||||
<summary><i>HTTP Methods</i></summary>
|
||||
|
||||
---
|
||||
**HTTP Methods**
|
||||
|
||||
- `GET` - Requests retrieve resource information
|
||||
- `HEAD` - Retrieve response headers identical to those of a GET request, but without the response body.
|
||||
- `POST` - The server creates a new entry in a database
|
||||
- `PUT` - Updates an existing resource
|
||||
- `PATCH` - Very similar to `PUT` but makes a partial update on a resource
|
||||
- `DELETE` - Deletes resource or related component
|
||||
- `HEAD` - Retrieve response headers identical to those of a GET request, but without the response body.
|
||||
- `CONNECT` - Establishes a tunnel to the server identified by the target resource
|
||||
- `OPTIONS` - Describe the communication options for the target resource
|
||||
- `TRACE` - Performs a message loop-back test along the path to the target resource
|
||||
- `PATCH` - Very similar to `PUT` but makes a partial update on a resource
|
||||
- `<custom>` - Some APIs use custom request methods such as `LIST`. Type in your custom methods.
|
||||
|
||||
---
|
||||
🌈 **Make it yours:** Customizable combinations for background, foreground and accent colors — [customize now ✨](https://hoppscotch.io/settings).
|
||||
|
||||
</details>
|
||||
**Theming**
|
||||
|
||||
🌈 **Make it yours:** Customizable combinations for background, foreground and accent colors. [Customize now ✨](https://hoppscotch.io/settings)
|
||||
- Choose theme: System (default), Light, Dark and Black
|
||||
- Choose accent color: Green (default), Teal, Blue, Indigo, Purple, Yellow, Orange, Red and Pink
|
||||
- Distraction free Zen mode
|
||||
|
||||
<details>
|
||||
<summary><i>Theming</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Choose theme: System, Light, Dark (default) and Black
|
||||
- Choose accent color: Blue, Green (default), Teal, Indigo, Purple, Orange, Pink, Red, and Yellow
|
||||
- Toggle auto-scroll to response
|
||||
|
||||
<p>
|
||||
<a href="https://hoppscotch.io"><img src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/static/images/screenshots/banner_light.png" alt="Screenshot" width="100%"></a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
_Customized themes are synced with local session storage_
|
||||
_Customized themes are synced with cloud / local session_
|
||||
|
||||
🔥 **PWA:** Install as a [PWA](https://developers.google.com/web/progressive-web-apps) on your device.
|
||||
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Instant loading with Service Workers
|
||||
- Offline support
|
||||
- Low RAM/memory and CPU usage
|
||||
- Add to Home Screen
|
||||
- Desktop PWA
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
🚀 **Request:** Retrieve response from endpoint instantly.
|
||||
|
||||
- Choose `method`
|
||||
- Enter `URL`
|
||||
- Send
|
||||
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
1. Choose `method`
|
||||
2. Enter `URL`
|
||||
3. Send
|
||||
|
||||
- Copy/share public "Share URL"
|
||||
- Generate/copy request code snippets for 10+ languages and frameworks
|
||||
- Import `cURL`
|
||||
- Label requests
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
🔌 **WebSocket:** Establish full-duplex communication channels over a single TCP connection.
|
||||
|
||||
📡 **Server Sent Events:** Receive a stream of updates from a server over a HTTP connection without resorting to polling.
|
||||
@@ -176,27 +128,13 @@ _Customized themes are synced with local session storage_
|
||||
|
||||
🔮 **GraphQL:** GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data.
|
||||
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Set endpoint and get schemas
|
||||
- Set endpoint and get schema
|
||||
- Multi-column docs
|
||||
- Set custom request headers
|
||||
- Query schema
|
||||
- Get query response
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
🔐 **Authentication:** Allows to identify the end user.
|
||||
|
||||
<details>
|
||||
<summary><i>Types</i></summary>
|
||||
|
||||
---
|
||||
🔐 **Authorization:** Allows to identify the end user.
|
||||
|
||||
- None
|
||||
- Basic
|
||||
@@ -204,136 +142,62 @@ _Customized themes are synced with local session storage_
|
||||
- OAuth 2.0
|
||||
- OIDC Access Token/PKCE
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
📢 **Headers:** Describes the format the body of your request is being sent as.
|
||||
|
||||
📫 **Parameters:** Use request parameters to set varying parts in simulated requests.
|
||||
|
||||
📃 **Request Body:** Used to send and receive data via the REST API.
|
||||
|
||||
<details>
|
||||
<summary><i>Options</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Set `Content Type`
|
||||
- Add or remove Parameter list
|
||||
- FormData, JSON and many more
|
||||
- Toggle between key-value and RAW input parameter list
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
👋 **Response:** Contains the status line, headers and the message/response body.
|
||||
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Copy response to clipboard
|
||||
- Download response as a file
|
||||
- View response headers
|
||||
- View raw and preview of HTML, image, JSON, XML responses
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
⏰ **History:** Request entries are synced with cloud / local session storage to restore with a single click.
|
||||
|
||||
📁 **Collections:** Keep your API requests organized with collections and folders. Reuse them with a single click.
|
||||
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Unlimited collections, folders and requests
|
||||
- Nested folders
|
||||
- Export as / import from GitHub gist
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
- Export and import as file or GitHub gist
|
||||
|
||||
_Collections are synced with cloud / local session storage_
|
||||
|
||||
🌐 **Proxy:** Enable Proxy Mode from Settings to access blocked APIs.
|
||||
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Hide your IP address
|
||||
- Fixes [`CORS`](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) (Cross Origin Resource Sharing) issues
|
||||
- Access APIs served in non-HTTPS (`http://`)
|
||||
- Use custom Proxy URL
|
||||
- Access APIs served in non-HTTPS (`http://`) endpoints
|
||||
- Use your own Proxy URL
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
_Official proxy server is hosted by Hoppscotch - **[GitHub](https://github.com/hoppscotch/proxyscotch)** - **[Privacy Policy](https://github.com/hoppscotch/proxyscotch/wiki/Privacy-policy)**_
|
||||
_Official proxy server is hosted by Hoppscotch - **[GitHub](https://github.com/hoppscotch/proxyscotch)** - **[Privacy Policy](https://docs.hoppscotch.io/privacy)**_
|
||||
|
||||
📜 **Pre-Request Scripts β:** Snippets of code associated with a request that are executed before the request is sent.
|
||||
|
||||
<details>
|
||||
<summary><i>Use-cases</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Initialize environment variables
|
||||
- Set environment variables
|
||||
- Include timestamp in the request headers
|
||||
- Send a random alphanumeric string in the URL parameters
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
- Any JavaScript functions
|
||||
|
||||
📄 **API Documentation:** Create and share dynamic API documentation easily, quickly.
|
||||
|
||||
<details>
|
||||
<summary><i>Usage</i></summary>
|
||||
|
||||
---
|
||||
|
||||
1. Add your requests to Collections and Folders
|
||||
2. Export Collections and easily share your APIs with the rest of your team
|
||||
3. Import Collections and Generate Documentation on-the-go
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
⌨️ **Keyboard Shortcuts:** Optimized for efficiency.
|
||||
|
||||
> **[Shortcuts WIki](https://github.com/hoppscotch/hoppscotch/wiki/Shortcuts)**
|
||||
> **[Read our documentation on Keyboard Shortcuts](https://docs.hoppscotch.io/features/shortcuts)**
|
||||
|
||||
🌎 **i18n:** Experience the app in your own language.
|
||||
|
||||
<details>
|
||||
<summary><i>Usage</i></summary>
|
||||
|
||||
---
|
||||
|
||||
1. Scroll down to the footer
|
||||
2. Click "Choose Language" icon button
|
||||
3. Select your language from the menu
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
_Keep in mind: Translations aren't available for all source and target language combinations_
|
||||
|
||||
**To provide a localized experience for users around the world, you can add you own translations.**
|
||||
|
||||
_**All `i18n` contributions are welcome to `i18n` [branch](https://github.com/hoppscotch/hoppscotch/tree/i18n) only!**_
|
||||
Help us to translate Hoppscotch. Please read [`TRANSLATIONS`](TRANSLATIONS.md) for details on our [`CODE OF CONDUCT`](CODE_OF_CONDUCT.md), and the process for submitting pull requests to us.
|
||||
|
||||
📦 **Add-ons:** Official add-ons for hoppscotch.
|
||||
|
||||
@@ -347,56 +211,36 @@ _**All `i18n` contributions are welcome to `i18n` [branch](https://github.com/ho
|
||||
|
||||
- **[Hopp-Doc-Gen](https://github.com/hoppscotch/hopp-doc-gen)** - An API doc generator CLI for Hoppscotch
|
||||
|
||||
_Add-ons are developed and maintained under **[Official Hoppscotch Organization](https://github.com/hoppscotch)**._
|
||||
_Add-ons are developed and maintained under **[Hoppscotch Organization](https://github.com/hoppscotch)**._
|
||||
|
||||
☁️ **Auth + Sync:** Sign in and sync in real-time.
|
||||
☁️ **Auth + Sync:** Sign in and sync your data in real-time.
|
||||
|
||||
**Sign in with**
|
||||
|
||||
- Google
|
||||
- GitHub
|
||||
- Google
|
||||
- Email
|
||||
|
||||
**Sync**
|
||||
**Synchronize your data**
|
||||
|
||||
- History
|
||||
- Collections
|
||||
- Environments
|
||||
- Notes
|
||||
- Settings
|
||||
|
||||
✅ **Post-Request Tests β:** Write tests associated with a request that are executed after the request response.
|
||||
|
||||
<details>
|
||||
<summary><i>Use-cases</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Check the status code as an integer
|
||||
- Filter response headers
|
||||
- Parse the response data
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
📝 **Notes** : Instantly jot down notes, tasks or whatever you feel like as they come to your mind.
|
||||
|
||||
_Notes are only available for signed-in users_
|
||||
- Any JavaScript functions
|
||||
|
||||
🌱 **Environments** : Environment variables allow you to store and reuse values in your requests and scripts.
|
||||
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Unlimited environments and variables
|
||||
- Initialize through pre-request script
|
||||
- Export as / import from GitHub gist
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><i>Use-cases</i></summary>
|
||||
|
||||
@@ -412,20 +256,17 @@ _Notes are only available for signed-in users_
|
||||
|
||||
👨👩👧👦 **Teams β:** Helps you collaborate across your team to design, develop, and test APIs faster.
|
||||
|
||||
<details>
|
||||
<summary><i>Features</i></summary>
|
||||
|
||||
---
|
||||
|
||||
- Unlimited team collections and shared requests
|
||||
- Unlimited team members
|
||||
- User roles
|
||||
|
||||
---
|
||||
🚚 **Bulk Edit:** Edit key-value pairs in bulk.
|
||||
|
||||
</details>
|
||||
- Entries are separated by newline
|
||||
- Keys and values are separated by `:`
|
||||
- Prepend `//` to any row you want to add but keep disabled
|
||||
|
||||
**To find out more, please check out [Hoppscotch Wiki](https://github.com/hoppscotch/hoppscotch/wiki).**
|
||||
**For more features, please read our [documentation](https://docs.hoppscotch.io).**
|
||||
|
||||
## **Demo**
|
||||
|
||||
@@ -441,7 +282,7 @@ _Notes are only available for signed-in users_
|
||||
## **Built with**
|
||||
|
||||
- [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML)
|
||||
- [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS), [SCSS](https://sass-lang.com), [Tailwind CSS](https://tailwindcss.com)
|
||||
- [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS), [SCSS](https://sass-lang.com), [Windi CSS](https://windicss.org)
|
||||
- [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
||||
- [TypeScript](https://www.typescriptlang.org)
|
||||
- [Vue](https://vuejs.org)
|
||||
@@ -449,22 +290,23 @@ _Notes are only available for signed-in users_
|
||||
|
||||
## **Developing**
|
||||
|
||||
0. Update [`.env.example`](https://github.com/hoppscotch/hoppscotch/blob/main/.env.example) file found in repository's root directory with your own keys and rename it to `.env`.
|
||||
0. Update [`.env.example`](https://github.com/hoppscotch/hoppscotch/blob/main/.env.example) file found in `packages/hoppscotch-app` with your own keys and rename it to `.env`.
|
||||
|
||||
_Sample keys only works with the [production build](https://hoppscotch.io)._
|
||||
|
||||
#### Browser based development environment
|
||||
### Browser based development environment
|
||||
|
||||
[](https://gitpod.io/#https://github.com/hoppscotch/hoppscotch)
|
||||
- [GitHub codespace](https://docs.github.com/en/codespaces/developing-in-codespaces/creating-a-codespace)
|
||||
- [Gitpod](https://gitpod.io/#https://github.com/hoppscotch/hoppscotch)
|
||||
|
||||
#### Local development environment
|
||||
### Local development environment
|
||||
|
||||
1. [Clone this repo](https://help.github.com/en/articles/cloning-a-repository) with git.
|
||||
2. Install dependencies by running `npm install` within the directory that you cloned (probably `hoppscotch`).
|
||||
3. Start the development server with `npm run dev`.
|
||||
2. Install dependencies by running `pnpm install` within the directory that you cloned (probably `hoppscotch`).
|
||||
3. Start the development server with `pnpm run dev`.
|
||||
4. Open development site by going to [`http://localhost:3000`](http://localhost:3000) in your browser.
|
||||
|
||||
#### Docker compose
|
||||
### Docker compose
|
||||
|
||||
1. [Clone this repo](https://help.github.com/en/articles/cloning-a-repository) with git.
|
||||
2. Run `docker-compose up`
|
||||
@@ -475,44 +317,15 @@ _Sample keys only works with the [production build](https://hoppscotch.io)._
|
||||
**Official container** [](https://hub.docker.com/r/hoppscotch/hoppscotch)
|
||||
|
||||
```bash
|
||||
#pull
|
||||
docker pull hoppscotch/hoppscotch
|
||||
|
||||
#build
|
||||
docker build -t hoppscotch/hoppscotch:latest .
|
||||
|
||||
#run
|
||||
docker run -p 3000:3000 hoppscotch/hoppscotch:latest
|
||||
docker run --rm --name hoppscotch -p 3000:3000 hoppscotch/hoppscotch:latest
|
||||
```
|
||||
|
||||
**Legacy container** [](https://hub.docker.com/r/liyasthomas/postwoman)
|
||||
|
||||
<details>
|
||||
<summary><i>Legacy container</i></summary>
|
||||
|
||||
---
|
||||
|
||||
```bash
|
||||
#pull
|
||||
docker pull liyasthomas/postwoman
|
||||
|
||||
#build
|
||||
docker build -t liyasthomas/postwoman:latest .
|
||||
|
||||
#run
|
||||
docker run -p 3000:3000 liyasthomas/postwoman:latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
|
||||
## **Releasing**
|
||||
|
||||
1. [Clone this repo](https://help.github.com/en/articles/cloning-a-repository) with git.
|
||||
2. Install dependencies by running `npm install` within the directory that you cloned (probably `hoppscotch`).
|
||||
3. Build the release files with `npm run generate`.
|
||||
4. Find the built project in `./dist`.
|
||||
2. Install dependencies by running `pnpm install` within the directory that you cloned (probably `hoppscotch`).
|
||||
3. Build the release files with `pnpm run generate`.
|
||||
4. Find the built project in `packages/hoppscotch-app/dist`.
|
||||
|
||||
## **Contributing**
|
||||
|
||||
@@ -522,7 +335,7 @@ Please read [`CONTRIBUTING`](CONTRIBUTING.md) for details on our [`CODE OF CONDU
|
||||
|
||||
## **Continuous Integration**
|
||||
|
||||
We use [Travis CI](https://travis-ci.com) for continuous integration. Check out our [Travis CI Status](https://travis-ci.com/hoppscotch/hoppscotch).
|
||||
We use [GitHub Actions](https://github.com/features/actions) for continuous integration. Check out our [build workflows](https://github.com/hoppscotch/hoppscotch/actions).
|
||||
|
||||
## **Changelog**
|
||||
|
||||
@@ -530,167 +343,15 @@ See the [`CHANGELOG`](CHANGELOG.md) file for details.
|
||||
|
||||
## **Authors**
|
||||
|
||||
### Lead Developers
|
||||
This project exists thanks to all the people who contribute — [make a contribution](CONTRIBUTING.md).
|
||||
|
||||
- **[Liyas Thomas](https://github.com/liyasthomas)** - _Author_
|
||||
- **[Andrew Bastin](https://github.com/andrewbastin)** - _Lead developer_
|
||||
- **[Caneco](https://twitter.com/caneco)** - _Logo and banner designer_
|
||||
|
||||
### Collaborators <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="https://liyasthomas.web.app"><img src="https://avatars1.githubusercontent.com/u/10395817?v=4" width="100px;" alt=""/><br /><sub><b>Liyas Thomas</b></sub></a><br /><a href="https://github.com/liyasthomas/hoppscotch/commits?author=liyasthomas" title="Code">💻</a> <a href="#design-liyasthomas" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/AndrewBastin"><img src="https://avatars2.githubusercontent.com/u/9131943?v=4" width="100px;" alt=""/><br /><sub><b>Andrew Bastin</b></sub></a><br /><a href="https://github.com/liyasthomas/hoppscotch/commits?author=AndrewBastin" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-enable -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
See the list of [contributors](https://github.com/hoppscotch/hoppscotch/graphs/contributors) who participated in this project.
|
||||
|
||||
### Financial Contributors
|
||||
|
||||
Become a financial contributor and help us sustain our community [[Support](#support)].
|
||||
|
||||
#### GitHub Sponsors
|
||||
|
||||
<p align="center">
|
||||
<a href="https://simplescraper.io/?utm_source=hs" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="100"
|
||||
src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/assets/images/Simplescraper.png"
|
||||
alt="Simplescraper"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/anmolm96" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/anmolm96.png?size=64"
|
||||
alt="Anmol Maini"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/juzhiyuan" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/juzhiyuan.png?size=64"
|
||||
alt="琚致远"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/eldadfux" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/eldadfux.png?size=64"
|
||||
alt="Eldad A. Fux"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/aishwarydhare" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/aishwarydhare.png?size=64"
|
||||
alt="Aishwary Dhare"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/rithish" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/rithish.png?size=64"
|
||||
alt="Rithish"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/ankumar" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/ankumar.png?size=64"
|
||||
alt="Anil Kumar"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/gpeal" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/gpeal.png?size=64"
|
||||
alt="Gabriel Peal"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/donokuda" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/donokuda.png?size=64"
|
||||
alt="Don Okuda"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/ebrescia" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/ebrescia.png?size=64"
|
||||
alt="Erica Brescia"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/mlynch" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/mlynch.png?size=64"
|
||||
alt="Max Lynch"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/brianshaler" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/brianshaler.png?size=64"
|
||||
alt="Brian Shaler"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/mxstbr" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/mxstbr.png?size=64"
|
||||
alt="Max Stoiber"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/jjcaine" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="64"
|
||||
src="https://github.com/jjcaine.png?size=64"
|
||||
alt="John Caine"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
#### Open Collective
|
||||
|
||||
<p align="center">
|
||||
<a href="https://pipedream.com/?ref=hoppscotch" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="100"
|
||||
src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/assets/images/pipedream.png"
|
||||
alt="pipedream"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://paw.cloud/?utm_source=hoppscotch&utm_medium=github&utm_campaign=hoppscotch-sponsorship" target="_blank" rel="noopener">
|
||||
<img
|
||||
width="100"
|
||||
src="https://raw.githubusercontent.com/hoppscotch/hoppscotch/main/assets/images/Paw-Logo-for-Hoppscotch.png"
|
||||
alt="Paw"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
### Code Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute [[Contribute](CONTRIBUTING.md)].
|
||||
|
||||
<a href="https://github.com/hoppscotch/hoppscotch/graphs/contributors"><img src="https://opencollective.com/hoppscotch/contributors.svg?width=890&button=false" /></a>
|
||||
<div align="center">
|
||||
<a href="https://github.com/hoppscotch/hoppscotch/graphs/contributors">
|
||||
<img src="https://opencollective.com/hoppscotch/contributors.svg?width=840&button=false"
|
||||
alt="Contributors"
|
||||
width="100%" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
## **License**
|
||||
|
||||
|
||||
@@ -1,41 +1,23 @@
|
||||
# Translations
|
||||
|
||||
Thanks for your interest in helping translating the software!
|
||||
Thanks for showing your interest in helping us to translate the software.
|
||||
|
||||
## Starting a translation
|
||||
## Creating a new translation
|
||||
|
||||
Before you start working on a translation, look through the [open pull requests](https://github.com/hoppscotch/hoppscotch/pulls) to see if anyone else is already working on one for your language.
|
||||
Before you start working on a new language, please look through the [open pull requests](https://github.com/hoppscotch/hoppscotch/pulls) to see if anyone is already working on a translation. If you find one, please join the discussion and help us keep the existing translations up to date.
|
||||
|
||||
If there's not, then today is your day to lead this effort! Here's how to start:
|
||||
if there is no existing translation, you can create a new one by following these steps:
|
||||
|
||||
1. [Fork this repository](https://github.com/hoppscotch/hoppscotch/fork)
|
||||
2. Create a new branch for your translation work e.g. `es`.
|
||||
3. Copy `lang/en-US.json` to your target language file e.g. `lang/es-ES.json` and translate all the strings.
|
||||
4. Add your language entry to `nuxt.config.js`.
|
||||
1. **[Fork the repository](https://github.com/hoppscotch/hoppscotch/fork).**
|
||||
2. **Create a new branch for your translation.**
|
||||
3. **Create target language file in the [`locales`](https://github.com/hoppscotch/hoppscotch/tree/main/locales) directory.**
|
||||
4. **Copy the contents of the source file [`locales/en.json`](https://github.com/hoppscotch/hoppscotch/blob/main/locales/en.json) to the target language file.**
|
||||
5. **Translate the strings in the target language file.**
|
||||
6. **Add your language entry to [`languages.json`](https://github.com/hoppscotch/hoppscotch/blob/main/languages.json).**
|
||||
7. **Save & commit changes.**
|
||||
8. **Send a pull request.**
|
||||
|
||||
e.g.
|
||||
|
||||
```
|
||||
i18n: {
|
||||
locales: [
|
||||
{
|
||||
code: "en",
|
||||
name: "English",
|
||||
iso: "en-US",
|
||||
file: "en-US.json",
|
||||
},
|
||||
{
|
||||
code: 'es',
|
||||
name: 'Español',
|
||||
iso: 'es-ES',
|
||||
file: 'es-ES.json'
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
5. Save & commit changes.
|
||||
6. Send a pull request. (You may send a pull request before all steps above are complete: e.g., you may want to ask for help with translations, or getting tests to pass. However your pull request will not be merged until all steps above are complete.)
|
||||
_You may send a pull request before all steps above are complete: e.g., you may want to ask for help with translations, or getting tests to pass. However, your pull request will not be merged until all steps above are complete._
|
||||
|
||||
Completing an initial translation of the whole site is a fairly large task. One way to break that task up is to work with other translators through pull requests on your fork. You can also [add collaborators to your fork](https://help.github.com/en/github/setting-up-and-managing-your-github-user-account/inviting-collaborators-to-a-personal-repository) if you'd like to invite other translators to commit directly to your fork and share responsibility for merging pull requests.
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export default {}
|
||||
@@ -1,259 +0,0 @@
|
||||
/* fallback */
|
||||
@font-face {
|
||||
font-family: "Material Icons";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Material_Icons-400-fallback1.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* devanagari */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-400-devanagari2.woff2") format("woff2");
|
||||
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8,
|
||||
U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-400-latin-ext3.woff2") format("woff2");
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
||||
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-400-latin4.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
/* devanagari */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-500-devanagari5.woff2") format("woff2");
|
||||
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8,
|
||||
U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-500-latin-ext6.woff2") format("woff2");
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
||||
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-500-latin7.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
/* devanagari */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-600-devanagari8.woff2") format("woff2");
|
||||
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8,
|
||||
U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-600-latin-ext9.woff2") format("woff2");
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
||||
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-600-latin10.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
/* devanagari */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-700-devanagari11.woff2") format("woff2");
|
||||
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8,
|
||||
U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-700-latin-ext12.woff2") format("woff2");
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
||||
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-700-latin13.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
/* devanagari */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-800-devanagari14.woff2") format("woff2");
|
||||
unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8,
|
||||
U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-800-latin-ext15.woff2") format("woff2");
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
||||
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Poppins-800-latin16.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Roboto_Mono-400-cyrillic-ext17.woff2") format("woff2");
|
||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F,
|
||||
U+FE2E-FE2F;
|
||||
}
|
||||
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Roboto_Mono-400-cyrillic18.woff2") format("woff2");
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Roboto_Mono-400-greek19.woff2") format("woff2");
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Roboto_Mono-400-vietnamese20.woff2") format("woff2");
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1,
|
||||
U+01AF-01B0, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Roboto_Mono-400-latin-ext21.woff2") format("woff2");
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
|
||||
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: "Roboto Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("~assets/fonts/Roboto_Mono-400-latin22.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
|
||||
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
|
||||
U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
font-family: "Material Icons"; /* stylelint-disable-line font-family-no-missing-generic-family-keyword */
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
direction: ltr;
|
||||
-webkit-font-feature-settings: "liga";
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
/* purgecss start ignore */
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
|
||||
/* purgecss end ignore */
|
||||
@tailwind utilities;
|
||||
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 3.5 MiB |
@@ -1,8 +0,0 @@
|
||||
<svg width="198" height="172" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="none" d="M-1-1h200v174H-1z"/>
|
||||
<g>
|
||||
<path fill="#f02e65" d="M197.289 88c0 35.899-29.101 65-65 65-16.675 0-31.883-6.279-43.389-16.601 18.433-8.298 31.266-26.827 31.266-48.353 0-21.553-12.865-40.101-31.335-48.384C100.346 29.304 115.581 23 132.289 23c35.899 0 65 29.101 65 65z"/>
|
||||
<path fill="#f02e65" d="M106.306 36.116a65 65 0 10-78.307 103.769 65 65 0 1078.307-103.77v.001zm-7.229 9.578a53 53 0 01-63.85 84.612 53 53 0 0163.85-84.612z"/>
|
||||
<path fill="#f02e65" d="M68.894 65.511c-.078.192-1.072 4.095-2.142 8.725-1.111 4.63-2.871 11.938-3.864 16.262-1.915 7.92-3.063 13.124-3.063 13.813 0 .19 1.187.345 2.64.345h2.641l1.185-5.282c.69-2.869 2.221-9.451 3.445-14.616 1.225-5.166 2.716-11.441 3.291-13.967.573-2.526 1.147-4.82 1.263-5.088.115-.344-.537-.458-2.526-.458-1.493 0-2.795.114-2.87.266zM48.345 82.079l-3.52 3.827 1.034 1.224c.572.688 2.143 2.411 3.482 3.827l2.449 2.601h6.964l-3.29-3.559c-1.8-1.911-3.292-3.749-3.292-3.978 0-.268 1.378-1.989 3.062-3.826 1.683-1.874 3.061-3.483 3.061-3.674 0-.153-1.454-.268-3.214-.268h-3.176l-3.56 3.826zm26.785-3.597c0 .116.651.842 1.453 1.646 2.987 2.984 5.091 5.511 4.976 6.007-.076.269-1.531 2.066-3.29 3.941l-3.175 3.482h3.557l3.559-.038 3.251-3.558c1.8-1.988 3.253-3.751 3.253-3.98 0-.19-1.53-1.989-3.444-4.016l-3.442-3.713h-3.331c-1.875 0-3.367.115-3.367.229z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.6 MiB |
|
Before Width: | Height: | Size: 6.3 KiB |
@@ -1,813 +0,0 @@
|
||||
$responsiveWidth: 768px;
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
:root {
|
||||
@apply antialiased;
|
||||
|
||||
font-variant-ligatures: common-ligatures;
|
||||
}
|
||||
|
||||
::selection {
|
||||
@apply bg-acColor;
|
||||
@apply text-actColor;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
@apply h-1;
|
||||
@apply w-2;
|
||||
|
||||
&:hover {
|
||||
@apply bg-bgDarkColor;
|
||||
}
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
@apply bg-fgLightColor;
|
||||
|
||||
&:hover {
|
||||
@apply bg-fgColor;
|
||||
}
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
@apply text-fgLightColor;
|
||||
@apply opacity-25;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-bgColor;
|
||||
@apply text-fgColor;
|
||||
@apply text-base;
|
||||
@apply font-medium;
|
||||
@apply select-none;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-touch-callout: none;
|
||||
}
|
||||
|
||||
body.afterLoad {
|
||||
@apply transition-colors;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
|
||||
body.sticky-footer footer {
|
||||
@apply opacity-25;
|
||||
}
|
||||
|
||||
.page-enter-active,
|
||||
.page-leave-active,
|
||||
.layout-enter-active,
|
||||
.layout-leave-active {
|
||||
@apply transition-opacity;
|
||||
@apply duration-150;
|
||||
}
|
||||
|
||||
.page-enter,
|
||||
.page-leave-active,
|
||||
.layout-enter,
|
||||
.layout-leave-active {
|
||||
@apply opacity-0;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply inline-flex;
|
||||
@apply text-current;
|
||||
@apply no-underline;
|
||||
@apply outline-none;
|
||||
|
||||
&.link {
|
||||
@apply text-acColor;
|
||||
}
|
||||
}
|
||||
|
||||
header,
|
||||
footer {
|
||||
& > div {
|
||||
@apply flex;
|
||||
@apply py-2;
|
||||
@apply px-2;
|
||||
@apply w-full;
|
||||
@apply items-center;
|
||||
@apply justify-between;
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
@apply min-h-screen;
|
||||
@apply flex;
|
||||
@apply flex-col;
|
||||
@apply flex-nowrap;
|
||||
}
|
||||
|
||||
.wrapper .page {
|
||||
min-height: calc(100vh - 153px);
|
||||
}
|
||||
|
||||
.header,
|
||||
.content,
|
||||
.columns,
|
||||
.footer {
|
||||
@apply flex;
|
||||
@apply flex-1;
|
||||
}
|
||||
|
||||
.nav-first,
|
||||
.sticky-inner {
|
||||
@apply flex;
|
||||
@apply order-1;
|
||||
@apply flex-col;
|
||||
@apply sticky;
|
||||
@apply top-0;
|
||||
@apply items-start;
|
||||
@apply items-stretch;
|
||||
@apply h-full;
|
||||
}
|
||||
|
||||
main {
|
||||
@apply flex;
|
||||
@apply flex-col;
|
||||
@apply flex-1;
|
||||
@apply order-2;
|
||||
@apply relative;
|
||||
@apply px-4;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
@apply flex;
|
||||
@apply items-center;
|
||||
@apply m-0;
|
||||
@apply font-bold;
|
||||
}
|
||||
|
||||
h3.title {
|
||||
@apply m-2;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-sm;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply border-b;
|
||||
@apply border-dashed;
|
||||
@apply border-brdColor;
|
||||
@apply my-4;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
@apply z-50;
|
||||
@apply outline-none;
|
||||
|
||||
.tooltip-inner {
|
||||
@apply rounded-lg;
|
||||
@apply px-4;
|
||||
@apply py-2;
|
||||
@apply text-xs;
|
||||
@apply font-medium;
|
||||
@apply shadow-lg;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
@apply bg-ttColor;
|
||||
@apply text-fgColor;
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
@apply h-0;
|
||||
@apply w-0;
|
||||
@apply border-solid;
|
||||
@apply absolute;
|
||||
@apply m-2;
|
||||
@apply border-ttColor;
|
||||
@apply z-30;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
|
||||
&[x-placement^="top"] {
|
||||
@apply mb-0;
|
||||
|
||||
.tooltip-arrow {
|
||||
@apply mt-0;
|
||||
@apply mb-0;
|
||||
|
||||
border-width: 5px 5px 0 5px;
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
bottom: -5px;
|
||||
left: calc(50% - 5px);
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="bottom"] {
|
||||
@apply mt-0;
|
||||
|
||||
.tooltip-arrow {
|
||||
@apply mt-0;
|
||||
@apply mb-0;
|
||||
|
||||
border-width: 0 5px 5px 5px;
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-top-color: transparent !important;
|
||||
top: -5px;
|
||||
left: calc(50% - 5px);
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="right"] {
|
||||
@apply ml-0;
|
||||
|
||||
.tooltip-arrow {
|
||||
@apply ml-0;
|
||||
@apply mr-0;
|
||||
|
||||
border-width: 5px 5px 5px 0;
|
||||
border-left-color: transparent !important;
|
||||
border-top-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
left: -5px;
|
||||
top: calc(50% - 5px);
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="left"] {
|
||||
@apply mr-0;
|
||||
|
||||
.tooltip-arrow {
|
||||
@apply ml-0;
|
||||
@apply mr-0;
|
||||
|
||||
border-width: 5px 0 5px 5px;
|
||||
border-top-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
right: -5px;
|
||||
top: calc(50% - 5px);
|
||||
}
|
||||
}
|
||||
|
||||
&.popover {
|
||||
.wrapper {
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.popover-inner {
|
||||
@apply bg-ttColor;
|
||||
@apply text-fgColor;
|
||||
@apply text-base;
|
||||
@apply p-2;
|
||||
@apply rounded-lg;
|
||||
@apply overflow-auto;
|
||||
@apply shadow-lg;
|
||||
|
||||
max-height: 256px;
|
||||
min-width: 128px;
|
||||
|
||||
button {
|
||||
@apply flex-1;
|
||||
@apply m-0;
|
||||
@apply p-2;
|
||||
@apply justify-start;
|
||||
@apply text-left;
|
||||
}
|
||||
|
||||
div {
|
||||
@apply flex;
|
||||
@apply items-stretch;
|
||||
@apply flex-col;
|
||||
}
|
||||
}
|
||||
|
||||
.popover-arrow {
|
||||
@apply border-ttColor;
|
||||
}
|
||||
}
|
||||
|
||||
&[aria-hidden="true"] {
|
||||
@apply invisible;
|
||||
@apply opacity-0;
|
||||
@apply transition-opacity;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
|
||||
&[aria-hidden="false"] {
|
||||
@apply visible;
|
||||
@apply opacity-100;
|
||||
@apply transition-opacity;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
}
|
||||
|
||||
.info:not(.toasted) {
|
||||
@apply m-4;
|
||||
@apply text-fgLightColor;
|
||||
|
||||
.material-icons {
|
||||
@apply align-middle;
|
||||
@apply mr-2;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
@apply inline-flex;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply p-4;
|
||||
@apply bg-acColor;
|
||||
@apply text-actColor;
|
||||
@apply font-bold;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
@apply fill-current;
|
||||
@apply cursor-pointer;
|
||||
@apply outline-none;
|
||||
@apply border-none;
|
||||
|
||||
span {
|
||||
@apply inline-flex;
|
||||
@apply ml-4;
|
||||
@apply text-left;
|
||||
}
|
||||
|
||||
&:not([disabled]):hover,
|
||||
&:not([disabled]):active,
|
||||
&:not([disabled]):focus {
|
||||
@apply text-actColor;
|
||||
@apply fill-current;
|
||||
@apply outline-none;
|
||||
|
||||
box-shadow: inset 0 0 0 2px var(--fg-color);
|
||||
}
|
||||
|
||||
&.icon {
|
||||
@apply bg-transparent;
|
||||
@apply text-fgLightColor;
|
||||
@apply fill-current;
|
||||
@apply outline-none;
|
||||
@apply border-none;
|
||||
@apply rounded-lg;
|
||||
|
||||
&:not([disabled]):hover,
|
||||
&:not([disabled]):active,
|
||||
&:not([disabled]):focus {
|
||||
@apply text-fgColor;
|
||||
@apply fill-current;
|
||||
@apply shadow-none;
|
||||
}
|
||||
}
|
||||
|
||||
&.primary {
|
||||
@apply text-acColor;
|
||||
@apply px-6;
|
||||
|
||||
&:not([disabled]):hover,
|
||||
&:not([disabled]):active,
|
||||
&:not([disabled]):focus {
|
||||
@apply bg-acColor;
|
||||
@apply text-actColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes beat {
|
||||
30% {
|
||||
@apply transform;
|
||||
@apply scale-90;
|
||||
}
|
||||
50% {
|
||||
@apply transform;
|
||||
@apply scale-110;
|
||||
}
|
||||
100% {
|
||||
@apply transform;
|
||||
@apply scale-100;
|
||||
}
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
&:active {
|
||||
animation: beat 0.5s forwards 1;
|
||||
}
|
||||
}
|
||||
|
||||
fieldset:target,
|
||||
section:target {
|
||||
animation: highlight 2s ease;
|
||||
}
|
||||
|
||||
@keyframes highlight {
|
||||
50% {
|
||||
box-shadow: 0 0 0 2px var(--ac-color);
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
@apply truncate;
|
||||
}
|
||||
|
||||
input[type="file"],
|
||||
input[type="radio"],
|
||||
#installPWA {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.show-on-large-screen {
|
||||
@apply flex;
|
||||
@apply flex-1;
|
||||
}
|
||||
|
||||
.method,
|
||||
.url-field,
|
||||
kbd,
|
||||
select,
|
||||
input,
|
||||
textarea,
|
||||
pre,
|
||||
code {
|
||||
@apply flex;
|
||||
@apply p-4;
|
||||
@apply bg-bgDarkColor;
|
||||
@apply text-fgColor;
|
||||
@apply font-mono;
|
||||
@apply font-normal;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
@apply select-text;
|
||||
@apply resize-y;
|
||||
@apply outline-none;
|
||||
@apply w-full;
|
||||
|
||||
&:not([readonly]):not(.ace_editor):hover,
|
||||
&:not([readonly]):not(.ace_editor):active,
|
||||
&:not([readonly]):not(.ace_editor):focus {
|
||||
box-shadow: inset 0 0 0 2px var(--fg-light-color);
|
||||
}
|
||||
}
|
||||
|
||||
.method {
|
||||
@apply cursor-pointer;
|
||||
@apply uppercase;
|
||||
@apply rounded-none;
|
||||
|
||||
min-width: 128px;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
box-shadow: inset 0 0 0 2px var(--fg-light-color);
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
@apply grid;
|
||||
}
|
||||
|
||||
pre.ace_editor {
|
||||
@apply font-mono;
|
||||
@apply font-normal;
|
||||
@apply z-0;
|
||||
@apply resize-none;
|
||||
}
|
||||
|
||||
kbd,
|
||||
code,
|
||||
pre {
|
||||
@apply w-auto;
|
||||
}
|
||||
|
||||
.select-wrapper {
|
||||
@apply relative;
|
||||
@apply w-full;
|
||||
|
||||
pre,
|
||||
input {
|
||||
@apply cursor-pointer;
|
||||
}
|
||||
|
||||
.trigger {
|
||||
@apply w-full;
|
||||
}
|
||||
|
||||
&::after {
|
||||
@apply inline-block;
|
||||
@apply absolute;
|
||||
@apply pointer-events-none;
|
||||
@apply font-icon;
|
||||
@apply text-fgLightColor;
|
||||
|
||||
content: "\e313";
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
@apply cursor-pointer;
|
||||
@apply appearance-none;
|
||||
|
||||
// height: 40px;
|
||||
|
||||
&::-ms-expand {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
|
||||
option {
|
||||
@apply bg-bgColor;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
@apply hidden;
|
||||
|
||||
&,
|
||||
& + label {
|
||||
@apply align-middle;
|
||||
@apply cursor-pointer;
|
||||
|
||||
&::before {
|
||||
@apply border;
|
||||
@apply border-fgColor;
|
||||
@apply rounded-lg;
|
||||
@apply inline-flex;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply text-transparent;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
|
||||
content: "\2714";
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin: 8px 8px 8px 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:checked + label::before {
|
||||
@apply bg-acColor;
|
||||
@apply border-acColor;
|
||||
@apply text-actColor;
|
||||
}
|
||||
}
|
||||
|
||||
.error:not(input),
|
||||
.disabled:not(input),
|
||||
[disabled] {
|
||||
@apply bg-errColor;
|
||||
@apply text-fgLightColor;
|
||||
@apply fill-current;
|
||||
@apply cursor-not-allowed;
|
||||
|
||||
&.icon {
|
||||
@apply text-errColor;
|
||||
@apply fill-current;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
@apply p-4;
|
||||
@apply text-fgLightColor;
|
||||
@apply text-sm;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
@apply flex;
|
||||
}
|
||||
|
||||
ul li,
|
||||
ol li {
|
||||
@apply inline-flex;
|
||||
@apply flex-col;
|
||||
@apply flex-nowrap;
|
||||
@apply flex-1;
|
||||
@apply justify-center;
|
||||
|
||||
&.shrink {
|
||||
@apply flex-grow-0;
|
||||
}
|
||||
}
|
||||
|
||||
.row-wrapper {
|
||||
@apply flex;
|
||||
@apply items-center;
|
||||
@apply justify-between;
|
||||
@apply flex-1;
|
||||
@apply flex-row;
|
||||
|
||||
span,
|
||||
div {
|
||||
@apply inline-flex;
|
||||
@apply flex-nowrap;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
}
|
||||
}
|
||||
|
||||
.info-response {
|
||||
@apply text-yellow-400;
|
||||
}
|
||||
|
||||
.success-response {
|
||||
@apply text-green-400;
|
||||
}
|
||||
|
||||
.redir-response {
|
||||
@apply text-pink-400;
|
||||
}
|
||||
|
||||
.cl-error-response {
|
||||
@apply text-red-400;
|
||||
}
|
||||
|
||||
.sv-error-response {
|
||||
@apply text-red-600;
|
||||
}
|
||||
|
||||
.missing-data-response {
|
||||
@apply text-fgLightColor;
|
||||
}
|
||||
|
||||
#response-details-wrapper {
|
||||
@apply relative;
|
||||
|
||||
textarea {
|
||||
@apply m-0;
|
||||
@apply w-full;
|
||||
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.covers-response {
|
||||
@apply absolute;
|
||||
@apply inset-0;
|
||||
@apply bg-white;
|
||||
@apply h-full;
|
||||
@apply w-full;
|
||||
}
|
||||
}
|
||||
|
||||
#send {
|
||||
@apply whitespace-nowrap;
|
||||
@apply outline-none;
|
||||
@apply border-none;
|
||||
|
||||
&.show {
|
||||
@apply flex;
|
||||
@apply fixed;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
@apply shadow-lg;
|
||||
@apply rounded-lg;
|
||||
|
||||
bottom: 86px;
|
||||
left: 50%;
|
||||
z-index: 10001;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
@apply flex;
|
||||
@apply rounded-lg;
|
||||
@apply w-full;
|
||||
}
|
||||
|
||||
.toasted-container .toasted {
|
||||
justify-content: space-between !important;
|
||||
}
|
||||
|
||||
.toasted.info {
|
||||
background-color: var(--ac-color) !important;
|
||||
color: var(--act-color) !important;
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
.toasted.bubble .action {
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
.toasted .action {
|
||||
margin-left: auto !important;
|
||||
}
|
||||
|
||||
.page-columns {
|
||||
@apply flex;
|
||||
@apply flex-1;
|
||||
@apply flex-col;
|
||||
}
|
||||
|
||||
.inner-left {
|
||||
@apply flex;
|
||||
@apply order-1;
|
||||
}
|
||||
|
||||
.inner-right {
|
||||
@apply flex;
|
||||
@apply order-2;
|
||||
@apply ml-4;
|
||||
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
@media (max-width: $responsiveWidth) {
|
||||
.content,
|
||||
.columns {
|
||||
@apply flex-col;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 0 8px 68px;
|
||||
margin-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
@apply flex-col;
|
||||
@apply flex-nowrap;
|
||||
}
|
||||
|
||||
ul li,
|
||||
ol li {
|
||||
@apply flex;
|
||||
}
|
||||
|
||||
.hide-on-small-screen {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.sticky-inner {
|
||||
@apply relative;
|
||||
@apply w-full;
|
||||
}
|
||||
|
||||
.inner-left {
|
||||
order: 0;
|
||||
}
|
||||
|
||||
.inner-right {
|
||||
@apply ml-0;
|
||||
}
|
||||
|
||||
.toasted-container {
|
||||
margin-bottom: 68px;
|
||||
}
|
||||
}
|
||||
|
||||
.toasted-ad {
|
||||
@apply bg-gray-50;
|
||||
@apply text-gray-900;
|
||||
@apply font-bold;
|
||||
@apply text-sm;
|
||||
@apply rounded-lg;
|
||||
@apply shadow-lg;
|
||||
|
||||
padding: 16px !important;
|
||||
|
||||
.action {
|
||||
@apply bg-gray-50;
|
||||
@apply text-gray-900;
|
||||
@apply rounded-lg;
|
||||
@apply font-bold;
|
||||
|
||||
text-transform: none !important;
|
||||
padding: 12px 16px !important;
|
||||
font-size: 16px !important;
|
||||
margin: 0 !important;
|
||||
margin-left: 8px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.virtual-list {
|
||||
@apply overflow-auto;
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
@mixin baseTheme {
|
||||
--font-sans: "Poppins", "sans-serif";
|
||||
--font-mono: "Roboto Mono", "monospace";
|
||||
--font-icon: "Material Icons";
|
||||
}
|
||||
|
||||
@mixin darkTheme {
|
||||
// Background color
|
||||
--bg-color: rgba(32, 33, 36, 1);
|
||||
// Light Background color
|
||||
--bg-light-color: rgba(255, 255, 255, 0.04);
|
||||
// Dark Background color
|
||||
--bg-dark-color: rgba(0, 0, 0, 0.2);
|
||||
// Text color
|
||||
--fg-color: rgba(255, 255, 255, 0.9);
|
||||
// Light Text color
|
||||
--fg-light-color: rgba(255, 255, 255, 0.5);
|
||||
// Border color
|
||||
--brd-color: rgba(255, 255, 255, 0.05);
|
||||
// Error color
|
||||
--err-color: rgba(255, 255, 255, 0.05);
|
||||
// Tooltip color
|
||||
--tt-color: rgba(48, 48, 48, 1);
|
||||
// Editor theme
|
||||
--editor-theme: "twilight";
|
||||
// Active text color
|
||||
--act-color: rgba(32, 33, 36, 1);
|
||||
}
|
||||
|
||||
@mixin lightTheme {
|
||||
// Background color
|
||||
--bg-color: rgba(255, 255, 255, 1);
|
||||
// Light Background color
|
||||
--bg-light-color: rgba(0, 0, 0, 0.05);
|
||||
// Dark Background color
|
||||
--bg-dark-color: rgba(0, 0, 0, 0.02);
|
||||
// Text color
|
||||
--fg-color: rgba(0, 0, 0, 0.9);
|
||||
// Light Text color
|
||||
--fg-light-color: rgba(0, 0, 0, 0.6);
|
||||
// Border color
|
||||
--brd-color: rgba(0, 0, 0, 0.1);
|
||||
// Error color
|
||||
--err-color: rgba(0, 0, 0, 0.1);
|
||||
// Tooltip color
|
||||
--tt-color: rgba(255, 255, 255, 1);
|
||||
// Editor theme
|
||||
--editor-theme: "iplastic";
|
||||
// Active text color
|
||||
--act-color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
@mixin blackTheme {
|
||||
// Background color
|
||||
--bg-color: rgba(0, 0, 0, 1);
|
||||
// Light Background color
|
||||
--bg-light-color: rgba(255, 255, 255, 0.02);
|
||||
// Dark Background color
|
||||
--bg-dark-color: rgba(255, 255, 255, 0.04);
|
||||
// Text color
|
||||
--fg-color: rgba(255, 255, 255, 0.9);
|
||||
// Light Text color
|
||||
--fg-light-color: rgba(255, 255, 255, 0.5);
|
||||
// Border color
|
||||
--brd-color: rgba(255, 255, 255, 0.05);
|
||||
// Error color
|
||||
--err-color: rgba(255, 255, 255, 0.05);
|
||||
// Tooltip color
|
||||
--tt-color: rgba(32, 32, 32, 1);
|
||||
// Editor theme
|
||||
--editor-theme: "vibrant_ink";
|
||||
// Active text color
|
||||
--act-color: rgba(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
@mixin blueTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.blue.400");
|
||||
}
|
||||
|
||||
@mixin greenTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.green.400");
|
||||
}
|
||||
|
||||
@mixin tealTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.teal.400");
|
||||
}
|
||||
|
||||
@mixin indigoTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.indigo.400");
|
||||
}
|
||||
|
||||
@mixin purpleTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.purple.400");
|
||||
}
|
||||
|
||||
@mixin orangeTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.orange.400");
|
||||
}
|
||||
|
||||
@mixin pinkTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.pink.400");
|
||||
}
|
||||
|
||||
@mixin redTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.red.400");
|
||||
}
|
||||
|
||||
@mixin yellowTheme {
|
||||
// Acent color
|
||||
--ac-color: theme("colors.yellow.400");
|
||||
}
|
||||
|
||||
:root {
|
||||
@include baseTheme;
|
||||
@include darkTheme;
|
||||
@include greenTheme;
|
||||
}
|
||||
|
||||
:root.light {
|
||||
@include lightTheme;
|
||||
}
|
||||
|
||||
:root.dark {
|
||||
@include darkTheme;
|
||||
}
|
||||
|
||||
:root.black {
|
||||
@include blackTheme;
|
||||
}
|
||||
|
||||
:root[data-accent="blue"] {
|
||||
@include blueTheme;
|
||||
}
|
||||
:root[data-accent="green"] {
|
||||
@include greenTheme;
|
||||
}
|
||||
:root[data-accent="teal"] {
|
||||
@include tealTheme;
|
||||
}
|
||||
:root[data-accent="indigo"] {
|
||||
@include indigoTheme;
|
||||
}
|
||||
:root[data-accent="purple"] {
|
||||
@include purpleTheme;
|
||||
}
|
||||
:root[data-accent="orange"] {
|
||||
@include orangeTheme;
|
||||
}
|
||||
:root[data-accent="pink"] {
|
||||
@include pinkTheme;
|
||||
}
|
||||
:root[data-accent="red"] {
|
||||
@include redTheme;
|
||||
}
|
||||
:root[data-accent="yellow"] {
|
||||
@include yellowTheme;
|
||||
}
|
||||
3
commitlint.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: ["@commitlint/config-conventional"],
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<p class="info">
|
||||
{{ $t("donate_info1") }}
|
||||
</p>
|
||||
<p class="info">
|
||||
{{ $t("donate_info2") }}
|
||||
</p>
|
||||
<div class="px-2 row-wrapper">
|
||||
<span>
|
||||
<a
|
||||
v-tooltip.right="$t('recurring')"
|
||||
href="https://github.com/sponsors/hoppscotch"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<button class="icon">
|
||||
<i class="material-icons">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
class="material-icons"
|
||||
>
|
||||
<path
|
||||
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
|
||||
/>
|
||||
</svg>
|
||||
</i>
|
||||
<span>GitHub Sponsors</span>
|
||||
</button>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="px-2 row-wrapper">
|
||||
<span>
|
||||
<a
|
||||
v-tooltip.right="$t('one_time_recurring')"
|
||||
href="https://opencollective.com/hoppscotch"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<button class="icon">
|
||||
<i class="material-icons">donut_large</i>
|
||||
<span>{{ $t("open_collective") }}</span>
|
||||
</button>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="px-2 row-wrapper">
|
||||
<span>
|
||||
<a
|
||||
v-tooltip.right="$t('recurring')"
|
||||
href="https://www.patreon.com/liyasthomas"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<button class="icon">
|
||||
<i class="material-icons">local_parking</i>
|
||||
<span>{{ $t("patreon") }}</span>
|
||||
</button>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="px-2 row-wrapper">
|
||||
<span>
|
||||
<a
|
||||
v-tooltip.right="$t('one_time')"
|
||||
href="https://www.paypal.me/liyascthomas"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<button class="icon">
|
||||
<i class="material-icons">payment</i>
|
||||
<span>{{ $t("paypal") }}</span>
|
||||
</button>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="p-2">
|
||||
<h3 class="title">Financial Contributors</h3>
|
||||
<div class="contributors">
|
||||
<a
|
||||
href="https://oss.capital/?ref=hoppscotch"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<img
|
||||
style="height: 100%; width: 300px"
|
||||
src="~assets/images/ossc-banner.svg"
|
||||
alt="OSS Capital"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://appwrite.io/?utm_source=hoppscotch&utm_medium=banner&utm_campaign=hello"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<img
|
||||
style="height: 100%; width: 300px; background: #fff"
|
||||
src="~assets/images/appwrite-banner.svg"
|
||||
alt="Appwrite"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://pipedream.com/?ref=hoppscotch"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<img
|
||||
style="max-width: 100px"
|
||||
src="~assets/images/pipedream.png"
|
||||
alt="pipedream"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://paw.cloud/?utm_source=hoppscotch&utm_medium=website&utm_campaign=hoppscotch-sponsorship"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<img
|
||||
style="max-width: 100px"
|
||||
src="~assets/images/Paw-Logo-for-Hoppscotch.png"
|
||||
alt="Paw"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://simplescraper.io/?utm_source=hs"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<img
|
||||
style="max-height: 50px"
|
||||
src="~assets/images/Simplescraper_dark.png"
|
||||
alt="Simplescraper"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://tyk.io?ref=hoppscotch" target="_blank" rel="noopener">
|
||||
<img
|
||||
style="max-width: 320px"
|
||||
src="~assets/images/Tyk-side-project-logo-tagline-blk.png"
|
||||
alt="Tyk Banner"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<p class="info">
|
||||
This project exists thanks to all the
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
href="https://github.com/hoppscotch/hoppscotch/graphs/contributors"
|
||||
class="link"
|
||||
>
|
||||
people who contribute
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.contributors {
|
||||
@apply flex;
|
||||
@apply items-center;
|
||||
@apply flex-wrap;
|
||||
@apply overflow-auto;
|
||||
@apply m-2;
|
||||
@apply space-x-2;
|
||||
@apply space-y-2;
|
||||
}
|
||||
</style>
|
||||
@@ -1,106 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("extensions") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<p class="info">
|
||||
{{ $t("extensions_info1") }}
|
||||
</p>
|
||||
<div class="px-2">
|
||||
<a
|
||||
href="https://addons.mozilla.org/en-US/firefox/addon/hoppscotch"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<button class="icon">
|
||||
<svg
|
||||
class="material-icons"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path
|
||||
d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm8.003 8.657c-1.276-3.321-4.46-4.605-5.534-4.537 3.529 1.376 4.373 6.059 4.06 7.441-.307-1.621-1.286-3.017-1.872-3.385 3.417 8.005-4.835 10.465-7.353 7.687.649.168 1.931.085 2.891-.557.898-.602.983-.638 1.56-.683.686-.053-.041-1.406-1.539-1.177-.616.094-1.632.819-2.88.341-1.508-.576-1.46-2.634.096-2.015.337-.437.088-1.263.088-1.263.452-.414 1.022-.706 1.37-.911.228-.135.829-.507.795-1.23-.123-.096-.32-.219-.766-.193-1.736.11-1.852-.518-1.967-.808.078-.668.524-1.534 1.361-1.931-1.257-.193-2.28.397-2.789 1.154-.809-.174-1.305-.183-2.118-.031-.316-.24-.666-.67-.878-1.181C6.36 3.312 9.027 2 12 2c5.912 0 8.263 4.283 8.003 6.657z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Firefox</span>
|
||||
<span
|
||||
v-if="hasFirefoxExtInstalled"
|
||||
v-tooltip="$t('installed')"
|
||||
class="icon"
|
||||
>
|
||||
<i class="material-icons">done</i>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
<div class="px-2">
|
||||
<a
|
||||
href="https://chrome.google.com/webstore/detail/hoppscotch-browser-extens/amknoiejhlmhancpahfcfcfhllgkpbld"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<button class="icon">
|
||||
<svg
|
||||
class="material-icons"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
>
|
||||
<path
|
||||
d="M2.897 4.181A11.87 11.87 0 0111.969 0c4.288 0 8.535 2.273 10.717 6.554h-9.293c-1.674.001-2.755-.037-3.926.579-1.376.724-2.415 2.067-2.777 3.644L2.897 4.181zM8.007 12c0 2.2 1.789 3.99 3.988 3.99s3.988-1.79 3.988-3.99-1.789-3.991-3.988-3.991S8.007 9.8 8.007 12zm5.536 5.223c-2.238.666-4.858-.073-6.293-2.549-1.095-1.891-3.989-6.933-5.305-9.225A11.856 11.856 0 000 11.956c0 5.448 3.726 10.65 9.673 11.818l3.87-6.551zm2.158-9.214a5.463 5.463 0 011.007 6.719 1815.43 1815.43 0 01-5.46 9.248C18.437 24.419 24 18.616 24 12.004c0-1.313-.22-2.66-.69-3.995h-7.609z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Chrome</span>
|
||||
<span
|
||||
v-if="hasChromeExtInstalled"
|
||||
v-tooltip="$t('installed')"
|
||||
class="icon"
|
||||
>
|
||||
<i class="material-icons">done</i>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer"></div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
hasChromeExtensionInstalled,
|
||||
hasFirefoxExtensionInstalled,
|
||||
} from "~/helpers/strategies/ExtensionStrategy"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasChromeExtInstalled: hasChromeExtensionInstalled(),
|
||||
hasFirefoxExtInstalled: hasFirefoxExtensionInstalled(),
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show() {
|
||||
this.hasChromeExtInstalled = hasChromeExtensionInstalled()
|
||||
this.hasFirefoxExtInstalled = hasFirefoxExtensionInstalled()
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,104 +0,0 @@
|
||||
<template>
|
||||
<footer class="footer">
|
||||
<div class="row-wrapper">
|
||||
<span
|
||||
class="flex flex-col font-mono md:flex-row"
|
||||
style="align-items: start"
|
||||
>
|
||||
<a
|
||||
class="footer-link"
|
||||
href="https://www.netlify.com"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
Powered by Netlify
|
||||
</a>
|
||||
<span>
|
||||
<a
|
||||
class="footer-link"
|
||||
href="https://oss.capital/?ref=hoppscotch"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
OSS Capital
|
||||
</a>
|
||||
<a
|
||||
class="footer-link"
|
||||
href="https://paw.cloud/?utm_source=hoppscotch&utm_medium=website&utm_campaign=hoppscotch-sponsorship"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
Paw
|
||||
</a>
|
||||
<a
|
||||
class="footer-link"
|
||||
href="https://simplescraper.io/?utm_source=hs"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
Simplescraper
|
||||
</a>
|
||||
</span>
|
||||
<iframe
|
||||
src="https://ghbtns.com/github-btn.html?user=hoppscotch&type=sponsor"
|
||||
frameborder="0"
|
||||
scrolling="0"
|
||||
width="150"
|
||||
height="20"
|
||||
title="GitHub"
|
||||
class="footer-link"
|
||||
loading="lazy"
|
||||
></iframe>
|
||||
</span>
|
||||
<span
|
||||
class="flex flex-col font-mono md:flex-row"
|
||||
style="align-items: start"
|
||||
>
|
||||
<a href="mailto:support@hoppscotch.io" target="_blank" rel="noopener">
|
||||
<button v-tooltip="$t('contact_us')" class="icon">
|
||||
<i class="material-icons">email</i>
|
||||
</button>
|
||||
</a>
|
||||
<v-popover>
|
||||
<button v-tooltip="$t('choose_language')" class="icon">
|
||||
<i class="material-icons">translate</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div v-for="locale in availableLocales" :key="locale.code">
|
||||
<nuxt-link :to="switchLocalePath(locale.code)">
|
||||
<button v-close-popover class="icon">
|
||||
{{ locale.name }}
|
||||
</button>
|
||||
</nuxt-link>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</span>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
computed: {
|
||||
availableLocales() {
|
||||
return this.$i18n.locales.filter(({ code }) => code !== this.$i18n.locale)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.footer-link {
|
||||
@apply inline-flex;
|
||||
@apply flex-shrink-0;
|
||||
@apply my-2;
|
||||
@apply mx-4;
|
||||
@apply text-fgLightColor;
|
||||
@apply text-sm;
|
||||
|
||||
&:hover {
|
||||
@apply text-fgColor;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,342 +0,0 @@
|
||||
<template>
|
||||
<header class="header">
|
||||
<div class="row-wrapper">
|
||||
<span class="slide-in">
|
||||
<nuxt-link :to="localePath('index')">
|
||||
<h1 class="hide-on-small-screen logo">Hoppscotch</h1>
|
||||
<h1 class="show-on-small-screen logo">Hs</h1>
|
||||
</nuxt-link>
|
||||
<iframe
|
||||
src="https://ghbtns.com/github-btn.html?user=hoppscotch&repo=hoppscotch&type=star&count=true"
|
||||
frameborder="0"
|
||||
scrolling="0"
|
||||
width="150"
|
||||
height="20"
|
||||
title="GitHub"
|
||||
class="ml-8 hide-on-small-screen"
|
||||
loading="lazy"
|
||||
></iframe>
|
||||
</span>
|
||||
<span>
|
||||
<a
|
||||
href="https://appwrite.io/?utm_source=hoppscotch&utm_medium=banner&utm_campaign=hello"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
class="
|
||||
inline-flex
|
||||
items-center
|
||||
px-4
|
||||
py-2
|
||||
mx-4
|
||||
font-mono
|
||||
text-sm
|
||||
rounded-md
|
||||
bg-bgDarkColor
|
||||
hide-on-small-screen
|
||||
"
|
||||
>
|
||||
Appwrite - Open-Source Backend as a Service
|
||||
<img
|
||||
class="w-8 ml-2"
|
||||
src="~assets/images/appwrite-icon.svg"
|
||||
alt="Appwrite"
|
||||
/>
|
||||
</a>
|
||||
<button
|
||||
id="installPWA"
|
||||
v-tooltip="$t('install_pwa')"
|
||||
class="icon"
|
||||
@click.prevent="showInstallPrompt()"
|
||||
>
|
||||
<i class="material-icons">offline_bolt</i>
|
||||
</button>
|
||||
<a
|
||||
href="https://github.com/hoppscotch/hoppscotch"
|
||||
target="_blank"
|
||||
aria-label="GitHub"
|
||||
rel="noopener"
|
||||
>
|
||||
<button v-tooltip="'GitHub'" class="icon" aria-label="GitHub">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
class="material-icons"
|
||||
>
|
||||
<path
|
||||
d="M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</a>
|
||||
<v-popover v-if="fb.currentUser === null">
|
||||
<button v-tooltip="$t('login_with')" class="icon">
|
||||
<i class="material-icons">login</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<FirebaseLogin />
|
||||
</template>
|
||||
</v-popover>
|
||||
<v-popover v-else>
|
||||
<button
|
||||
v-tooltip="
|
||||
(fb.currentUser.displayName ||
|
||||
'<label><i>Name not found</i></label>') +
|
||||
'<br>' +
|
||||
(fb.currentUser.email || '<label><i>Email not found</i></label>')
|
||||
"
|
||||
class="icon"
|
||||
aria-label="Account"
|
||||
>
|
||||
<img
|
||||
v-if="fb.currentUser.photoURL"
|
||||
:src="fb.currentUser.photoURL"
|
||||
class="w-6 h-6 rounded-full material-icons"
|
||||
alt="Profile image"
|
||||
/>
|
||||
<i v-else class="material-icons">account_circle</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<nuxt-link v-close-popover :to="localePath('settings')">
|
||||
<button class="icon">
|
||||
<i class="material-icons">settings</i>
|
||||
<span>
|
||||
{{ $t("settings") }}
|
||||
</span>
|
||||
</button>
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<div>
|
||||
<FirebaseLogout />
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
<v-popover>
|
||||
<button v-tooltip="$t('more')" class="icon">
|
||||
<i class="material-icons">drag_indicator</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<button v-close-popover class="icon" @click="showExtensions = true">
|
||||
<i class="material-icons">extension</i>
|
||||
<span>{{ $t("extensions") }}</span>
|
||||
</button>
|
||||
<button v-close-popover class="icon" @click="showShortcuts = true">
|
||||
<i class="material-icons">keyboard</i>
|
||||
<span>{{ $t("shortcuts") }}</span>
|
||||
</button>
|
||||
<button v-close-popover class="icon" @click="showSupport = true">
|
||||
<i class="material-icons">favorite</i>
|
||||
<span>{{ $t("support_us") }}</span>
|
||||
</button>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
onClick="window.open('https://twitter.com/share?text=👽 Hoppscotch • Open source API development ecosystem - Helps you create requests faster, saving precious time on development.&url=https://hoppscotch.io&hashtags=hoppscotch&via=hoppscotch_io');"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
|
||||
<path
|
||||
d="M24 4.557a9.83 9.83 0 01-2.828.775 4.932 4.932 0 002.165-2.724 9.864 9.864 0 01-3.127 1.195 4.916 4.916 0 00-3.594-1.555c-3.179 0-5.515 2.966-4.797 6.045A13.978 13.978 0 011.671 3.149a4.93 4.93 0 001.523 6.574 4.903 4.903 0 01-2.229-.616c-.054 2.281 1.581 4.415 3.949 4.89a4.935 4.935 0 01-2.224.084 4.928 4.928 0 004.6 3.419A9.9 9.9 0 010 19.54a13.94 13.94 0 007.548 2.212c9.142 0 14.307-7.721 13.995-14.646A10.025 10.025 0 0024 4.557z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Tweet</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="navigatorShare"
|
||||
v-close-popover
|
||||
v-tooltip="$t('more')"
|
||||
class="icon"
|
||||
@click="nativeShare"
|
||||
>
|
||||
<i class="material-icons">share</i>
|
||||
<span>Share</span>
|
||||
</button>
|
||||
</template>
|
||||
</v-popover>
|
||||
</span>
|
||||
</div>
|
||||
<AppExtensions
|
||||
:show="showExtensions"
|
||||
@hide-modal="showExtensions = false"
|
||||
/>
|
||||
<AppShortcuts :show="showShortcuts" @hide-modal="showShortcuts = false" />
|
||||
<AppSupport :show="showSupport" @hide-modal="showSupport = false" />
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import intializePwa from "~/helpers/pwa"
|
||||
import { fb } from "~/helpers/fb"
|
||||
// import { hasExtensionInstalled } from "~/helpers/strategies/ExtensionStrategy"
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// Once the PWA code is initialized, this holds a method
|
||||
// that can be called to show the user the installation
|
||||
// prompt.
|
||||
showInstallPrompt: null,
|
||||
showExtensions: false,
|
||||
showShortcuts: false,
|
||||
showSupport: false,
|
||||
navigatorShare: navigator.share,
|
||||
fb,
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
this._keyListener = function (e) {
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault()
|
||||
this.showExtensions = this.showShortcuts = this.showSupport = false
|
||||
}
|
||||
}
|
||||
document.addEventListener("keydown", this._keyListener.bind(this))
|
||||
|
||||
// Initializes the PWA code - checks if the app is installed,
|
||||
// etc.
|
||||
this.showInstallPrompt = await intializePwa()
|
||||
const cookiesAllowed = localStorage.getItem("cookiesAllowed") === "yes"
|
||||
if (!cookiesAllowed) {
|
||||
this.$toast.show(this.$t("we_use_cookies"), {
|
||||
icon: "info",
|
||||
duration: 5000,
|
||||
theme: "toasted-primary",
|
||||
action: [
|
||||
{
|
||||
text: this.$t("dismiss"),
|
||||
onClick: (_, toastObject) => {
|
||||
localStorage.setItem("cookiesAllowed", "yes")
|
||||
toastObject.goAway(0)
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
// let showAd = localStorage.getItem("showAd") === "no"
|
||||
// if (!showAd) {
|
||||
// setTimeout(() => {
|
||||
// this.$toast.clear()
|
||||
// this.$toast.show(
|
||||
// "<span><a href='https://github.com/sponsors/hoppscotch' target='_blank' rel='noopener'>Sponsor us to support Hoppscotch open source project 💖</a><br><sub>Whoosh this away to dismiss.</sub></span>",
|
||||
// {
|
||||
// icon: "",
|
||||
// duration: 0,
|
||||
// theme: "toasted-ad",
|
||||
// action: [
|
||||
// {
|
||||
// text: "Sponsor",
|
||||
// icon: "chevron_right",
|
||||
// onClick: (_, toastObject) => {
|
||||
// localStorage.setItem("showAd", "no")
|
||||
// toastObject.goAway(0)
|
||||
// window.open("https://github.com/sponsors/hoppscotch")
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// onComplete() {
|
||||
// localStorage.setItem("showAd", "no")
|
||||
// },
|
||||
// }
|
||||
// )
|
||||
// }, 8000)
|
||||
// }
|
||||
|
||||
// let showExtensionsToast = localStorage.getItem("showExtensionsToast") === "yes"
|
||||
// if (!showExtensionsToast) {
|
||||
// setTimeout(() => {
|
||||
// if (!hasExtensionInstalled()) {
|
||||
// this.$toast.show(this.$t("extensions_info2"), {
|
||||
// icon: "extension",
|
||||
// duration: 5000,
|
||||
// theme: "toasted-primary",
|
||||
// action: [
|
||||
// {
|
||||
// text: this.$t("yes"),
|
||||
// onClick: (_, toastObject) => {
|
||||
// this.showExtensions = true
|
||||
// localStorage.setItem("showExtensionsToast", "yes")
|
||||
// toastObject.goAway(0)
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// text: this.$t("no"),
|
||||
// onClick: (_, toastObject) => {
|
||||
// this.$store.commit("setMiscState", {
|
||||
// value: false,
|
||||
// attribute: "showExtensionsToast",
|
||||
// })
|
||||
// localStorage.setItem("showExtensionsToast", "no")
|
||||
// toastObject.goAway(0)
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// })
|
||||
// }
|
||||
// }, 5000)
|
||||
// }
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("keydown", this._keyListener)
|
||||
},
|
||||
methods: {
|
||||
nativeShare() {
|
||||
if (navigator.share) {
|
||||
navigator
|
||||
.share({
|
||||
title: "Hoppscotch",
|
||||
text: "Hoppscotch • Open source API development ecosystem - Helps you create requests faster, saving precious time on development.",
|
||||
url: "https://hoppscotch.io",
|
||||
})
|
||||
.then(() => {})
|
||||
.catch(console.error)
|
||||
} else {
|
||||
// fallback
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$responsiveWidth: 768px;
|
||||
|
||||
.logo {
|
||||
@apply text-xl;
|
||||
@apply transition-colors;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
|
||||
&:hover {
|
||||
@apply text-acColor;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
0% {
|
||||
@apply opacity-0;
|
||||
@apply -left-4;
|
||||
}
|
||||
|
||||
100% {
|
||||
@apply opacity-100;
|
||||
@apply left-0;
|
||||
}
|
||||
}
|
||||
|
||||
.slide-in {
|
||||
@apply relative;
|
||||
|
||||
animation: slideIn 0.2s forwards ease-in-out;
|
||||
}
|
||||
|
||||
.show-on-small-screen {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
@media (max-width: $responsiveWidth) {
|
||||
.show-on-small-screen {
|
||||
@apply inline-flex;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,22 +0,0 @@
|
||||
<template>
|
||||
<svg viewBox="0 0 612.001 612.001">
|
||||
<path
|
||||
:fill="color"
|
||||
data-old_color="#202124"
|
||||
class="active-path"
|
||||
data-original="#202124"
|
||||
d="M64.601 236.822C64.601 394.256 192.786 612 306.001 612 412.582 612 547.4 394.256 547.4 236.822S439.322 0 306 0 64.601 79.388 64.601 236.822zm304.12 116.415c29.475-29.475 70.598-40.195 108.552-32.173 8.021 37.954-2.698 79.077-32.173 108.552-29.475 29.476-70.598 40.196-108.552 32.174-8.022-37.955 2.698-79.078 32.173-108.552zm-233.994-32.174c37.954-8.02 79.077 2.698 108.552 32.173 29.475 29.475 40.195 70.598 32.173 108.552-37.954 8.021-79.077-2.698-108.552-32.173-29.475-29.476-40.194-70.598-32.173-108.552z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
color: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,74 +0,0 @@
|
||||
<template>
|
||||
<fieldset :id="label.toLowerCase()">
|
||||
<legend v-if="!noLegend" @click.prevent="collapse">
|
||||
<span>{{ label }}</span>
|
||||
<i class="ml-2 align-middle material-icons">
|
||||
{{ isCollapsed(label) ? "expand_more" : "expand_less" }}
|
||||
</i>
|
||||
</legend>
|
||||
<div
|
||||
class="collapsible"
|
||||
:class="{ hidden: isCollapsed(label.toLowerCase()) }"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</fieldset>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue"
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
label: {
|
||||
type: String,
|
||||
default: "Section",
|
||||
},
|
||||
noLegend: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
sectionString(): string {
|
||||
return `${this.$route.path.replace(/\/+$/, "")}/${this.label}`
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
collapse() {
|
||||
// Save collapsed section into the collapsedSections array
|
||||
this.$store.commit("setCollapsedSection", this.sectionString)
|
||||
},
|
||||
isCollapsed(_label: string) {
|
||||
return (
|
||||
this.$store.state.theme.collapsedSections.includes(
|
||||
this.sectionString
|
||||
) || false
|
||||
)
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
fieldset {
|
||||
@apply my-4;
|
||||
@apply rounded-lg;
|
||||
@apply bg-bgDarkColor;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
@apply w-full;
|
||||
|
||||
legend {
|
||||
@apply px-4;
|
||||
@apply text-fgColor;
|
||||
@apply font-bold;
|
||||
@apply cursor-pointer;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,102 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("shortcuts") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<div class="p-2">
|
||||
<div>
|
||||
<kbd>{{ getSpecialKey() }}</kbd>
|
||||
+
|
||||
<kbd>G</kbd>
|
||||
<label>{{ $t("send_request") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>{{ getSpecialKey() }}</kbd
|
||||
>+<kbd>S</kbd>
|
||||
<label>{{ $t("save_to_collections") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>{{ getSpecialKey() }}</kbd
|
||||
>+<kbd>K</kbd>
|
||||
<label>{{ $t("copy_request_link") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>{{ getSpecialKey() }}</kbd
|
||||
>+<kbd>I</kbd>
|
||||
<label>{{ $t("reset_request") }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="p-2">
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>▲</kbd>
|
||||
<label>{{ $t("select_next_method") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>▼</kbd>
|
||||
<label>{{ $t("select_previous_method") }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="p-2">
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>G</kbd>
|
||||
<label>{{ $t("select_get_method") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>H</kbd>
|
||||
<label>{{ $t("select_head_method") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>P</kbd>
|
||||
<label>{{ $t("select_post_method") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>U</kbd>
|
||||
<label>{{ $t("select_put_method") }}</label>
|
||||
</div>
|
||||
<div>
|
||||
<kbd>Alt</kbd>+<kbd>X</kbd>
|
||||
<label>{{ $t("select_delete_method") }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer"></div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getPlatformSpecialKey } from "~/helpers/platformutils"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
methods: {
|
||||
getSpecialKey: getPlatformSpecialKey,
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
kbd {
|
||||
@apply inline-flex;
|
||||
@apply resize-none;
|
||||
@apply m-2;
|
||||
@apply rounded-lg;
|
||||
@apply py-2;
|
||||
@apply px-4;
|
||||
@apply text-sm;
|
||||
}
|
||||
</style>
|
||||
@@ -1,307 +0,0 @@
|
||||
<template>
|
||||
<aside class="nav-first">
|
||||
<nav class="primary-nav">
|
||||
<!--
|
||||
We're using manual checks for linkActive because the query string
|
||||
seems to mess up the nuxt-link active class.
|
||||
-->
|
||||
<nuxt-link
|
||||
v-tooltip.right="$t('home')"
|
||||
:to="localePath('index')"
|
||||
:class="linkActive('/')"
|
||||
:aria-label="$t('home')"
|
||||
>
|
||||
<AppLogo alt class="material-icons" style="height: 24px" />
|
||||
</nuxt-link>
|
||||
<nuxt-link
|
||||
v-tooltip.right="$t('realtime')"
|
||||
:to="localePath('realtime')"
|
||||
:class="linkActive('/realtime')"
|
||||
>
|
||||
<i class="material-icons">language</i>
|
||||
</nuxt-link>
|
||||
<nuxt-link
|
||||
v-tooltip.right="$t('graphql')"
|
||||
:to="localePath('graphql')"
|
||||
:class="linkActive('/graphql')"
|
||||
:aria-label="$t('graphql')"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24"
|
||||
width="24"
|
||||
viewBox="0 0 29.999 30"
|
||||
>
|
||||
<path d="M4.08 22.864l-1.1-.636L15.248.98l1.1.636z" />
|
||||
<path d="M2.727 20.53h24.538v1.272H2.727z" />
|
||||
<path
|
||||
d="M15.486 28.332L3.213 21.246l.636-1.1 12.273 7.086zm10.662-18.47L13.874 2.777l.636-1.1 12.273 7.086z"
|
||||
/>
|
||||
<path d="M3.852 9.858l-.636-1.1L15.5 1.67l.636 1.1z" />
|
||||
<path
|
||||
d="M25.922 22.864l-12.27-21.25 1.1-.636 12.27 21.25zM3.7 7.914h1.272v14.172H3.7zm21.328 0H26.3v14.172h-1.272z"
|
||||
/>
|
||||
<path d="M15.27 27.793l-.555-.962 10.675-6.163.555.962z" />
|
||||
<path
|
||||
d="M27.985 22.5a2.68 2.68 0 01-3.654.981 2.68 2.68 0 01-.981-3.654 2.68 2.68 0 013.654-.981 2.665 2.665 0 01.98 3.654M6.642 10.174a2.68 2.68 0 01-3.654.981A2.68 2.68 0 012.007 7.5a2.68 2.68 0 013.654-.981 2.68 2.68 0 01.981 3.654M2.015 22.5a2.68 2.68 0 01.981-3.654 2.68 2.68 0 013.654.981 2.68 2.68 0 01-.981 3.654c-1.287.735-2.92.3-3.654-.98m21.343-12.326a2.68 2.68 0 01.981-3.654 2.68 2.68 0 013.654.981 2.68 2.68 0 01-.981 3.654 2.68 2.68 0 01-3.654-.981M15 30a2.674 2.674 0 112.674-2.673A2.68 2.68 0 0115 30m0-24.652a2.67 2.67 0 01-2.674-2.674 2.67 2.67 0 115.347 0A2.67 2.67 0 0115 5.347"
|
||||
/>
|
||||
</svg>
|
||||
</nuxt-link>
|
||||
<nuxt-link
|
||||
v-tooltip.right="$t('documentation')"
|
||||
:to="localePath('doc')"
|
||||
:class="linkActive('/doc')"
|
||||
:aria-label="$t('documentation')"
|
||||
>
|
||||
<i class="material-icons">topic</i>
|
||||
</nuxt-link>
|
||||
<nuxt-link
|
||||
v-tooltip.right="$t('settings')"
|
||||
:to="localePath('settings')"
|
||||
:class="linkActive('/settings')"
|
||||
:aria-label="$t('settings')"
|
||||
>
|
||||
<i class="material-icons">settings</i>
|
||||
</nuxt-link>
|
||||
</nav>
|
||||
<nav v-if="$route.path == '/'" class="secondary-nav">
|
||||
<a v-tooltip.right="$t('request')" href="#request">
|
||||
<i class="material-icons">cloud_upload</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('options')" href="#options">
|
||||
<i class="material-icons">toc</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('response')" href="#response">
|
||||
<i class="material-icons">cloud_download</i>
|
||||
</a>
|
||||
</nav>
|
||||
<nav v-else-if="$route.path.includes('/realtime')" class="secondary-nav">
|
||||
<a v-tooltip.right="$t('request')" href="#request">
|
||||
<i class="material-icons">cloud_upload</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('communication')" href="#response">
|
||||
<i class="material-icons">cloud_download</i>
|
||||
</a>
|
||||
</nav>
|
||||
<nav v-else-if="$route.path.includes('/graphql')" class="secondary-nav">
|
||||
<a v-tooltip.right="$t('endpoint')" href="#endpoint">
|
||||
<i class="material-icons">cloud</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('schema')" href="#schema">
|
||||
<i class="material-icons">assignment_returned</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('query')" href="#query">
|
||||
<i class="material-icons">cloud_upload</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('response')" href="#response">
|
||||
<i class="material-icons">cloud_download</i>
|
||||
</a>
|
||||
</nav>
|
||||
<nav v-else-if="$route.path.includes('/doc')" class="secondary-nav">
|
||||
<a v-tooltip.right="$t('import')" href="#import">
|
||||
<i class="material-icons">folder</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('documentation')" href="#documentation">
|
||||
<i class="material-icons">insert_drive_file</i>
|
||||
</a>
|
||||
</nav>
|
||||
<nav v-else-if="$route.path.includes('/settings')" class="secondary-nav">
|
||||
<a v-tooltip.right="$t('account')" href="#account">
|
||||
<i class="material-icons">person</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('theme')" href="#theme">
|
||||
<i class="material-icons">brush</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('extensions')" href="#extensions">
|
||||
<i class="material-icons">extension</i>
|
||||
</a>
|
||||
<a v-tooltip.right="$t('proxy')" href="#proxy">
|
||||
<i class="material-icons">public</i>
|
||||
</a>
|
||||
</nav>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
mounted() {
|
||||
window.addEventListener("scroll", () => {
|
||||
const mainNavLinks = document.querySelectorAll("nav.secondary-nav a")
|
||||
const fromTop = window.scrollY
|
||||
mainNavLinks.forEach(({ hash, classList }) => {
|
||||
const section = document.querySelector(hash)
|
||||
if (
|
||||
section &&
|
||||
section.offsetTop <= fromTop &&
|
||||
section.offsetTop + section.offsetHeight > fromTop
|
||||
) {
|
||||
classList.add("current")
|
||||
} else {
|
||||
classList.remove("current")
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
linkActive(path) {
|
||||
return {
|
||||
"nuxt-link-exact-active": this.$route.path === path,
|
||||
"nuxt-link-active": this.$route.path === path,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$responsiveWidth: 768px;
|
||||
|
||||
.nav-first {
|
||||
@apply z-10;
|
||||
@apply h-screen;
|
||||
@apply p-2;
|
||||
@apply bg-bgDarkColor;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
@apply space-y-2;
|
||||
}
|
||||
|
||||
nav.primary-nav {
|
||||
@apply flex;
|
||||
@apply flex-col;
|
||||
@apply flex-nowrap;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply space-y-2;
|
||||
@apply w-full;
|
||||
|
||||
svg {
|
||||
@apply fill-current;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply inline-flex;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply flex-shrink-0;
|
||||
@apply p-4;
|
||||
@apply rounded-full;
|
||||
@apply bg-bgLightColor;
|
||||
@apply text-fgLightColor;
|
||||
@apply fill-current;
|
||||
@apply outline-none;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
|
||||
&:hover {
|
||||
@apply text-fgColor;
|
||||
@apply fill-current;
|
||||
|
||||
svg {
|
||||
@apply fill-current;
|
||||
}
|
||||
}
|
||||
|
||||
&.nuxt-link-exact-active {
|
||||
@apply bg-acColor;
|
||||
@apply text-actColor;
|
||||
@apply fill-current;
|
||||
|
||||
border-radius: 16px;
|
||||
|
||||
svg {
|
||||
@apply fill-current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nav.primary-nav::-webkit-scrollbar,
|
||||
.nav-first::-webkit-scrollbar {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
nav.secondary-nav {
|
||||
@apply flex;
|
||||
@apply flex-col;
|
||||
@apply flex-nowrap;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply border-t-2;
|
||||
@apply border-dashed;
|
||||
@apply border-brdColor;
|
||||
@apply pt-2;
|
||||
@apply space-y-2;
|
||||
|
||||
a {
|
||||
@apply inline-flex;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply flex-shrink-0;
|
||||
@apply p-4;
|
||||
@apply rounded-full;
|
||||
@apply bg-bgDarkColor;
|
||||
@apply text-fgLightColor;
|
||||
@apply fill-current;
|
||||
@apply outline-none;
|
||||
@apply transition;
|
||||
@apply ease-in-out;
|
||||
@apply duration-150;
|
||||
|
||||
&:hover {
|
||||
@apply text-fgColor;
|
||||
@apply fill-current;
|
||||
}
|
||||
|
||||
&.current {
|
||||
@apply text-acColor;
|
||||
@apply fill-current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $responsiveWidth) {
|
||||
.nav-first {
|
||||
@apply fixed;
|
||||
@apply top-auto;
|
||||
@apply bottom-0;
|
||||
@apply h-auto;
|
||||
@apply p-0;
|
||||
@apply w-full;
|
||||
@apply bg-bgColor;
|
||||
@apply shadow-2xl;
|
||||
}
|
||||
|
||||
nav.primary-nav {
|
||||
@apply flex-row;
|
||||
@apply flex-nowrap;
|
||||
@apply overflow-auto;
|
||||
@apply bg-bgDarkColor;
|
||||
@apply space-y-0;
|
||||
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
a {
|
||||
@apply bg-transparent;
|
||||
@apply my-2;
|
||||
@apply flex-1;
|
||||
|
||||
&.nuxt-link-exact-active {
|
||||
@apply bg-transparent;
|
||||
@apply text-acColor;
|
||||
@apply fill-current;
|
||||
|
||||
svg {
|
||||
@apply fill-current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nav.secondary-nav {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,31 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("support_us") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<AppContributors />
|
||||
</div>
|
||||
<div slot="footer"></div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
methods: {
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,60 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("new_collection") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="$t('my_new_collection')"
|
||||
@keyup.enter="addNewCollection"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="addNewCollection">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addNewCollection() {
|
||||
this.$emit("submit", this.name)
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,67 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="$emit('hide-modal')">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("new_folder") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="$t('my_new_folder')"
|
||||
@keyup.enter="addFolder"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="addFolder">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
folder: { type: Object, default: () => {} },
|
||||
folderPath: { type: String, default: null },
|
||||
collectionIndex: { type: Number, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addFolder() {
|
||||
this.$emit("add-folder", {
|
||||
name: this.name,
|
||||
folder: this.folder,
|
||||
path: this.folderPath || `${this.collectionIndex}`,
|
||||
})
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,105 +0,0 @@
|
||||
<template>
|
||||
<div v-if="show">
|
||||
<SmartTabs
|
||||
:id="'collections_tab'"
|
||||
styles="m-4"
|
||||
@tab-changed="updateCollectionsType"
|
||||
>
|
||||
<SmartTab
|
||||
:id="'my-collections'"
|
||||
:label="'My Collections'"
|
||||
:selected="true"
|
||||
/>
|
||||
<SmartTab
|
||||
v-if="currentUser && currentUser.eaInvited && !doc"
|
||||
:id="'team-collections'"
|
||||
:label="'Team Collections'"
|
||||
>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="select-wrapper">
|
||||
<SmartIntersection @intersecting="onTeamSelectIntersect">
|
||||
<select
|
||||
id="team"
|
||||
type="text"
|
||||
class="team"
|
||||
autofocus
|
||||
@change="updateSelectedTeam(myTeams[$event.target.value])"
|
||||
>
|
||||
<option
|
||||
:key="undefined"
|
||||
:value="undefined"
|
||||
hidden
|
||||
disabled
|
||||
selected
|
||||
>
|
||||
Select team
|
||||
</option>
|
||||
<option
|
||||
v-for="(team, index) in myTeams"
|
||||
:key="index"
|
||||
:value="index"
|
||||
>
|
||||
{{ team.name }}
|
||||
</option>
|
||||
</select>
|
||||
</SmartIntersection>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</SmartTab>
|
||||
</SmartTabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from "graphql-tag"
|
||||
import { currentUserInfo$ } from "~/helpers/teams/BackendUserInfo"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
doc: Boolean,
|
||||
show: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
skipTeamsFetching: true,
|
||||
}
|
||||
},
|
||||
subscriptions() {
|
||||
return {
|
||||
currentUser: currentUserInfo$,
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
myTeams: {
|
||||
query: gql`
|
||||
query GetMyTeams {
|
||||
myTeams {
|
||||
id
|
||||
name
|
||||
myRole
|
||||
}
|
||||
}
|
||||
`,
|
||||
pollInterval: 10000,
|
||||
skip() {
|
||||
return this.skipTeamsFetching
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onTeamSelectIntersect() {
|
||||
// Load team data as soon as intersection
|
||||
this.$apollo.queries.myTeams.refetch()
|
||||
this.skipTeamsFetching = false
|
||||
},
|
||||
updateCollectionsType(tabID) {
|
||||
this.$emit("update-collection-type", tabID)
|
||||
},
|
||||
updateSelectedTeam(team) {
|
||||
this.$emit("update-selected-team", team)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,61 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_collection") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="placeholderCollName"
|
||||
@keyup.enter="saveCollection"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="saveCollection">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
placeholderCollName: { type: String, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
saveCollection() {
|
||||
this.$emit("submit", this.name)
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,59 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="$emit('hide-modal')">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_folder") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
@keyup.enter="editFolder"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="editFolder">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editFolder() {
|
||||
this.$emit("submit", this.name)
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_request") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="requestUpdateData.name"
|
||||
type="text"
|
||||
:placeholder="placeholderReqName"
|
||||
@keyup.enter="saveRequest"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="saveRequest">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
placeholderReqName: { type: String, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
requestUpdateData: {
|
||||
name: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
saveRequest() {
|
||||
this.$emit("submit", this.requestUpdateData)
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.requestUpdateData = { name: null }
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,262 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("save_request_as") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("token_req_name") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="requestData.name"
|
||||
type="text"
|
||||
@keyup.enter="saveRequestAs"
|
||||
/>
|
||||
<label for="selectLabel">Select location</label>
|
||||
<!-- <input readonly :value="path" /> -->
|
||||
<Collections
|
||||
:picked="picked"
|
||||
:save-request="true"
|
||||
@select="onSelect"
|
||||
@update-collection="collectionsType.type = $event"
|
||||
@update-coll-type="onUpdateCollType"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="saveRequestAs">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
import { getSettingSubject } from "~/newstore/settings"
|
||||
import * as teamUtils from "~/helpers/teams/utils"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
editingRequest: { type: Object, default: () => {} },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultRequestName: "Untitled Request",
|
||||
path: "Path will appear here",
|
||||
requestData: {
|
||||
name: undefined,
|
||||
collectionIndex: undefined,
|
||||
folderName: undefined,
|
||||
requestIndex: undefined,
|
||||
},
|
||||
collectionsType: {
|
||||
type: "my-collections",
|
||||
selectedTeam: undefined,
|
||||
},
|
||||
picked: null,
|
||||
}
|
||||
},
|
||||
subscriptions() {
|
||||
return {
|
||||
SYNC_COLLECTIONS: getSettingSubject("syncCollections"),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
folders() {
|
||||
const collections = this.$store.state.postwoman.collections
|
||||
const collectionIndex = this.$data.requestData.collectionIndex
|
||||
const userSelectedAnyCollection = collectionIndex !== undefined
|
||||
if (!userSelectedAnyCollection) return []
|
||||
|
||||
const noCollectionAvailable = collections[collectionIndex] !== undefined
|
||||
if (!noCollectionAvailable) return []
|
||||
|
||||
return getFolderNames(collections[collectionIndex].folders, [])
|
||||
},
|
||||
requests() {
|
||||
const collections = this.$store.state.postwoman.collections
|
||||
const collectionIndex = this.$data.requestData.collectionIndex
|
||||
const folderName = this.$data.requestData.folderName
|
||||
|
||||
const userSelectedAnyCollection = collectionIndex !== undefined
|
||||
if (!userSelectedAnyCollection) {
|
||||
return []
|
||||
}
|
||||
|
||||
const userSelectedAnyFolder =
|
||||
folderName !== undefined && folderName !== ""
|
||||
|
||||
if (userSelectedAnyFolder) {
|
||||
const collection = collections[collectionIndex]
|
||||
const folder = findFolder(folderName, collection)
|
||||
return folder.requests
|
||||
} else {
|
||||
const collection = collections[collectionIndex]
|
||||
const noCollectionAvailable = collection !== undefined
|
||||
|
||||
if (!noCollectionAvailable) {
|
||||
return []
|
||||
}
|
||||
|
||||
return collection.requests
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
"requestData.collectionIndex": function resetFolderAndRequestIndex() {
|
||||
// if user has chosen some folder, than selected other collection, which doesn't have any folders
|
||||
// than `requestUpdateData.folderName` won't be reseted
|
||||
this.$data.requestData.folderName = undefined
|
||||
this.$data.requestData.requestIndex = undefined
|
||||
},
|
||||
"requestData.folderName": function resetRequestIndex() {
|
||||
this.$data.requestData.requestIndex = undefined
|
||||
},
|
||||
editingRequest({ name }) {
|
||||
this.$data.requestData.name = name || this.$data.defaultRequestName
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onUpdateCollType(newCollType) {
|
||||
this.collectionsType = newCollType
|
||||
},
|
||||
onSelect({ picked }) {
|
||||
this.picked = picked
|
||||
},
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && this.SYNC_COLLECTIONS) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(JSON.stringify(this.$store.state.postwoman.collections)),
|
||||
"collections"
|
||||
)
|
||||
}
|
||||
},
|
||||
saveRequestAs() {
|
||||
if (this.picked == null) {
|
||||
this.$toast.error(this.$t("select_collection"), {
|
||||
icon: "error",
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.$data.requestData.name.length === 0) {
|
||||
this.$toast.error(this.$t("empty_req_name"), {
|
||||
icon: "error",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const requestUpdated = {
|
||||
...this.$props.editingRequest,
|
||||
name: this.$data.requestData.name,
|
||||
collection: this.$data.requestData.collectionIndex,
|
||||
}
|
||||
|
||||
if (this.picked.pickedType === "my-request") {
|
||||
this.$store.commit("postwoman/saveRequestAs", {
|
||||
request: requestUpdated,
|
||||
collectionIndex: this.picked.collectionIndex,
|
||||
folderName: this.picked.folderName,
|
||||
requestIndex: this.picked.requestIndex,
|
||||
flag: "rest",
|
||||
})
|
||||
|
||||
this.syncCollections()
|
||||
} else if (this.picked.pickedType === "my-folder") {
|
||||
this.$store.commit("postwoman/saveRequestAs", {
|
||||
request: requestUpdated,
|
||||
collectionIndex: this.picked.collectionIndex,
|
||||
folderName: this.picked.folderName,
|
||||
flag: "rest",
|
||||
})
|
||||
|
||||
this.syncCollections()
|
||||
} else if (this.picked.pickedType === "my-collection") {
|
||||
this.$store.commit("postwoman/saveRequestAs", {
|
||||
request: requestUpdated,
|
||||
collectionIndex: this.picked.collectionIndex,
|
||||
flag: "rest",
|
||||
})
|
||||
|
||||
this.syncCollections()
|
||||
} else if (this.picked.pickedType === "teams-request") {
|
||||
teamUtils.overwriteRequestTeams(
|
||||
this.$apollo,
|
||||
JSON.stringify(requestUpdated),
|
||||
requestUpdated.name,
|
||||
this.picked.requestID
|
||||
)
|
||||
} else if (this.picked.pickedType === "teams-folder") {
|
||||
teamUtils.saveRequestAsTeams(
|
||||
this.$apollo,
|
||||
JSON.stringify(requestUpdated),
|
||||
requestUpdated.name,
|
||||
this.collectionsType.selectedTeam.id,
|
||||
this.picked.folderID
|
||||
)
|
||||
} else if (this.picked.pickedType === "teams-collection") {
|
||||
teamUtils.saveRequestAsTeams(
|
||||
this.$apollo,
|
||||
JSON.stringify(requestUpdated),
|
||||
requestUpdated.name,
|
||||
this.collectionsType.selectedTeam.id,
|
||||
this.picked.collectionID
|
||||
)
|
||||
}
|
||||
this.$toast.success("Requested added", {
|
||||
icon: "done",
|
||||
})
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
function getFolderNames(folders, namesList, folderName = "") {
|
||||
if (folders.length) {
|
||||
folders.forEach((folder) => {
|
||||
namesList.push(folderName + folder.name)
|
||||
if (folder.folders && folder.folders.length) {
|
||||
getFolderNames(folder.folders, namesList, folder.name + "/")
|
||||
}
|
||||
})
|
||||
}
|
||||
return namesList
|
||||
}
|
||||
|
||||
function findFolder(folderName, currentFolder) {
|
||||
let selectedFolder
|
||||
let result
|
||||
|
||||
if (folderName === currentFolder.name) {
|
||||
return currentFolder
|
||||
}
|
||||
|
||||
for (let i = 0; i < currentFolder.folders.length; i++) {
|
||||
selectedFolder = currentFolder.folders[i]
|
||||
|
||||
result = findFolder(folderName, selectedFolder)
|
||||
|
||||
if (result !== false) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
</script>
|
||||
@@ -1,82 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("new_collection") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="$t('my_new_collection')"
|
||||
@keyup.enter="addNewCollection"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="addNewCollection">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
addNewCollection() {
|
||||
if (!this.$data.name) {
|
||||
this.$toast.info(this.$t("invalid_collection_name"))
|
||||
return
|
||||
}
|
||||
this.$store.commit("postwoman/addNewCollection", {
|
||||
name: this.$data.name,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.syncCollections()
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,82 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="$emit('hide-modal')">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("new_folder") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="$t('my_new_folder')"
|
||||
@keyup.enter="addFolder"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="addFolder">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
folder: { type: Object, default: () => {} },
|
||||
folderPath: { type: String, default: null },
|
||||
collectionIndex: { type: Number, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
addFolder() {
|
||||
this.$emit("add-folder", {
|
||||
name: this.name,
|
||||
folder: this.folder,
|
||||
path: this.folderPath || `${this.collectionIndex}`,
|
||||
})
|
||||
this.syncCollections()
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,203 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:class="[
|
||||
'row-wrapper transition duration-150 ease-in-out',
|
||||
{ 'bg-bgDarkColor': dragging },
|
||||
]"
|
||||
@dragover.prevent
|
||||
@drop.prevent="dropEvent"
|
||||
@dragover="dragging = true"
|
||||
@drop="dragging = false"
|
||||
@dragleave="dragging = false"
|
||||
@dragend="dragging = false"
|
||||
>
|
||||
<button class="icon" @click="toggleShowChildren">
|
||||
<i v-show="!showChildren && !isFiltered" class="material-icons"
|
||||
>arrow_right</i
|
||||
>
|
||||
<i v-show="showChildren || isFiltered" class="material-icons"
|
||||
>arrow_drop_down</i
|
||||
>
|
||||
<i class="material-icons">folder</i>
|
||||
<span>{{ collection.name }}</span>
|
||||
</button>
|
||||
<div>
|
||||
<button
|
||||
v-if="doc"
|
||||
v-tooltip.left="$t('import')"
|
||||
class="icon"
|
||||
@click="$emit('select-collection')"
|
||||
>
|
||||
<i class="material-icons">topic</i>
|
||||
</button>
|
||||
<v-popover>
|
||||
<button v-tooltip.left="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="
|
||||
$emit('add-folder', {
|
||||
folder: collection,
|
||||
path: `${collectionIndex}`,
|
||||
})
|
||||
"
|
||||
>
|
||||
<i class="material-icons">create_new_folder</i>
|
||||
<span>{{ $t("new_folder") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="$emit('edit-collection')"
|
||||
>
|
||||
<i class="material-icons">create</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="confirmRemove = true"
|
||||
>
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="showChildren || isFiltered">
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(folder, index) in collection.folders"
|
||||
:key="folder.name"
|
||||
class="ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsGraphqlFolder
|
||||
:folder="folder"
|
||||
:folder-index="index"
|
||||
:folder-path="`${collectionIndex}/${index}`"
|
||||
:collection-index="collectionIndex"
|
||||
:doc="doc"
|
||||
:is-filtered="isFiltered"
|
||||
@add-folder="$emit('add-folder', $event)"
|
||||
@edit-folder="$emit('edit-folder', $event)"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(request, index) in collection.requests"
|
||||
:key="index"
|
||||
class="ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsGraphqlRequest
|
||||
:request="request"
|
||||
:collection-index="collectionIndex"
|
||||
:folder-index="-1"
|
||||
:folder-name="collection.name"
|
||||
:request-index="index"
|
||||
:doc="doc"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li
|
||||
v-if="
|
||||
collection.folders.length === 0 && collection.requests.length === 0
|
||||
"
|
||||
class="flex ml-8 border-l border-brdColor"
|
||||
>
|
||||
<p class="info">
|
||||
<i class="material-icons">not_interested</i>
|
||||
{{ $t("collection_empty") }}
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_collection')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeCollection"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
collectionIndex: { type: Number, default: null },
|
||||
collection: { type: Object, default: () => {} },
|
||||
doc: Boolean,
|
||||
isFiltered: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showChildren: false,
|
||||
dragging: false,
|
||||
selectedFolder: {},
|
||||
confirmRemove: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleShowChildren() {
|
||||
this.showChildren = !this.showChildren
|
||||
},
|
||||
removeCollection() {
|
||||
this.$store.commit("postwoman/removeCollection", {
|
||||
collectionIndex: this.collectionIndex,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
})
|
||||
this.syncCollections()
|
||||
},
|
||||
dropEvent({ dataTransfer }) {
|
||||
this.dragging = !this.dragging
|
||||
const oldCollectionIndex = dataTransfer.getData("oldCollectionIndex")
|
||||
const oldFolderIndex = dataTransfer.getData("oldFolderIndex")
|
||||
const oldFolderName = dataTransfer.getData("oldFolderName")
|
||||
const requestIndex = dataTransfer.getData("requestIndex")
|
||||
const flag = "graphql"
|
||||
this.$store.commit("postwoman/moveRequest", {
|
||||
oldCollectionIndex,
|
||||
newCollectionIndex: this.$props.collectionIndex,
|
||||
newFolderIndex: -1,
|
||||
newFolderName: this.$props.collection.name,
|
||||
oldFolderIndex,
|
||||
oldFolderName,
|
||||
requestIndex,
|
||||
flag,
|
||||
})
|
||||
this.syncCollections()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,89 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_collection") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="editingCollection.name"
|
||||
@keyup.enter="saveCollection"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="saveCollection">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
editingCollection: { type: Object, default: () => {} },
|
||||
editingCollectionIndex: { type: Number, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
saveCollection() {
|
||||
if (!this.$data.name) {
|
||||
this.$toast.info(this.$t("invalid_collection_name"))
|
||||
return
|
||||
}
|
||||
const collectionUpdated = {
|
||||
...this.$props.editingCollection,
|
||||
name: this.$data.name,
|
||||
}
|
||||
this.$store.commit("postwoman/editCollection", {
|
||||
collection: collectionUpdated,
|
||||
collectionIndex: this.$props.editingCollectionIndex,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.syncCollections()
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,84 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="$emit('hide-modal')">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_folder") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="folder.name"
|
||||
@keyup.enter="editFolder"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="editFolder">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
collectionIndex: { type: Number, default: null },
|
||||
folder: { type: Object, default: () => {} },
|
||||
folderIndex: { type: Number, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
editFolder() {
|
||||
this.$store.commit("postwoman/editFolder", {
|
||||
collectionIndex: this.$props.collectionIndex,
|
||||
folder: { ...this.$props.folder, name: this.$data.name },
|
||||
folderIndex: this.$props.folderIndex,
|
||||
folderName: this.$props.folder.name,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.syncCollections()
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,94 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_request") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="requestUpdateData.name"
|
||||
type="text"
|
||||
:placeholder="request.name"
|
||||
@keyup.enter="saveRequest"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="saveRequest">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
collectionIndex: { type: Number, default: null },
|
||||
folderIndex: { type: Number, default: null },
|
||||
folderName: { type: String, default: null },
|
||||
request: { type: Object, default: () => {} },
|
||||
requestIndex: { type: Number, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
requestUpdateData: {
|
||||
name: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
saveRequest() {
|
||||
const requestUpdated = {
|
||||
...this.$props.request,
|
||||
name: this.$data.requestUpdateData.name || this.$props.request.name,
|
||||
}
|
||||
|
||||
this.$store.commit("postwoman/editRequest", {
|
||||
requestCollectionIndex: this.$props.collectionIndex,
|
||||
requestFolderName: this.$props.folderName,
|
||||
requestFolderIndex: this.$props.folderIndex,
|
||||
requestNew: requestUpdated,
|
||||
requestIndex: this.$props.requestIndex,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.syncCollections()
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.requestUpdateData = { name: null }
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,195 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:class="[
|
||||
'row-wrapper transition duration-150 ease-in-out',
|
||||
{ 'bg-bgDarkColor': dragging },
|
||||
]"
|
||||
@dragover.prevent
|
||||
@drop.prevent="dropEvent"
|
||||
@dragover="dragging = true"
|
||||
@drop="dragging = false"
|
||||
@dragleave="dragging = false"
|
||||
@dragend="dragging = false"
|
||||
>
|
||||
<div>
|
||||
<button class="icon" @click="toggleShowChildren">
|
||||
<i v-show="!showChildren && !isFiltered" class="material-icons"
|
||||
>arrow_right</i
|
||||
>
|
||||
<i v-show="showChildren || isFiltered" class="material-icons"
|
||||
>arrow_drop_down</i
|
||||
>
|
||||
<i class="material-icons">folder_open</i>
|
||||
<span>{{ folder.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<v-popover>
|
||||
<button v-tooltip.left="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="$emit('add-folder', { folder, path: folderPath })"
|
||||
>
|
||||
<i class="material-icons">create_new_folder</i>
|
||||
<span>{{ $t("new_folder") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="
|
||||
$emit('edit-folder', { folder, folderIndex, collectionIndex })
|
||||
"
|
||||
>
|
||||
<i class="material-icons">edit</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button v-close-popover class="icon" @click="confirmRemove = true">
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<div v-show="showChildren || isFiltered">
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(subFolder, subFolderIndex) in folder.folders"
|
||||
:key="subFolder.name"
|
||||
class="ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsGraphqlFolder
|
||||
:folder="subFolder"
|
||||
:folder-index="subFolderIndex"
|
||||
:folder-path="`${folderPath}/${subFolderIndex}`"
|
||||
:collection-index="collectionIndex"
|
||||
:doc="doc"
|
||||
:is-filtered="isFiltered"
|
||||
@add-folder="$emit('add-folder', $event)"
|
||||
@edit-folder="$emit('edit-folder', $event)"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(request, index) in folder.requests"
|
||||
:key="index"
|
||||
class="flex ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsGraphqlRequest
|
||||
:request="request"
|
||||
:collection-index="collectionIndex"
|
||||
:folder-index="folderIndex"
|
||||
:folder-name="folder.name"
|
||||
:request-index="index"
|
||||
:doc="doc"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul
|
||||
v-if="
|
||||
folder.folders &&
|
||||
folder.folders.length === 0 &&
|
||||
folder.requests &&
|
||||
folder.requests.length === 0
|
||||
"
|
||||
>
|
||||
<li class="flex ml-8 border-l border-brdColor">
|
||||
<p class="info">
|
||||
<i class="material-icons">not_interested</i>
|
||||
{{ $t("folder_empty") }}
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_folder')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeFolder"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
name: "Folder",
|
||||
props: {
|
||||
folder: { type: Object, default: () => {} },
|
||||
folderIndex: { type: Number, default: null },
|
||||
collectionIndex: { type: Number, default: null },
|
||||
folderPath: { type: String, default: null },
|
||||
doc: Boolean,
|
||||
isFiltered: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showChildren: false,
|
||||
dragging: false,
|
||||
confirmRemove: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleShowChildren() {
|
||||
this.showChildren = !this.showChildren
|
||||
},
|
||||
removeFolder() {
|
||||
this.$store.commit("postwoman/removeFolder", {
|
||||
collectionIndex: this.$props.collectionIndex,
|
||||
folderName: this.$props.folder.name,
|
||||
folderIndex: this.$props.folderIndex,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.syncCollections()
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
})
|
||||
},
|
||||
dropEvent({ dataTransfer }) {
|
||||
this.dragging = !this.dragging
|
||||
const oldCollectionIndex = dataTransfer.getData("oldCollectionIndex")
|
||||
const oldFolderIndex = dataTransfer.getData("oldFolderIndex")
|
||||
const oldFolderName = dataTransfer.getData("oldFolderName")
|
||||
const requestIndex = dataTransfer.getData("requestIndex")
|
||||
const flag = "graphql"
|
||||
|
||||
this.$store.commit("postwoman/moveRequest", {
|
||||
oldCollectionIndex,
|
||||
newCollectionIndex: this.$props.collectionIndex,
|
||||
newFolderIndex: this.$props.folderIndex,
|
||||
newFolderName: this.$props.folder.name,
|
||||
oldFolderIndex,
|
||||
oldFolderName,
|
||||
requestIndex,
|
||||
flag,
|
||||
})
|
||||
this.syncCollections()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,123 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:class="[
|
||||
'row-wrapper transition duration-150 ease-in-out',
|
||||
{ 'bg-bgDarkColor': dragging },
|
||||
]"
|
||||
draggable="true"
|
||||
@dragstart="dragStart"
|
||||
@dragover.stop
|
||||
@dragleave="dragging = false"
|
||||
@dragend="dragging = false"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
v-tooltip="!doc ? $t('use_request') : ''"
|
||||
class="icon"
|
||||
@click="!doc ? selectRequest() : {}"
|
||||
>
|
||||
<i class="material-icons">description</i>
|
||||
<span>{{ request.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<v-popover>
|
||||
<button v-tooltip="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="
|
||||
$emit('edit-request', {
|
||||
collectionIndex,
|
||||
folderIndex,
|
||||
folderName,
|
||||
request,
|
||||
requestIndex,
|
||||
})
|
||||
"
|
||||
>
|
||||
<i class="material-icons">edit</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button v-close-popover class="icon" @click="confirmRemove = true">
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_request')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeRequest"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
request: { type: Object, default: () => {} },
|
||||
collectionIndex: { type: Number, default: null },
|
||||
folderIndex: { type: Number, default: null },
|
||||
folderName: { type: String, default: null },
|
||||
requestIndex: { type: Number, default: null },
|
||||
doc: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dragging: false,
|
||||
confirmRemove: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
selectRequest() {
|
||||
this.$store.commit("postwoman/selectGraphqlRequest", {
|
||||
request: this.request,
|
||||
})
|
||||
},
|
||||
dragStart({ dataTransfer }) {
|
||||
this.dragging = !this.dragging
|
||||
dataTransfer.setData("oldCollectionIndex", this.$props.collectionIndex)
|
||||
dataTransfer.setData("oldFolderIndex", this.$props.folderIndex)
|
||||
dataTransfer.setData("oldFolderName", this.$props.folderName)
|
||||
dataTransfer.setData("requestIndex", this.$props.requestIndex)
|
||||
},
|
||||
removeRequest() {
|
||||
this.$store.commit("postwoman/removeRequest", {
|
||||
collectionIndex: this.$props.collectionIndex,
|
||||
folderName: this.$props.folderName,
|
||||
requestIndex: this.$props.requestIndex,
|
||||
flag: "graphql",
|
||||
})
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
})
|
||||
this.confirmRemove = false
|
||||
this.syncCollections()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,253 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("save_request_as") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("token_req_name") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="requestData.name"
|
||||
type="text"
|
||||
@keyup.enter="saveRequestAs"
|
||||
/>
|
||||
<ul>
|
||||
<li>
|
||||
<label for="selectCollection">{{ $t("collection") }}</label>
|
||||
<span class="select-wrapper">
|
||||
<select
|
||||
id="selectCollection"
|
||||
v-model="requestData.collectionIndex"
|
||||
type="text"
|
||||
>
|
||||
<option
|
||||
:key="undefined"
|
||||
:value="undefined"
|
||||
hidden
|
||||
disabled
|
||||
selected
|
||||
>
|
||||
{{ $t("select_collection") }}
|
||||
</option>
|
||||
<option
|
||||
v-for="(collection, index) in $store.state.postwoman
|
||||
.collectionsGraphql"
|
||||
:key="index"
|
||||
:value="index"
|
||||
>
|
||||
{{ collection.name }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<label>{{ $t("folder") }}</label>
|
||||
<SmartAutoComplete
|
||||
v-model="requestData.folderName"
|
||||
:placeholder="$t('search')"
|
||||
:source="folders"
|
||||
:spellcheck="false"
|
||||
/>
|
||||
<ul>
|
||||
<li>
|
||||
<label for="selectRequest">{{ $t("request") }}</label>
|
||||
<span class="select-wrapper">
|
||||
<select
|
||||
id="selectRequest"
|
||||
v-model="requestData.requestIndex"
|
||||
type="text"
|
||||
>
|
||||
<option :key="undefined" :value="undefined">/</option>
|
||||
<option
|
||||
v-for="(folder, index) in requests"
|
||||
:key="index"
|
||||
:value="index"
|
||||
>
|
||||
{{ folder.name }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="saveRequestAs">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
editingRequest: { type: Object, default: () => {} },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultRequestName: "Untitled Request",
|
||||
requestData: {
|
||||
name: undefined,
|
||||
collectionIndex: undefined,
|
||||
folderName: undefined,
|
||||
requestIndex: undefined,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
folders() {
|
||||
const collections = this.$store.state.postwoman.collectionsGraphql
|
||||
const collectionIndex = this.$data.requestData.collectionIndex
|
||||
const userSelectedAnyCollection = collectionIndex !== undefined
|
||||
if (!userSelectedAnyCollection) return []
|
||||
|
||||
const noCollectionAvailable = collections[collectionIndex] !== undefined
|
||||
if (!noCollectionAvailable) return []
|
||||
|
||||
return getFolderNames(collections[collectionIndex].folders, [])
|
||||
},
|
||||
requests() {
|
||||
const collections = this.$store.state.postwoman.collectionsGraphql
|
||||
const collectionIndex = this.$data.requestData.collectionIndex
|
||||
const folderName = this.$data.requestData.folderName
|
||||
|
||||
const userSelectedAnyCollection = collectionIndex !== undefined
|
||||
if (!userSelectedAnyCollection) {
|
||||
return []
|
||||
}
|
||||
|
||||
const userSelectedAnyFolder =
|
||||
folderName !== undefined && folderName !== ""
|
||||
|
||||
if (userSelectedAnyFolder) {
|
||||
const collection = collections[collectionIndex]
|
||||
const folder = findFolder(folderName, collection)
|
||||
return folder.requests
|
||||
} else {
|
||||
const collection = collections[collectionIndex]
|
||||
const noCollectionAvailable = collection !== undefined
|
||||
|
||||
if (!noCollectionAvailable) {
|
||||
return []
|
||||
}
|
||||
|
||||
return collection.requests
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
"requestData.collectionIndex": function resetFolderAndRequestIndex() {
|
||||
// if user has chosen some folder, than selected other collection, which doesn't have any folders
|
||||
// than `requestUpdateData.folderName` won't be reseted
|
||||
this.$data.requestData.folderName = undefined
|
||||
this.$data.requestData.requestIndex = undefined
|
||||
},
|
||||
"requestData.folderName": function resetRequestIndex() {
|
||||
this.$data.requestData.requestIndex = undefined
|
||||
},
|
||||
editingRequest({ name }) {
|
||||
this.$data.requestData.name = name || this.$data.defaultRequestName
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && fb.currentSettings[0]) {
|
||||
if (fb.currentSettings[0].value) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(
|
||||
JSON.stringify(this.$store.state.postwoman.collectionsGraphql)
|
||||
),
|
||||
"collectionsGraphql"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
saveRequestAs() {
|
||||
const userDidntSpecifyCollection =
|
||||
this.$data.requestData.collectionIndex === undefined
|
||||
if (userDidntSpecifyCollection) {
|
||||
this.$toast.error(this.$t("select_collection"), {
|
||||
icon: "error",
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.$data.requestData.name.length === 0) {
|
||||
this.$toast.error(this.$t("empty_req_name"), {
|
||||
icon: "error",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const requestUpdated = {
|
||||
...this.$props.editingRequest,
|
||||
name: this.$data.requestData.name,
|
||||
collection: this.$data.requestData.collectionIndex,
|
||||
}
|
||||
|
||||
this.$store.commit("postwoman/saveRequestAs", {
|
||||
request: requestUpdated,
|
||||
collectionIndex: this.$data.requestData.collectionIndex,
|
||||
folderName: this.$data.requestData.folderName,
|
||||
requestIndex: this.$data.requestData.requestIndex,
|
||||
flag: "graphql",
|
||||
})
|
||||
|
||||
this.hideModal()
|
||||
this.syncCollections()
|
||||
},
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
function getFolderNames(folders, namesList) {
|
||||
if (folders.length) {
|
||||
folders.forEach((folder) => {
|
||||
namesList.push(folder.name)
|
||||
if (folder.folders && folder.folders.length) {
|
||||
getFolderNames(folder.folders, namesList)
|
||||
}
|
||||
})
|
||||
}
|
||||
return namesList
|
||||
}
|
||||
|
||||
function findFolder(folderName, currentFolder) {
|
||||
let selectedFolder
|
||||
let result
|
||||
|
||||
if (folderName === currentFolder.name) {
|
||||
return currentFolder
|
||||
}
|
||||
|
||||
for (let i = 0; i < currentFolder.folders.length; i++) {
|
||||
selectedFolder = currentFolder.folders[i]
|
||||
|
||||
result = findFolder(folderName, selectedFolder)
|
||||
|
||||
if (result !== false) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
</script>
|
||||
@@ -1,265 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:class="[
|
||||
'row-wrapper transition duration-150 ease-in-out',
|
||||
{ 'bg-bgDarkColor': dragging },
|
||||
]"
|
||||
@dragover.prevent
|
||||
@drop.prevent="dropEvent"
|
||||
@dragover="dragging = true"
|
||||
@drop="dragging = false"
|
||||
@dragleave="dragging = false"
|
||||
@dragend="dragging = false"
|
||||
>
|
||||
<button class="icon" @click="toggleShowChildren">
|
||||
<i v-show="!showChildren && !isFiltered" class="material-icons"
|
||||
>arrow_right</i
|
||||
>
|
||||
<i v-show="showChildren || isFiltered" class="material-icons"
|
||||
>arrow_drop_down</i
|
||||
>
|
||||
|
||||
<i v-if="isSelected" class="text-green-400 material-icons"
|
||||
>check_circle</i
|
||||
>
|
||||
|
||||
<i v-else class="material-icons">folder</i>
|
||||
<span>{{ collection.name }}</span>
|
||||
</button>
|
||||
<div>
|
||||
<button
|
||||
v-if="doc && !selected"
|
||||
v-tooltip.left="$t('import')"
|
||||
class="icon"
|
||||
@click="$emit('select-collection')"
|
||||
>
|
||||
<i class="material-icons">check_box_outline_blank</i>
|
||||
</button>
|
||||
<button
|
||||
v-if="doc && selected"
|
||||
v-tooltip.left="$t('delete')"
|
||||
class="icon"
|
||||
@click="$emit('unselect-collection')"
|
||||
>
|
||||
<i class="material-icons">check_box</i>
|
||||
</button>
|
||||
<v-popover v-if="!saveRequest">
|
||||
<button v-tooltip.left="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="
|
||||
$emit('add-folder', {
|
||||
folder: collection,
|
||||
path: `${collectionIndex}`,
|
||||
})
|
||||
"
|
||||
>
|
||||
<i class="material-icons">create_new_folder</i>
|
||||
<span>{{ $t("new_folder") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="$emit('edit-collection')"
|
||||
>
|
||||
<i class="material-icons">create</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="confirmRemove = true"
|
||||
>
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="showChildren || isFiltered">
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(folder, index) in collection.folders"
|
||||
:key="index"
|
||||
class="ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsMyFolder
|
||||
:folder="folder"
|
||||
:folder-index="index"
|
||||
:folder-path="`${collectionIndex}/${index}`"
|
||||
:collection-index="collectionIndex"
|
||||
:doc="doc"
|
||||
:save-request="saveRequest"
|
||||
:collections-type="collectionsType"
|
||||
:is-filtered="isFiltered"
|
||||
:picked="picked"
|
||||
@add-folder="$emit('add-folder', $event)"
|
||||
@edit-folder="$emit('edit-folder', $event)"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
@select="$emit('select', $event)"
|
||||
@remove-request="removeRequest"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(request, index) in collection.requests"
|
||||
:key="index"
|
||||
class="ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsMyRequest
|
||||
:request="request"
|
||||
:collection-index="collectionIndex"
|
||||
:folder-index="-1"
|
||||
:folder-name="collection.name"
|
||||
:folder-path="collectionIndex.toString()"
|
||||
:request-index="index"
|
||||
:doc="doc"
|
||||
:save-request="saveRequest"
|
||||
:collections-type="collectionsType"
|
||||
:picked="picked"
|
||||
@edit-request="editRequest($event)"
|
||||
@select="$emit('select', $event)"
|
||||
@remove-request="removeRequest"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li
|
||||
v-if="
|
||||
(collection.folders == undefined ||
|
||||
collection.folders.length === 0) &&
|
||||
(collection.requests == undefined ||
|
||||
collection.requests.length === 0)
|
||||
"
|
||||
class="flex ml-8 border-l border-brdColor"
|
||||
>
|
||||
<p class="info">
|
||||
<i class="material-icons">not_interested</i>
|
||||
{{ $t("collection_empty") }}
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_collection')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeCollection"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
import { getSettingSubject } from "~/newstore/settings"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
collectionIndex: { type: Number, default: null },
|
||||
collection: { type: Object, default: () => {} },
|
||||
doc: Boolean,
|
||||
isFiltered: Boolean,
|
||||
selected: Boolean,
|
||||
saveRequest: Boolean,
|
||||
collectionsType: { type: Object, default: () => {} },
|
||||
picked: { type: Object, default: () => {} },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showChildren: false,
|
||||
dragging: false,
|
||||
selectedFolder: {},
|
||||
confirmRemove: false,
|
||||
prevCursor: "",
|
||||
cursor: "",
|
||||
pageNo: 0,
|
||||
}
|
||||
},
|
||||
subscriptions() {
|
||||
return {
|
||||
SYNC_COLLECTIONS: getSettingSubject("syncCollections"),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isSelected() {
|
||||
return (
|
||||
this.picked &&
|
||||
this.picked.pickedType === "my-collection" &&
|
||||
this.picked.collectionIndex === this.collectionIndex
|
||||
)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
editRequest(event) {
|
||||
this.$emit("edit-request", event)
|
||||
},
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && this.SYNC_COLLECTIONS) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(JSON.stringify(this.$store.state.postwoman.collections)),
|
||||
"collections"
|
||||
)
|
||||
}
|
||||
},
|
||||
toggleShowChildren() {
|
||||
if (this.$props.saveRequest)
|
||||
this.$emit("select", {
|
||||
picked: {
|
||||
pickedType: "my-collection",
|
||||
collectionIndex: this.collectionIndex,
|
||||
},
|
||||
})
|
||||
|
||||
this.$emit("expand-collection", this.collection.id)
|
||||
this.showChildren = !this.showChildren
|
||||
},
|
||||
removeCollection() {
|
||||
this.$emit("remove-collection", {
|
||||
collectionsType: this.collectionsType,
|
||||
collectionIndex: this.collectionIndex,
|
||||
collectionID: this.collection.id,
|
||||
})
|
||||
this.confirmRemove = false
|
||||
},
|
||||
dropEvent({ dataTransfer }) {
|
||||
this.dragging = !this.dragging
|
||||
const oldCollectionIndex = dataTransfer.getData("oldCollectionIndex")
|
||||
const oldFolderIndex = dataTransfer.getData("oldFolderIndex")
|
||||
const oldFolderName = dataTransfer.getData("oldFolderName")
|
||||
const requestIndex = dataTransfer.getData("requestIndex")
|
||||
const flag = "rest"
|
||||
this.$store.commit("postwoman/moveRequest", {
|
||||
oldCollectionIndex,
|
||||
newCollectionIndex: this.$props.collectionIndex,
|
||||
newFolderIndex: -1,
|
||||
newFolderName: this.$props.collection.name,
|
||||
oldFolderIndex,
|
||||
oldFolderName,
|
||||
requestIndex,
|
||||
flag,
|
||||
})
|
||||
this.syncCollections()
|
||||
},
|
||||
removeRequest({ collectionIndex, folderName, requestIndex }) {
|
||||
this.$emit("remove-request", {
|
||||
collectionIndex,
|
||||
folderName,
|
||||
requestIndex,
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,241 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:class="[
|
||||
'row-wrapper transition duration-150 ease-in-out',
|
||||
{ 'bg-bgDarkColor': dragging },
|
||||
]"
|
||||
@dragover.prevent
|
||||
@drop.prevent="dropEvent"
|
||||
@dragover="dragging = true"
|
||||
@drop="dragging = false"
|
||||
@dragleave="dragging = false"
|
||||
@dragend="dragging = false"
|
||||
>
|
||||
<div>
|
||||
<button class="icon" @click="toggleShowChildren">
|
||||
<i v-show="!showChildren && !isFiltered" class="material-icons"
|
||||
>arrow_right</i
|
||||
>
|
||||
<i v-show="showChildren || isFiltered" class="material-icons"
|
||||
>arrow_drop_down</i
|
||||
>
|
||||
<i v-if="isSelected" class="text-green-400 material-icons"
|
||||
>check_circle</i
|
||||
>
|
||||
<i v-else class="material-icons">folder_open</i>
|
||||
<span>{{ folder.name ? folder.name : folder.title }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<v-popover v-if="!saveRequest">
|
||||
<button v-tooltip.left="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="$emit('add-folder', { folder, path: folderPath })"
|
||||
>
|
||||
<i class="material-icons">create_new_folder</i>
|
||||
<span>{{ $t("new_folder") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="
|
||||
$emit('edit-folder', { folder, folderIndex, collectionIndex })
|
||||
"
|
||||
>
|
||||
<i class="material-icons">edit</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button v-close-popover class="icon" @click="confirmRemove = true">
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<div v-show="showChildren || isFiltered">
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(subFolder, subFolderIndex) in folder.folders"
|
||||
:key="subFolder.name"
|
||||
class="ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsMyFolder
|
||||
:folder="subFolder"
|
||||
:folder-index="subFolderIndex"
|
||||
:collection-index="collectionIndex"
|
||||
:doc="doc"
|
||||
:save-request="saveRequest"
|
||||
:collections-type="collectionsType"
|
||||
:folder-path="`${folderPath}/${subFolderIndex}`"
|
||||
:picked="picked"
|
||||
@add-folder="$emit('add-folder', $event)"
|
||||
@edit-folder="$emit('edit-folder', $event)"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
@update-team-collections="$emit('update-team-collections')"
|
||||
@select="$emit('select', $event)"
|
||||
@remove-request="removeRequest"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(request, index) in folder.requests"
|
||||
:key="index"
|
||||
class="flex ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsMyRequest
|
||||
:request="request"
|
||||
:collection-index="collectionIndex"
|
||||
:folder-index="folderIndex"
|
||||
:folder-name="folder.name"
|
||||
:request-index="index"
|
||||
:folder-path="folderPath"
|
||||
:doc="doc"
|
||||
:picked="picked"
|
||||
:save-request="saveRequest"
|
||||
:collections-type="collectionsType"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
@select="$emit('select', $event)"
|
||||
@remove-request="removeRequest"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul
|
||||
v-if="
|
||||
folder.folders &&
|
||||
folder.folders.length === 0 &&
|
||||
folder.requests &&
|
||||
folder.requests.length === 0
|
||||
"
|
||||
>
|
||||
<li class="flex ml-8 border-l border-brdColor">
|
||||
<p class="info">
|
||||
<i class="material-icons">not_interested</i>
|
||||
{{ $t("folder_empty") }}
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_folder')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeFolder"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
import { getSettingSubject } from "~/newstore/settings"
|
||||
|
||||
export default {
|
||||
name: "Folder",
|
||||
props: {
|
||||
folder: { type: Object, default: () => {} },
|
||||
folderIndex: { type: Number, default: null },
|
||||
collectionIndex: { type: Number, default: null },
|
||||
folderPath: { type: String, default: null },
|
||||
doc: Boolean,
|
||||
saveRequest: Boolean,
|
||||
isFiltered: Boolean,
|
||||
collectionsType: { type: Object, default: () => {} },
|
||||
picked: { type: Object, default: () => {} },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showChildren: false,
|
||||
dragging: false,
|
||||
confirmRemove: false,
|
||||
prevCursor: "",
|
||||
cursor: "",
|
||||
}
|
||||
},
|
||||
subscriptions() {
|
||||
return {
|
||||
SYNC_COLLECTIONS: getSettingSubject("syncCollections"),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isSelected() {
|
||||
return (
|
||||
this.picked &&
|
||||
this.picked.pickedType === "my-folder" &&
|
||||
this.picked.folderPath === this.folderPath
|
||||
)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
syncCollections() {
|
||||
if (fb.currentUser !== null && this.SYNC_COLLECTIONS) {
|
||||
fb.writeCollections(
|
||||
JSON.parse(JSON.stringify(this.$store.state.postwoman.collections)),
|
||||
"collections"
|
||||
)
|
||||
}
|
||||
},
|
||||
toggleShowChildren() {
|
||||
if (this.$props.saveRequest)
|
||||
this.$emit("select", {
|
||||
picked: {
|
||||
pickedType: "my-folder",
|
||||
collectionIndex: this.collectionIndex,
|
||||
folderName: this.folder.name,
|
||||
folderPath: this.folderPath,
|
||||
},
|
||||
})
|
||||
this.showChildren = !this.showChildren
|
||||
},
|
||||
removeFolder() {
|
||||
this.$store.commit("postwoman/removeFolder", {
|
||||
collectionIndex: this.$props.collectionIndex,
|
||||
folderName: this.$props.folder.name,
|
||||
folderIndex: this.$props.folderIndex,
|
||||
flag: "rest",
|
||||
})
|
||||
this.syncCollections()
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
})
|
||||
},
|
||||
dropEvent({ dataTransfer }) {
|
||||
this.dragging = !this.dragging
|
||||
const oldCollectionIndex = dataTransfer.getData("oldCollectionIndex")
|
||||
const oldFolderIndex = dataTransfer.getData("oldFolderIndex")
|
||||
const oldFolderName = dataTransfer.getData("oldFolderName")
|
||||
const requestIndex = dataTransfer.getData("requestIndex")
|
||||
const flag = "rest"
|
||||
|
||||
this.$store.commit("postwoman/moveRequest", {
|
||||
oldCollectionIndex,
|
||||
newCollectionIndex: this.$props.collectionIndex,
|
||||
newFolderIndex: this.$props.folderIndex,
|
||||
newFolderName: this.$props.folder.name,
|
||||
oldFolderIndex,
|
||||
oldFolderName,
|
||||
requestIndex,
|
||||
flag,
|
||||
})
|
||||
this.syncCollections()
|
||||
},
|
||||
removeRequest({ collectionIndex, folderName, requestIndex }) {
|
||||
this.$emit("remove-request", {
|
||||
collectionIndex,
|
||||
folderName,
|
||||
requestIndex,
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,146 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:class="[
|
||||
'row-wrapper transition duration-150 ease-in-out',
|
||||
{ 'bg-bgDarkColor': dragging },
|
||||
]"
|
||||
draggable="true"
|
||||
@dragstart="dragStart"
|
||||
@dragover.stop
|
||||
@dragleave="dragging = false"
|
||||
@dragend="dragging = false"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
v-tooltip="!doc ? $t('use_request') : ''"
|
||||
class="icon"
|
||||
@click="!doc ? selectRequest() : {}"
|
||||
>
|
||||
<i v-if="isSelected" class="mx-3 text-green-400 material-icons"
|
||||
>check_circle</i
|
||||
>
|
||||
|
||||
<span v-else :class="getRequestLabelColor(request.method)">{{
|
||||
request.method
|
||||
}}</span>
|
||||
<span>{{ request.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<v-popover v-if="!saveRequest">
|
||||
<button v-tooltip="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="
|
||||
$emit('edit-request', {
|
||||
collectionIndex,
|
||||
folderIndex,
|
||||
folderName,
|
||||
request,
|
||||
requestIndex,
|
||||
})
|
||||
"
|
||||
>
|
||||
<i class="material-icons">edit</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button v-close-popover class="icon" @click="confirmRemove = true">
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_request')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeRequest"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
request: { type: Object, default: () => {} },
|
||||
collectionIndex: { type: Number, default: null },
|
||||
folderIndex: { type: Number, default: null },
|
||||
folderName: { type: String, default: null },
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
requestIndex: [Number, String],
|
||||
doc: Boolean,
|
||||
saveRequest: Boolean,
|
||||
collectionsType: { type: Object, default: () => {} },
|
||||
folderPath: { type: String, default: null },
|
||||
picked: { type: Object, default: () => {} },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dragging: false,
|
||||
requestMethodLabels: {
|
||||
get: "text-green-400",
|
||||
post: "text-yellow-400",
|
||||
put: "text-blue-400",
|
||||
delete: "text-red-400",
|
||||
default: "text-gray-400",
|
||||
},
|
||||
confirmRemove: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isSelected() {
|
||||
return (
|
||||
this.picked &&
|
||||
this.picked.pickedType === "my-request" &&
|
||||
this.picked.folderPath === this.folderPath &&
|
||||
this.picked.requestIndex === this.requestIndex
|
||||
)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
selectRequest() {
|
||||
if (this.$props.saveRequest)
|
||||
this.$emit("select", {
|
||||
picked: {
|
||||
pickedType: "my-request",
|
||||
collectionIndex: this.collectionIndex,
|
||||
folderPath: this.folderPath,
|
||||
folderName: this.folderName,
|
||||
requestIndex: this.requestIndex,
|
||||
},
|
||||
})
|
||||
else
|
||||
this.$store.commit("postwoman/selectRequest", { request: this.request })
|
||||
},
|
||||
dragStart({ dataTransfer }) {
|
||||
this.dragging = !this.dragging
|
||||
dataTransfer.setData("oldCollectionIndex", this.$props.collectionIndex)
|
||||
dataTransfer.setData("oldFolderIndex", this.$props.folderIndex)
|
||||
dataTransfer.setData("oldFolderName", this.$props.folderName)
|
||||
dataTransfer.setData("requestIndex", this.$props.requestIndex)
|
||||
},
|
||||
removeRequest() {
|
||||
this.$emit("remove-request", {
|
||||
collectionIndex: this.$props.collectionIndex,
|
||||
folderName: this.$props.folderName,
|
||||
requestIndex: this.$props.requestIndex,
|
||||
})
|
||||
},
|
||||
getRequestLabelColor(method) {
|
||||
return (
|
||||
this.requestMethodLabels[method.toLowerCase()] ||
|
||||
this.requestMethodLabels.default
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,236 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="transition duration-150 ease-in-out row-wrapper">
|
||||
<button class="icon" @click="toggleShowChildren">
|
||||
<i v-show="!showChildren && !isFiltered" class="material-icons"
|
||||
>arrow_right</i
|
||||
>
|
||||
<i v-show="showChildren || isFiltered" class="material-icons"
|
||||
>arrow_drop_down</i
|
||||
>
|
||||
|
||||
<i v-if="isSelected" class="text-green-400 material-icons"
|
||||
>check_circle</i
|
||||
>
|
||||
|
||||
<i v-else class="material-icons">folder</i>
|
||||
<span>{{ collection.title }}</span>
|
||||
</button>
|
||||
<div>
|
||||
<button
|
||||
v-if="doc && !selected"
|
||||
v-tooltip.left="$t('import')"
|
||||
class="icon"
|
||||
@click="$emit('select-collection')"
|
||||
>
|
||||
<i class="material-icons">check_box_outline_blank</i>
|
||||
</button>
|
||||
<button
|
||||
v-if="doc && selected"
|
||||
v-tooltip.left="$t('delete')"
|
||||
class="icon"
|
||||
@click="$emit('unselect-collection')"
|
||||
>
|
||||
<i class="material-icons">check_box</i>
|
||||
</button>
|
||||
<v-popover v-if="!saveRequest">
|
||||
<button
|
||||
v-if="collectionsType.selectedTeam.myRole !== 'VIEWER'"
|
||||
v-tooltip.left="$t('more')"
|
||||
class="tooltip-target icon"
|
||||
>
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-if="collectionsType.selectedTeam.myRole !== 'VIEWER'"
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="
|
||||
$emit('add-folder', {
|
||||
folder: collection,
|
||||
path: `${collectionIndex}`,
|
||||
})
|
||||
"
|
||||
>
|
||||
<i class="material-icons">create_new_folder</i>
|
||||
<span>{{ $t("new_folder") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-if="collectionsType.selectedTeam.myRole !== 'VIEWER'"
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="$emit('edit-collection')"
|
||||
>
|
||||
<i class="material-icons">create</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-if="collectionsType.selectedTeam.myRole !== 'VIEWER'"
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="confirmRemove = true"
|
||||
>
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="showChildren || isFiltered">
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(folder, index) in collection.children"
|
||||
:key="folder.title"
|
||||
class="ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsTeamsFolder
|
||||
:folder="folder"
|
||||
:folder-index="index"
|
||||
:folder-path="`${collectionIndex}/${index}`"
|
||||
:collection-index="collectionIndex"
|
||||
:doc="doc"
|
||||
:save-request="saveRequest"
|
||||
:collections-type="collectionsType"
|
||||
:is-filtered="isFiltered"
|
||||
:picked="picked"
|
||||
@add-folder="$emit('add-folder', $event)"
|
||||
@edit-folder="$emit('edit-folder', $event)"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
@select="$emit('select', $event)"
|
||||
@expand-collection="expandCollection"
|
||||
@remove-request="removeRequest"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(request, index) in collection.requests"
|
||||
:key="index"
|
||||
class="ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsTeamsRequest
|
||||
:request="request.request"
|
||||
:collection-index="collectionIndex"
|
||||
:folder-index="-1"
|
||||
:folder-name="collection.name"
|
||||
:request-index="request.id"
|
||||
:doc="doc"
|
||||
:save-request="saveRequest"
|
||||
:collections-type="collectionsType"
|
||||
:picked="picked"
|
||||
@edit-request="editRequest($event)"
|
||||
@select="$emit('select', $event)"
|
||||
@remove-request="removeRequest"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li
|
||||
v-if="
|
||||
(collection.children == undefined ||
|
||||
collection.children.length === 0) &&
|
||||
(collection.requests == undefined ||
|
||||
collection.requests.length === 0)
|
||||
"
|
||||
class="flex ml-8 border-l border-brdColor"
|
||||
>
|
||||
<p class="info">
|
||||
<i class="material-icons">not_interested</i>
|
||||
{{ $t("collection_empty") }}
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_collection')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeCollection"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
collectionIndex: { type: Number, default: null },
|
||||
collection: { type: Object, default: () => {} },
|
||||
doc: Boolean,
|
||||
isFiltered: Boolean,
|
||||
selected: Boolean,
|
||||
saveRequest: Boolean,
|
||||
collectionsType: { type: Object, default: () => {} },
|
||||
picked: { type: Object, default: () => {} },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showChildren: false,
|
||||
dragging: false,
|
||||
selectedFolder: {},
|
||||
confirmRemove: false,
|
||||
prevCursor: "",
|
||||
cursor: "",
|
||||
pageNo: 0,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isSelected() {
|
||||
return (
|
||||
this.picked &&
|
||||
this.picked.pickedType === "teams-collection" &&
|
||||
this.picked.collectionID === this.collection.id
|
||||
)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
editRequest(event) {
|
||||
this.$emit("edit-request", event)
|
||||
if (this.$props.saveRequest)
|
||||
this.$emit("select", {
|
||||
picked: {
|
||||
pickedType: "teams-collection",
|
||||
collectionID: this.collection.id,
|
||||
},
|
||||
})
|
||||
},
|
||||
toggleShowChildren() {
|
||||
if (this.$props.saveRequest)
|
||||
this.$emit("select", {
|
||||
picked: {
|
||||
pickedType: "teams-collection",
|
||||
collectionID: this.collection.id,
|
||||
},
|
||||
})
|
||||
|
||||
this.$emit("expand-collection", this.collection.id)
|
||||
this.showChildren = !this.showChildren
|
||||
},
|
||||
removeCollection() {
|
||||
this.$emit("remove-collection", {
|
||||
collectionsType: this.collectionsType,
|
||||
collectionIndex: this.collectionIndex,
|
||||
collectionID: this.collection.id,
|
||||
})
|
||||
this.confirmRemove = false
|
||||
},
|
||||
expandCollection(collectionID) {
|
||||
this.$emit("expand-collection", collectionID)
|
||||
},
|
||||
removeRequest({ collectionIndex, folderName, requestIndex }) {
|
||||
this.$emit("remove-request", {
|
||||
collectionIndex,
|
||||
folderName,
|
||||
requestIndex,
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,219 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="transition duration-150 ease-in-out row-wrapper">
|
||||
<div>
|
||||
<button class="icon" @click="toggleShowChildren">
|
||||
<i v-show="!showChildren && !isFiltered" class="material-icons"
|
||||
>arrow_right</i
|
||||
>
|
||||
<i v-show="showChildren || isFiltered" class="material-icons"
|
||||
>arrow_drop_down</i
|
||||
>
|
||||
|
||||
<i v-if="isSelected" class="text-green-400 material-icons"
|
||||
>check_circle</i
|
||||
>
|
||||
|
||||
<i v-else class="material-icons">folder_open</i>
|
||||
<span>{{ folder.name ? folder.name : folder.title }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<v-popover v-if="!saveRequest">
|
||||
<button
|
||||
v-if="collectionsType.selectedTeam.myRole !== 'VIEWER'"
|
||||
v-tooltip.left="$t('more')"
|
||||
class="tooltip-target icon"
|
||||
>
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-if="collectionsType.selectedTeam.myRole !== 'VIEWER'"
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="$emit('add-folder', { folder, path: folderPath })"
|
||||
>
|
||||
<i class="material-icons">create_new_folder</i>
|
||||
<span>{{ $t("new_folder") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-if="collectionsType.selectedTeam.myRole !== 'VIEWER'"
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="
|
||||
$emit('edit-folder', { folder, folderIndex, collectionIndex })
|
||||
"
|
||||
>
|
||||
<i class="material-icons">edit</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-if="collectionsType.selectedTeam.myRole !== 'VIEWER'"
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="confirmRemove = true"
|
||||
>
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<div v-show="showChildren || isFiltered">
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(subFolder, subFolderIndex) in folder.children"
|
||||
:key="subFolder.name"
|
||||
class="ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsTeamsFolder
|
||||
:folder="subFolder"
|
||||
:folder-index="subFolderIndex"
|
||||
:collection-index="collectionIndex"
|
||||
:doc="doc"
|
||||
:save-request="saveRequest"
|
||||
:collections-type="collectionsType"
|
||||
:folder-path="`${folderPath}/${subFolderIndex}`"
|
||||
:picked="picked"
|
||||
@add-folder="$emit('add-folder', $event)"
|
||||
@edit-folder="$emit('edit-folder', $event)"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
@update-team-collections="$emit('update-team-collections')"
|
||||
@select="$emit('select', $event)"
|
||||
@expand-collection="expandCollection"
|
||||
@remove-request="removeRequest"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(request, index) in folder.requests"
|
||||
:key="index"
|
||||
class="flex ml-8 border-l border-brdColor"
|
||||
>
|
||||
<CollectionsTeamsRequest
|
||||
:request="request.request"
|
||||
:collection-index="collectionIndex"
|
||||
:folder-index="folderIndex"
|
||||
:folder-name="folder.name"
|
||||
:request-index="request.id"
|
||||
:doc="doc"
|
||||
:save-request="saveRequest"
|
||||
:collections-type="collectionsType"
|
||||
:picked="picked"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
@select="$emit('select', $event)"
|
||||
@remove-request="removeRequest"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul
|
||||
v-if="
|
||||
(folder.children == undefined || folder.children.length === 0) &&
|
||||
(folder.requests == undefined || folder.requests.length === 0)
|
||||
"
|
||||
>
|
||||
<li class="flex ml-8 border-l border-brdColor">
|
||||
<p class="info">
|
||||
<i class="material-icons">not_interested</i>
|
||||
{{ $t("folder_empty") }}
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_folder')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeFolder"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as teamUtils from "~/helpers/teams/utils"
|
||||
|
||||
export default {
|
||||
name: "Folder",
|
||||
props: {
|
||||
folder: { type: Object, default: () => {} },
|
||||
folderIndex: { type: Number, default: null },
|
||||
collectionIndex: { type: Number, default: null },
|
||||
folderPath: { type: String, default: null },
|
||||
doc: Boolean,
|
||||
saveRequest: Boolean,
|
||||
isFiltered: Boolean,
|
||||
collectionsType: { type: Object, default: () => {} },
|
||||
picked: { type: Object, default: () => {} },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showChildren: false,
|
||||
confirmRemove: false,
|
||||
prevCursor: "",
|
||||
cursor: "",
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isSelected() {
|
||||
return (
|
||||
this.picked &&
|
||||
this.picked.pickedType === "teams-folder" &&
|
||||
this.picked.folderID === this.folder.id
|
||||
)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleShowChildren() {
|
||||
if (this.$props.saveRequest)
|
||||
this.$emit("select", {
|
||||
picked: {
|
||||
pickedType: "teams-folder",
|
||||
folderID: this.folder.id,
|
||||
},
|
||||
})
|
||||
|
||||
this.$emit("expand-collection", this.$props.folder.id)
|
||||
this.showChildren = !this.showChildren
|
||||
},
|
||||
removeFolder() {
|
||||
if (this.collectionsType.selectedTeam.myRole !== "VIEWER") {
|
||||
teamUtils
|
||||
.deleteCollection(this.$apollo, this.folder.id)
|
||||
.then(() => {
|
||||
// Result
|
||||
this.$toast.success(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
})
|
||||
this.$emit("update-team-collections")
|
||||
this.confirmRemove = false
|
||||
})
|
||||
.catch((error) => {
|
||||
// Error
|
||||
this.$toast.error(this.$t("error_occurred"), {
|
||||
icon: "done",
|
||||
})
|
||||
console.error(error)
|
||||
})
|
||||
this.$emit("update-team-collections")
|
||||
}
|
||||
},
|
||||
expandCollection(collectionID) {
|
||||
this.$emit("expand-collection", collectionID)
|
||||
},
|
||||
removeRequest({ collectionIndex, folderName, requestIndex }) {
|
||||
this.$emit("remove-request", {
|
||||
collectionIndex,
|
||||
folderName,
|
||||
requestIndex,
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,128 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="transition duration-150 ease-in-out row-wrapper">
|
||||
<div>
|
||||
<button
|
||||
v-tooltip="!doc ? $t('use_request') : ''"
|
||||
class="icon"
|
||||
@click="!doc ? selectRequest() : {}"
|
||||
>
|
||||
<i v-if="isSelected" class="mx-3 text-green-400 material-icons"
|
||||
>check_circle</i
|
||||
>
|
||||
|
||||
<span v-else :class="getRequestLabelColor(request.method)">{{
|
||||
request.method
|
||||
}}</span>
|
||||
<span>{{ request.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<v-popover v-if="!saveRequest">
|
||||
<button
|
||||
v-if="collectionsType.selectedTeam.myRole !== 'VIEWER'"
|
||||
v-tooltip="$t('more')"
|
||||
class="tooltip-target icon"
|
||||
>
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="
|
||||
$emit('edit-request', {
|
||||
collectionIndex,
|
||||
folderIndex,
|
||||
folderName,
|
||||
request,
|
||||
requestIndex,
|
||||
})
|
||||
"
|
||||
>
|
||||
<i class="material-icons">edit</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button v-close-popover class="icon" @click="confirmRemove = true">
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_request')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeRequest"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
request: { type: Object, default: () => {} },
|
||||
collectionIndex: { type: Number, default: null },
|
||||
folderIndex: { type: Number, default: null },
|
||||
folderName: { type: String, default: null },
|
||||
// eslint-disable-next-line vue/require-default-prop
|
||||
requestIndex: [Number, String],
|
||||
doc: Boolean,
|
||||
saveRequest: Boolean,
|
||||
collectionsType: { type: Object, default: () => {} },
|
||||
picked: { type: Object, default: () => {} },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dragging: false,
|
||||
requestMethodLabels: {
|
||||
get: "text-green-400",
|
||||
post: "text-yellow-400",
|
||||
put: "text-blue-400",
|
||||
delete: "text-red-400",
|
||||
default: "text-gray-400",
|
||||
},
|
||||
confirmRemove: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isSelected() {
|
||||
return (
|
||||
this.picked &&
|
||||
this.picked.pickedType === "teams-request" &&
|
||||
this.picked.requestID === this.requestIndex
|
||||
)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
selectRequest() {
|
||||
if (this.$props.saveRequest)
|
||||
this.$emit("select", {
|
||||
picked: {
|
||||
pickedType: "teams-request",
|
||||
requestID: this.requestIndex,
|
||||
},
|
||||
})
|
||||
else
|
||||
this.$store.commit("postwoman/selectRequest", { request: this.request })
|
||||
},
|
||||
removeRequest() {
|
||||
this.$emit("remove-request", {
|
||||
collectionIndex: this.$props.collectionIndex,
|
||||
folderName: this.$props.folderName,
|
||||
requestIndex: this.$props.requestIndex,
|
||||
})
|
||||
},
|
||||
getRequestLabelColor(method) {
|
||||
return (
|
||||
this.requestMethodLabels[method.toLowerCase()] ||
|
||||
this.requestMethodLabels.default
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,39 +0,0 @@
|
||||
<template>
|
||||
<div class="folder">
|
||||
<h3>
|
||||
<i class="material-icons">folder_open</i>
|
||||
{{ folder.name || $t("none") }}
|
||||
</h3>
|
||||
<div v-for="(subFolder, index) in folder.folders" :key="index">
|
||||
<DocsFolder :folder="subFolder" />
|
||||
</div>
|
||||
<div v-for="(request, index) in folder.requests" :key="index">
|
||||
<DocsRequest :request="request" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
folder: { type: Object, default: () => {} },
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.folder {
|
||||
@apply flex;
|
||||
@apply flex-col;
|
||||
@apply justify-center;
|
||||
@apply flex-1;
|
||||
@apply p-4;
|
||||
@apply border-l;
|
||||
@apply border-brdColor;
|
||||
@apply mt-4;
|
||||
|
||||
.material-icons {
|
||||
@apply mr-4;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,153 +0,0 @@
|
||||
<template>
|
||||
<div class="request">
|
||||
<h4>
|
||||
<i class="material-icons">insert_drive_file</i>
|
||||
{{ request.name || $t("none") }}
|
||||
</h4>
|
||||
<p v-if="request.url" class="doc-desc">
|
||||
<span>
|
||||
{{ $t("url") }}: <code>{{ request.url || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="request.path" class="doc-desc">
|
||||
<span>
|
||||
{{ $t("path") }}:
|
||||
<code>{{ request.path || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="request.method" class="doc-desc">
|
||||
<span>
|
||||
{{ $t("method") }}:
|
||||
<code>{{ request.method || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="request.auth" class="doc-desc">
|
||||
<span>
|
||||
{{ $t("authentication") }}:
|
||||
<code>{{ request.auth || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="request.httpUser" class="doc-desc">
|
||||
<span>
|
||||
{{ $t("username") }}:
|
||||
<code>{{ request.httpUser || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="request.httpPassword" class="doc-desc">
|
||||
<span>
|
||||
{{ $t("password") }}:
|
||||
<code>{{ request.httpPassword || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="request.bearerToken" class="doc-desc">
|
||||
<span>
|
||||
{{ $t("token") }}:
|
||||
<code>{{ request.bearerToken || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
<h4 v-if="request.headers">{{ $t("headers") }}</h4>
|
||||
<span v-if="request.headers">
|
||||
<p v-for="header in request.headers" :key="header.key" class="doc-desc">
|
||||
<span>
|
||||
{{ header.key || $t("none") }}:
|
||||
<code>{{ header.value || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
</span>
|
||||
<h4 v-if="request.params">{{ $t("parameters") }}</h4>
|
||||
<span v-if="request.params">
|
||||
<p
|
||||
v-for="parameter in request.params"
|
||||
:key="parameter.key"
|
||||
class="doc-desc"
|
||||
>
|
||||
<span>
|
||||
{{ parameter.key || $t("none") }}:
|
||||
<code>{{ parameter.value || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
</span>
|
||||
<h4 v-if="request.bodyParams">{{ $t("payload") }}</h4>
|
||||
<span v-if="request.bodyParams">
|
||||
<p
|
||||
v-for="payload in request.bodyParams"
|
||||
:key="payload.key"
|
||||
class="doc-desc"
|
||||
>
|
||||
<span>
|
||||
{{ payload.key || $t("none") }}:
|
||||
<code>{{ payload.value || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
</span>
|
||||
<p v-if="request.rawParams" class="doc-desc">
|
||||
<span>
|
||||
{{ $t("parameters") }}:
|
||||
<code>{{ request.rawParams || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="request.contentType" class="doc-desc">
|
||||
<span>
|
||||
{{ $t("content_type") }}:
|
||||
<code>{{ request.contentType || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
<p v-if="request.requestType" class="doc-desc">
|
||||
<span>
|
||||
{{ $t("request_type") }}:
|
||||
<code>{{ request.requestType || $t("none") }}</code>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
request: { type: Object, default: () => {} },
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.request {
|
||||
@apply flex;
|
||||
@apply flex-col;
|
||||
@apply justify-center;
|
||||
@apply flex-1;
|
||||
@apply p-4;
|
||||
@apply border;
|
||||
@apply border-brdColor;
|
||||
@apply rounded-lg;
|
||||
@apply mt-4;
|
||||
|
||||
h4 {
|
||||
@apply mt-4;
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
@apply mr-4;
|
||||
}
|
||||
}
|
||||
|
||||
.doc-desc {
|
||||
@apply flex;
|
||||
@apply flex-col;
|
||||
@apply justify-center;
|
||||
@apply flex-1;
|
||||
@apply p-4;
|
||||
@apply text-fgLightColor;
|
||||
@apply border-b;
|
||||
@apply border-dashed;
|
||||
@apply border-brdColor;
|
||||
@apply m-0;
|
||||
|
||||
&:last-child {
|
||||
@apply border-b-0;
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
@apply mr-4;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,89 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("new_environment") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="$t('my_new_environment')"
|
||||
@keyup.enter="addNewEnvironment"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="addNewEnvironment">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
import { getSettingSubject } from "~/newstore/settings"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
}
|
||||
},
|
||||
subscriptions() {
|
||||
return {
|
||||
SYNC_ENVIRONMENTS: getSettingSubject("syncEnvironments"),
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncEnvironments() {
|
||||
if (fb.currentUser !== null && this.SYNC_ENVIRONMENTS) {
|
||||
fb.writeEnvironments(
|
||||
JSON.parse(JSON.stringify(this.$store.state.postwoman.environments))
|
||||
)
|
||||
}
|
||||
},
|
||||
addNewEnvironment() {
|
||||
if (!this.$data.name) {
|
||||
this.$toast.info(this.$t("invalid_environment_name"))
|
||||
return
|
||||
}
|
||||
const newEnvironment = [
|
||||
{
|
||||
name: this.$data.name,
|
||||
variables: [],
|
||||
},
|
||||
]
|
||||
this.$store.commit("postwoman/importAddEnvironments", {
|
||||
environments: newEnvironment,
|
||||
confirmation: "Environment added",
|
||||
})
|
||||
this.syncEnvironments()
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,224 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">{{ $t("edit_environment") }}</h3>
|
||||
<div>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<label for="selectLabel">{{ $t("label") }}</label>
|
||||
<input
|
||||
id="selectLabel"
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="editingEnvironment.name"
|
||||
@keyup.enter="saveEnvironment"
|
||||
/>
|
||||
<div class="row-wrapper">
|
||||
<label for="variableList">{{ $t("env_variable_list") }}</label>
|
||||
<div>
|
||||
<button
|
||||
v-tooltip.bottom="$t('clear')"
|
||||
class="icon"
|
||||
@click="clearContent($event)"
|
||||
>
|
||||
<i class="material-icons">clear_all</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ul
|
||||
v-for="(variable, index) in editingEnvCopy.variables"
|
||||
:key="index"
|
||||
class="
|
||||
border-b border-dashed
|
||||
divide-y
|
||||
md:divide-x
|
||||
border-brdColor
|
||||
divide-dashed divide-brdColor
|
||||
md:divide-y-0
|
||||
"
|
||||
:class="{ 'border-t': index == 0 }"
|
||||
>
|
||||
<li>
|
||||
<input
|
||||
:placeholder="$t('variable_count', { count: index + 1 })"
|
||||
:name="'param' + index"
|
||||
:value="variable.key"
|
||||
autofocus
|
||||
@change="
|
||||
$store.commit('postwoman/setVariableKey', {
|
||||
index,
|
||||
value: $event.target.value,
|
||||
})
|
||||
"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<input
|
||||
:placeholder="$t('value_count', { count: index + 1 })"
|
||||
:name="'value' + index"
|
||||
:value="
|
||||
typeof variable.value === 'string'
|
||||
? variable.value
|
||||
: JSON.stringify(variable.value)
|
||||
"
|
||||
@change="
|
||||
$store.commit('postwoman/setVariableValue', {
|
||||
index,
|
||||
value: $event.target.value,
|
||||
})
|
||||
"
|
||||
/>
|
||||
</li>
|
||||
<div>
|
||||
<li>
|
||||
<button
|
||||
id="variable"
|
||||
v-tooltip.bottom="$t('delete')"
|
||||
class="icon"
|
||||
@click="removeEnvironmentVariable(index)"
|
||||
>
|
||||
<i class="material-icons">delete</i>
|
||||
</button>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<button class="icon" @click="addEnvironmentVariable">
|
||||
<i class="material-icons">add</i>
|
||||
<span>{{ $t("add_new") }}</span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span></span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button class="icon primary" @click="saveEnvironment">
|
||||
{{ $t("save") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
import { getSettingSubject } from "~/newstore/settings"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
editingEnvironment: { type: Object, default: () => {} },
|
||||
editingEnvironmentIndex: { type: Number, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
doneButton: '<i class="material-icons">done</i>',
|
||||
}
|
||||
},
|
||||
subscriptions() {
|
||||
return {
|
||||
SYNC_ENVIRONMENTS: getSettingSubject("syncEnvironments"),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
editingEnvCopy() {
|
||||
return this.$store.state.postwoman.editingEnvironment
|
||||
},
|
||||
variableString() {
|
||||
const result = this.editingEnvCopy.variables
|
||||
return result === "" ? "" : JSON.stringify(result)
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
editingEnvironment() {
|
||||
this.name =
|
||||
this.$props.editingEnvironment && this.$props.editingEnvironment.name
|
||||
? this.$props.editingEnvironment.name
|
||||
: undefined
|
||||
this.$store.commit(
|
||||
"postwoman/setEditingEnvironment",
|
||||
this.$props.editingEnvironment
|
||||
)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
syncEnvironments() {
|
||||
if (fb.currentUser !== null && this.SYNC_ENVIRONMENTS) {
|
||||
fb.writeEnvironments(
|
||||
JSON.parse(JSON.stringify(this.$store.state.postwoman.environments))
|
||||
)
|
||||
}
|
||||
},
|
||||
clearContent({ target }) {
|
||||
this.$store.commit("postwoman/removeVariables", [])
|
||||
target.innerHTML = this.doneButton
|
||||
this.$toast.info(this.$t("cleared"), {
|
||||
icon: "clear_all",
|
||||
})
|
||||
setTimeout(
|
||||
() => (target.innerHTML = '<i class="material-icons">clear_all</i>'),
|
||||
1000
|
||||
)
|
||||
},
|
||||
addEnvironmentVariable() {
|
||||
const value = { key: "", value: "" }
|
||||
this.$store.commit("postwoman/addVariable", value)
|
||||
this.syncEnvironments()
|
||||
},
|
||||
removeEnvironmentVariable(index) {
|
||||
const variableIndex = index
|
||||
const oldVariables = this.editingEnvCopy.variables.slice()
|
||||
const newVariables = this.editingEnvCopy.variables.filter(
|
||||
(_, index) => variableIndex !== index
|
||||
)
|
||||
|
||||
this.$store.commit("postwoman/removeVariable", newVariables)
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
action: {
|
||||
text: this.$t("undo"),
|
||||
onClick: (_, toastObject) => {
|
||||
this.$store.commit("postwoman/removeVariable", oldVariables)
|
||||
toastObject.remove()
|
||||
},
|
||||
},
|
||||
})
|
||||
this.syncEnvironments()
|
||||
},
|
||||
saveEnvironment() {
|
||||
if (!this.$data.name) {
|
||||
this.$toast.info(this.$t("invalid_environment_name"))
|
||||
return
|
||||
}
|
||||
const environmentUpdated = {
|
||||
...this.editingEnvCopy,
|
||||
name: this.$data.name,
|
||||
}
|
||||
this.$store.commit("postwoman/saveEnvironment", {
|
||||
environment: environmentUpdated,
|
||||
environmentIndex: this.$props.editingEnvironmentIndex,
|
||||
})
|
||||
this.syncEnvironments()
|
||||
this.hideModal()
|
||||
},
|
||||
hideModal() {
|
||||
this.name = null
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,79 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="row-wrapper">
|
||||
<div>
|
||||
<button class="icon" @click="$emit('edit-environment')">
|
||||
<i class="material-icons">layers</i>
|
||||
<span>{{ environment.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<v-popover>
|
||||
<button v-tooltip.left="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="$emit('edit-environment')"
|
||||
>
|
||||
<i class="material-icons">create</i>
|
||||
<span>{{ $t("edit") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button v-close-popover class="icon" @click="confirmRemove = true">
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<SmartConfirmModal
|
||||
:show="confirmRemove"
|
||||
:title="$t('are_you_sure_remove_environment')"
|
||||
@hide-modal="confirmRemove = false"
|
||||
@resolve="removeEnvironment"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
import { getSettingSubject } from "~/newstore/settings"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
environment: { type: Object, default: () => {} },
|
||||
environmentIndex: { type: Number, default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
confirmRemove: false,
|
||||
}
|
||||
},
|
||||
subscriptions() {
|
||||
return {
|
||||
SYNC_ENVIRONMENTS: getSettingSubject("syncEnvironments"),
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncEnvironments() {
|
||||
if (fb.currentUser !== null && this.SYNC_ENVIRONMENTS) {
|
||||
fb.writeEnvironments(
|
||||
JSON.parse(JSON.stringify(this.$store.state.postwoman.environments))
|
||||
)
|
||||
}
|
||||
},
|
||||
removeEnvironment() {
|
||||
this.$store.commit("postwoman/removeEnvironment", this.environmentIndex)
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
})
|
||||
this.syncEnvironments()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,303 +0,0 @@
|
||||
<template>
|
||||
<SmartModal v-if="show" @close="hideModal">
|
||||
<div slot="header">
|
||||
<div class="row-wrapper">
|
||||
<h3 class="title">
|
||||
{{ $t("import_export") }} {{ $t("environments") }}
|
||||
</h3>
|
||||
<div>
|
||||
<v-popover>
|
||||
<button v-tooltip.left="$t('more')" class="tooltip-target icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
class="icon"
|
||||
@click="readEnvironmentGist"
|
||||
>
|
||||
<i class="material-icons">assignment_returned</i>
|
||||
<span>{{ $t("import_from_gist") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-tooltip.bottom="{
|
||||
content: !fb.currentUser
|
||||
? $t('login_with_github_to') + $t('create_secret_gist')
|
||||
: fb.currentUser.provider !== 'github.com'
|
||||
? $t('login_with_github_to') + $t('create_secret_gist')
|
||||
: null,
|
||||
}"
|
||||
>
|
||||
<button
|
||||
v-close-popover
|
||||
:disabled="
|
||||
!fb.currentUser
|
||||
? true
|
||||
: fb.currentUser.provider !== 'github.com'
|
||||
? true
|
||||
: false
|
||||
"
|
||||
class="icon"
|
||||
@click="createEnvironmentGist"
|
||||
>
|
||||
<i class="material-icons">assignment_turned_in</i>
|
||||
<span>{{ $t("create_secret_gist") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
<button class="icon" @click="hideModal">
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="body" class="flex flex-col">
|
||||
<div class="flex flex-col items-start p-2">
|
||||
<span
|
||||
v-tooltip="{
|
||||
content: !fb.currentUser
|
||||
? $t('login_first')
|
||||
: $t('replace_current'),
|
||||
}"
|
||||
>
|
||||
<button
|
||||
:disabled="!fb.currentUser"
|
||||
class="icon"
|
||||
@click="syncEnvironments"
|
||||
>
|
||||
<i class="material-icons">folder_shared</i>
|
||||
<span>{{ $t("import_from_sync") }}</span>
|
||||
</button>
|
||||
</span>
|
||||
<button
|
||||
v-tooltip="$t('replace_current')"
|
||||
class="icon"
|
||||
@click="openDialogChooseFileToReplaceWith"
|
||||
>
|
||||
<i class="material-icons">create_new_folder</i>
|
||||
<span>{{ $t("replace_json") }}</span>
|
||||
<input
|
||||
ref="inputChooseFileToReplaceWith"
|
||||
type="file"
|
||||
style="display: none"
|
||||
accept="application/json"
|
||||
@change="replaceWithJSON"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
v-tooltip="$t('preserve_current')"
|
||||
class="icon"
|
||||
@click="openDialogChooseFileToImportFrom"
|
||||
>
|
||||
<i class="material-icons">folder_special</i>
|
||||
<span>{{ $t("import_json") }}</span>
|
||||
<input
|
||||
ref="inputChooseFileToImportFrom"
|
||||
type="file"
|
||||
style="display: none"
|
||||
accept="application/json"
|
||||
@change="importFromJSON"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="showJsonCode" class="row-wrapper">
|
||||
<textarea v-model="environmentJson" rows="8" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<div class="row-wrapper">
|
||||
<span>
|
||||
<SmartToggle :on="showJsonCode" @change="showJsonCode = $event">
|
||||
{{ $t("show_code") }}
|
||||
</SmartToggle>
|
||||
</span>
|
||||
<span>
|
||||
<button class="icon" @click="hideModal">
|
||||
{{ $t("cancel") }}
|
||||
</button>
|
||||
<button
|
||||
v-tooltip="$t('download_file')"
|
||||
class="icon primary"
|
||||
@click="exportJSON"
|
||||
>
|
||||
{{ $t("export") }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</SmartModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
import { getSettingSubject } from "~/newstore/settings"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fb,
|
||||
showJsonCode: false,
|
||||
}
|
||||
},
|
||||
subscriptions() {
|
||||
return {
|
||||
SYNC_ENVIRONMENTS: getSettingSubject("syncEnvironments"),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
environmentJson() {
|
||||
return JSON.stringify(this.$store.state.postwoman.environments, null, 2)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async createEnvironmentGist() {
|
||||
await this.$axios
|
||||
.$post(
|
||||
"https://api.github.com/gists",
|
||||
{
|
||||
files: {
|
||||
"hoppscotch-environments.json": {
|
||||
content: this.environmentJson,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `token ${fb.currentUser.accessToken}`,
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
},
|
||||
}
|
||||
)
|
||||
.then((res) => {
|
||||
this.$toast.success(this.$t("gist_created"), {
|
||||
icon: "done",
|
||||
})
|
||||
window.open(res.html_url)
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$toast.error(this.$t("something_went_wrong"), {
|
||||
icon: "error",
|
||||
})
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
async readEnvironmentGist() {
|
||||
const gist = prompt(this.$t("enter_gist_url"))
|
||||
if (!gist) return
|
||||
await this.$axios
|
||||
.$get(`https://api.github.com/gists/${gist.split("/").pop()}`, {
|
||||
headers: {
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
},
|
||||
})
|
||||
.then(({ files }) => {
|
||||
const environments = JSON.parse(Object.values(files)[0].content)
|
||||
this.$store.commit("postwoman/replaceEnvironments", environments)
|
||||
this.fileImported()
|
||||
this.syncToFBEnvironments()
|
||||
})
|
||||
.catch((error) => {
|
||||
this.failedImport()
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
hideModal() {
|
||||
this.$emit("hide-modal")
|
||||
},
|
||||
openDialogChooseFileToReplaceWith() {
|
||||
this.$refs.inputChooseFileToReplaceWith.click()
|
||||
},
|
||||
openDialogChooseFileToImportFrom() {
|
||||
this.$refs.inputChooseFileToImportFrom.click()
|
||||
},
|
||||
replaceWithJSON() {
|
||||
const reader = new FileReader()
|
||||
reader.onload = ({ target }) => {
|
||||
const content = target.result
|
||||
const environments = JSON.parse(content)
|
||||
this.$store.commit("postwoman/replaceEnvironments", environments)
|
||||
}
|
||||
reader.readAsText(this.$refs.inputChooseFileToReplaceWith.files[0])
|
||||
this.fileImported()
|
||||
this.syncToFBEnvironments()
|
||||
this.$refs.inputChooseFileToReplaceWith.value = ""
|
||||
},
|
||||
importFromJSON() {
|
||||
const reader = new FileReader()
|
||||
reader.onload = ({ target }) => {
|
||||
const content = target.result
|
||||
const importFileObj = JSON.parse(content)
|
||||
if (
|
||||
importFileObj._postman_variable_scope === "environment" ||
|
||||
importFileObj._postman_variable_scope === "globals"
|
||||
) {
|
||||
this.importFromPostman(importFileObj)
|
||||
} else {
|
||||
this.importFromPostwoman(importFileObj)
|
||||
}
|
||||
}
|
||||
reader.readAsText(this.$refs.inputChooseFileToImportFrom.files[0])
|
||||
this.syncToFBEnvironments()
|
||||
this.$refs.inputChooseFileToImportFrom.value = ""
|
||||
},
|
||||
importFromPostwoman(environments) {
|
||||
const confirmation = this.$t("file_imported")
|
||||
this.$store.commit("postwoman/importAddEnvironments", {
|
||||
environments,
|
||||
confirmation,
|
||||
})
|
||||
},
|
||||
importFromPostman({ name, values }) {
|
||||
const environment = { name, variables: [] }
|
||||
values.forEach(({ key, value }) =>
|
||||
environment.variables.push({ key, value })
|
||||
)
|
||||
const environments = [environment]
|
||||
this.importFromPostwoman(environments)
|
||||
},
|
||||
exportJSON() {
|
||||
let text = this.environmentJson
|
||||
text = text.replace(/\n/g, "\r\n")
|
||||
const blob = new Blob([text], {
|
||||
type: "text/json",
|
||||
})
|
||||
const anchor = document.createElement("a")
|
||||
anchor.download = "hoppscotch-environment.json"
|
||||
anchor.href = window.URL.createObjectURL(blob)
|
||||
anchor.target = "_blank"
|
||||
anchor.style.display = "none"
|
||||
document.body.appendChild(anchor)
|
||||
anchor.click()
|
||||
document.body.removeChild(anchor)
|
||||
this.$toast.success(this.$t("download_started"), {
|
||||
icon: "done",
|
||||
})
|
||||
},
|
||||
syncEnvironments() {
|
||||
this.$store.commit(
|
||||
"postwoman/replaceEnvironments",
|
||||
fb.currentEnvironments
|
||||
)
|
||||
this.fileImported()
|
||||
},
|
||||
syncToFBEnvironments() {
|
||||
if (fb.currentUser !== null && this.SYNC_ENVIRONMENTS) {
|
||||
fb.writeEnvironments(
|
||||
JSON.parse(JSON.stringify(this.$store.state.postwoman.environments))
|
||||
)
|
||||
}
|
||||
},
|
||||
fileImported() {
|
||||
this.$toast.info(this.$t("file_imported"), {
|
||||
icon: "folder_shared",
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,190 +0,0 @@
|
||||
<template>
|
||||
<AppSection
|
||||
ref="environments"
|
||||
icon="history"
|
||||
:label="$t('environments')"
|
||||
no-legend
|
||||
>
|
||||
<div class="show-on-large-screen">
|
||||
<span class="select-wrapper">
|
||||
<select
|
||||
v-model="selectedEnvironmentIndex"
|
||||
:disabled="environments.length == 0"
|
||||
class="rounded-t-lg"
|
||||
>
|
||||
<option :value="-1">No environment</option>
|
||||
<option v-if="environments.length === 0" value="0">
|
||||
{{ $t("create_new_environment") }}
|
||||
</option>
|
||||
<option
|
||||
v-for="(environment, index) in environments"
|
||||
:key="index"
|
||||
:value="index"
|
||||
>
|
||||
{{ environment.name }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
<EnvironmentsAdd
|
||||
:show="showModalAdd"
|
||||
@hide-modal="displayModalAdd(false)"
|
||||
/>
|
||||
<EnvironmentsEdit
|
||||
:show="showModalEdit"
|
||||
:editing-environment="editingEnvironment"
|
||||
:editing-environment-index="editingEnvironmentIndex"
|
||||
@hide-modal="displayModalEdit(false)"
|
||||
/>
|
||||
<EnvironmentsImportExport
|
||||
:show="showModalImportExport"
|
||||
@hide-modal="displayModalImportExport(false)"
|
||||
/>
|
||||
<div class="border-b row-wrapper border-brdColor">
|
||||
<div>
|
||||
<button class="icon" @click="displayModalAdd(true)">
|
||||
<i class="material-icons">add</i>
|
||||
<span>{{ $t("new") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="icon" @click="displayModalImportExport(true)">
|
||||
{{ $t("import_export") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="environments.length === 0" class="info">
|
||||
<i class="material-icons">help_outline</i>
|
||||
{{ $t("create_new_environment") }}
|
||||
</p>
|
||||
<div class="virtual-list">
|
||||
<ul class="flex-col">
|
||||
<li
|
||||
v-for="(environment, index) in environments"
|
||||
:key="environment.name"
|
||||
>
|
||||
<EnvironmentsEnvironment
|
||||
:environment-index="index"
|
||||
:environment="environment"
|
||||
@edit-environment="editEnvironment(environment, index)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</AppSection>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
import { getSettingSubject } from "~/newstore/settings"
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
showModalImportExport: false,
|
||||
showModalAdd: false,
|
||||
showModalEdit: false,
|
||||
editingEnvironment: undefined,
|
||||
editingEnvironmentIndex: undefined,
|
||||
selectedEnvironmentIndex: -1,
|
||||
defaultEnvironment: {
|
||||
name: "My Environment Variables",
|
||||
variables: [],
|
||||
},
|
||||
}
|
||||
},
|
||||
subscriptions() {
|
||||
return {
|
||||
SYNC_ENVIRONMENTS: getSettingSubject("syncEnvironments"),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
environments() {
|
||||
return fb.currentUser !== null
|
||||
? fb.currentEnvironments
|
||||
: this.$store.state.postwoman.environments
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selectedEnvironmentIndex(val) {
|
||||
if (val === -1)
|
||||
this.$emit("use-environment", {
|
||||
environment: this.defaultEnvironment,
|
||||
environments: this.environments,
|
||||
})
|
||||
else
|
||||
this.$emit("use-environment", {
|
||||
environment: this.environments[val],
|
||||
environments: this.environments,
|
||||
})
|
||||
},
|
||||
environments: {
|
||||
handler({ length }) {
|
||||
if (length === 0) {
|
||||
this.selectedEnvironmentIndex = -1
|
||||
this.$emit("use-environment", {
|
||||
environment: this.defaultEnvironment,
|
||||
environments: this.environments,
|
||||
})
|
||||
} else if (this.environments[this.selectedEnvironmentIndex])
|
||||
this.$emit("use-environment", {
|
||||
environment: this.environments[this.selectedEnvironmentIndex],
|
||||
environments: this.environments,
|
||||
})
|
||||
else this.selectedEnvironmentIndex = -1
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this._keyListener = function (e) {
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault()
|
||||
this.showModalImportExport =
|
||||
this.showModalAdd =
|
||||
this.showModalEdit =
|
||||
false
|
||||
}
|
||||
}
|
||||
document.addEventListener("keydown", this._keyListener.bind(this))
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("keydown", this._keyListener)
|
||||
},
|
||||
methods: {
|
||||
displayModalAdd(shouldDisplay) {
|
||||
this.showModalAdd = shouldDisplay
|
||||
},
|
||||
displayModalEdit(shouldDisplay) {
|
||||
this.showModalEdit = shouldDisplay
|
||||
|
||||
if (!shouldDisplay) this.resetSelectedData()
|
||||
},
|
||||
displayModalImportExport(shouldDisplay) {
|
||||
this.showModalImportExport = shouldDisplay
|
||||
},
|
||||
editEnvironment(environment, environmentIndex) {
|
||||
this.$data.editingEnvironment = environment
|
||||
this.$data.editingEnvironmentIndex = environmentIndex
|
||||
this.displayModalEdit(true)
|
||||
this.syncEnvironments()
|
||||
},
|
||||
resetSelectedData() {
|
||||
this.$data.editingEnvironment = undefined
|
||||
this.$data.editingEnvironmentIndex = undefined
|
||||
},
|
||||
syncEnvironments() {
|
||||
if (fb.currentUser !== null && this.SYNC_ENVIRONMENTS) {
|
||||
fb.writeEnvironments(
|
||||
JSON.parse(JSON.stringify(this.$store.state.postwoman.environments))
|
||||
)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.virtual-list {
|
||||
max-height: calc(100vh - 270px);
|
||||
}
|
||||
</style>
|
||||
@@ -1,62 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="fb.currentFeeds.length !== 0"
|
||||
class="divide-y virtual-list divide-dashed divide-brdColor"
|
||||
>
|
||||
<ul v-for="feed in fb.currentFeeds" :key="feed.id" class="flex-col">
|
||||
<div data-test="list-item" class="show-on-large-screen">
|
||||
<li class="info">
|
||||
<label data-test="list-label">
|
||||
{{ feed.label || $t("no_label") }}
|
||||
</label>
|
||||
</li>
|
||||
<button class="icon" @click="deleteFeed(feed)">
|
||||
<i class="material-icons">delete</i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="show-on-large-screen">
|
||||
<li data-test="list-message" class="info clamb-3">
|
||||
<label>{{ feed.message || $t("empty") }}</label>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
<ul v-else class="flex-col">
|
||||
<li>
|
||||
<p class="info">{{ $t("empty") }}</p>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
fb,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async deleteFeed({ id }) {
|
||||
await fb.deleteFeed(id)
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.virtual-list {
|
||||
max-height: calc(100vh - 270px);
|
||||
}
|
||||
|
||||
.clamb-3 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
@apply overflow-hidden;
|
||||
}
|
||||
</style>
|
||||
@@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<div class="flex-col">
|
||||
<div class="show-on-large-screen">
|
||||
<input
|
||||
v-model="message"
|
||||
:aria-label="$t('label')"
|
||||
type="text"
|
||||
autofocus
|
||||
:placeholder="$t('paste_a_note')"
|
||||
class="rounded-t-lg"
|
||||
@keyup.enter="formPost"
|
||||
/>
|
||||
</div>
|
||||
<div class="border-b show-on-large-screen border-brdColor">
|
||||
<input
|
||||
v-model="label"
|
||||
:aria-label="$t('label')"
|
||||
type="text"
|
||||
autofocus
|
||||
:placeholder="$t('label')"
|
||||
@keyup.enter="formPost"
|
||||
/>
|
||||
<button
|
||||
class="icon"
|
||||
:disabled="!(message || label)"
|
||||
value="Save"
|
||||
@click="formPost"
|
||||
>
|
||||
<i class="material-icons">add</i>
|
||||
<span>Add</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
message: null,
|
||||
label: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formPost() {
|
||||
if (!(this.message || this.label)) {
|
||||
return
|
||||
}
|
||||
fb.writeFeeds(this.message, this.label)
|
||||
this.message = null
|
||||
this.label = null
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,198 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<button v-close-popover class="icon" @click="signInWithGoogle">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
class="material-icons"
|
||||
>
|
||||
<path
|
||||
d="M12.24 10.285V14.4h6.806c-.275 1.765-2.056 5.174-6.806 5.174-4.095 0-7.439-3.389-7.439-7.574s3.345-7.574 7.439-7.574c2.33 0 3.891.989 4.785 1.849l3.254-3.138C18.189 1.186 15.479 0 12.24 0c-6.635 0-12 5.365-12 12s5.365 12 12 12c6.926 0 11.52-4.869 11.52-11.726 0-.788-.085-1.39-.189-1.989H12.24z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Google</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button v-close-popover class="icon" @click="signInWithGithub">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
class="material-icons"
|
||||
>
|
||||
<path
|
||||
d="M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z"
|
||||
/>
|
||||
</svg>
|
||||
<span>GitHub</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
fb,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showLoginSuccess() {
|
||||
this.$toast.info(this.$t("login_success"), {
|
||||
icon: "vpn_key",
|
||||
})
|
||||
},
|
||||
async signInWithGoogle() {
|
||||
try {
|
||||
const { additionalUserInfo } = await fb.signInUserWithGoogle()
|
||||
|
||||
if (additionalUserInfo.isNewUser) {
|
||||
this.$toast.info(`${this.$t("turn_on")} ${this.$t("sync")}`, {
|
||||
icon: "sync",
|
||||
duration: null,
|
||||
closeOnSwipe: false,
|
||||
action: {
|
||||
text: this.$t("yes"),
|
||||
onClick: (_, toastObject) => {
|
||||
fb.writeSettings("syncHistory", true)
|
||||
fb.writeSettings("syncCollections", true)
|
||||
fb.writeSettings("syncEnvironments", true)
|
||||
this.$router.push({ path: "/settings" })
|
||||
toastObject.remove()
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
this.showLoginSuccess()
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
// An error happened.
|
||||
if (err.code === "auth/account-exists-with-different-credential") {
|
||||
// Step 2.
|
||||
// User's email already exists.
|
||||
// The pending Google credential.
|
||||
const pendingCred = err.credential
|
||||
// The provider account's email address.
|
||||
const email = err.email
|
||||
// Get sign-in methods for this email.
|
||||
const methods = await fb.getSignInMethodsForEmail(email)
|
||||
|
||||
// Step 3.
|
||||
// If the user has several sign-in methods,
|
||||
// the first method in the list will be the "recommended" method to use.
|
||||
if (methods[0] === "password") {
|
||||
// Asks the user their password.
|
||||
// In real scenario, you should handle this asynchronously.
|
||||
const password = promptUserForPassword() // TODO: implement promptUserForPassword.
|
||||
|
||||
const user = await fb.signInWithEmailAndPassword(email, password)
|
||||
await user.linkWithCredential(pendingCred)
|
||||
|
||||
this.showLoginSuccess()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.$toast.info(`${this.$t("account_exists")}`, {
|
||||
icon: "vpn_key",
|
||||
duration: null,
|
||||
closeOnSwipe: false,
|
||||
action: {
|
||||
text: this.$t("yes"),
|
||||
onClick: async (_, toastObject) => {
|
||||
const { user } = await fb.signInWithGithub()
|
||||
await user.linkAndRetrieveDataWithCredential(pendingCred)
|
||||
|
||||
this.showLoginSuccess()
|
||||
|
||||
toastObject.remove()
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
async signInWithGithub() {
|
||||
try {
|
||||
const { credential, additionalUserInfo } =
|
||||
await fb.signInUserWithGithub()
|
||||
|
||||
fb.setProviderInfo(credential.providerId, credential.accessToken)
|
||||
|
||||
if (additionalUserInfo.isNewUser) {
|
||||
this.$toast.info(`${this.$t("turn_on")} ${this.$t("sync")}`, {
|
||||
icon: "sync",
|
||||
duration: null,
|
||||
closeOnSwipe: false,
|
||||
action: {
|
||||
text: this.$t("yes"),
|
||||
onClick: (_, toastObject) => {
|
||||
fb.writeSettings("syncHistory", true)
|
||||
fb.writeSettings("syncCollections", true)
|
||||
fb.writeSettings("syncEnvironments", true)
|
||||
this.$router.push({ path: "/settings" })
|
||||
toastObject.remove()
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
this.showLoginSuccess()
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
// An error happened.
|
||||
if (err.code === "auth/account-exists-with-different-credential") {
|
||||
// Step 2.
|
||||
// User's email already exists.
|
||||
// The pending Google credential.
|
||||
const pendingCred = err.credential
|
||||
// The provider account's email address.
|
||||
const email = err.email
|
||||
// Get sign-in methods for this email.
|
||||
const methods = await fb.getSignInMethodsForEmail(email)
|
||||
|
||||
// Step 3.
|
||||
// If the user has several sign-in methods,
|
||||
// the first method in the list will be the "recommended" method to use.
|
||||
if (methods[0] === "password") {
|
||||
// Asks the user their password.
|
||||
// In real scenario, you should handle this asynchronously.
|
||||
const password = promptUserForPassword() // TODO: implement promptUserForPassword.
|
||||
|
||||
const user = await fb.signInWithEmailAndPassword(email, password)
|
||||
await user.linkWithCredential(pendingCred)
|
||||
|
||||
this.showLoginSuccess()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.$toast.info(`${this.$t("account_exists")}`, {
|
||||
icon: "vpn_key",
|
||||
duration: null,
|
||||
closeOnSwipe: false,
|
||||
action: {
|
||||
text: this.$t("yes"),
|
||||
onClick: async (_, toastObject) => {
|
||||
const { user } = await fb.signInUserWithGoogle()
|
||||
await user.linkAndRetrieveDataWithCredential(pendingCred)
|
||||
|
||||
this.showLoginSuccess()
|
||||
|
||||
toastObject.remove()
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,35 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<button v-close-popover class="icon" @click="logout">
|
||||
<i class="material-icons">exit_to_app</i>
|
||||
<span>{{ $t("logout") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
fb,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async logout() {
|
||||
try {
|
||||
await fb.signOutUser()
|
||||
|
||||
this.$toast.info(this.$t("logged_out"), {
|
||||
icon: "vpn_key",
|
||||
})
|
||||
} catch (err) {
|
||||
this.$toast.show(err.message || err, {
|
||||
icon: "error",
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,132 +0,0 @@
|
||||
import { shallowMount } from "@vue/test-utils"
|
||||
import feeds from "../Feeds"
|
||||
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
jest.mock("~/helpers/fb", () => ({
|
||||
__esModule: true,
|
||||
|
||||
fb: {
|
||||
currentFeeds: [
|
||||
{
|
||||
id: "test1",
|
||||
label: "First",
|
||||
message: "First Message",
|
||||
},
|
||||
{
|
||||
id: "test2",
|
||||
label: "Second",
|
||||
},
|
||||
{
|
||||
id: "test3",
|
||||
message: "Third Message",
|
||||
},
|
||||
{
|
||||
id: "test4",
|
||||
},
|
||||
],
|
||||
deleteFeed: jest.fn(() => Promise.resolve()),
|
||||
},
|
||||
}))
|
||||
|
||||
const factory = () =>
|
||||
shallowMount(feeds, {
|
||||
mocks: {
|
||||
$t: (text) => text,
|
||||
$toast: {
|
||||
error: jest.fn(),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
fb.deleteFeed.mockClear()
|
||||
})
|
||||
|
||||
describe("feeds", () => {
|
||||
test("mounts properly when proper components are given", () => {
|
||||
const wrapper = factory()
|
||||
|
||||
expect(wrapper).toBeTruthy()
|
||||
})
|
||||
|
||||
test("renders all the current feeds", () => {
|
||||
const wrapper = factory()
|
||||
|
||||
expect(wrapper.findAll("div[data-test='list-item']").wrappers).toHaveLength(
|
||||
4
|
||||
)
|
||||
})
|
||||
|
||||
test("feeds with no label displays the 'no_label' message", () => {
|
||||
const wrapper = factory()
|
||||
|
||||
expect(
|
||||
wrapper
|
||||
.findAll("label[data-test='list-label']")
|
||||
.wrappers.map((e) => e.text())
|
||||
.filter((text) => text === "no_label")
|
||||
).toHaveLength(2)
|
||||
})
|
||||
|
||||
test("feeds with no message displays the 'empty' message", () => {
|
||||
const wrapper = factory()
|
||||
|
||||
expect(
|
||||
wrapper
|
||||
.findAll("li[data-test='list-message']")
|
||||
.wrappers.map((e) => e.text())
|
||||
.filter((text) => text === "empty")
|
||||
).toHaveLength(2)
|
||||
})
|
||||
|
||||
test("labels in the list are proper", () => {
|
||||
const wrapper = factory()
|
||||
|
||||
expect(
|
||||
wrapper
|
||||
.findAll("label[data-test='list-label']")
|
||||
.wrappers.map((e) => e.text())
|
||||
).toEqual(["First", "Second", "no_label", "no_label"])
|
||||
})
|
||||
|
||||
test("messages in the list are proper", () => {
|
||||
const wrapper = factory()
|
||||
|
||||
expect(
|
||||
wrapper
|
||||
.findAll("li[data-test='list-message']")
|
||||
.wrappers.map((e) => e.text())
|
||||
).toEqual(["First Message", "empty", "Third Message", "empty"])
|
||||
})
|
||||
|
||||
test("clicking on the delete button deletes the feed", async () => {
|
||||
const wrapper = factory()
|
||||
|
||||
const deleteButton = wrapper.find("button")
|
||||
|
||||
await deleteButton.trigger("click")
|
||||
|
||||
expect(fb.deleteFeed).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
test("correct feed is passed to from the list for deletion", async () => {
|
||||
const wrapper = factory()
|
||||
|
||||
const deleteButton = wrapper.find("button")
|
||||
|
||||
await deleteButton.trigger("click")
|
||||
|
||||
expect(fb.deleteFeed).toHaveBeenCalledWith("test1")
|
||||
})
|
||||
|
||||
test("renders the 'empty' label if no elements in the current feeds", () => {
|
||||
jest.spyOn(fb, "currentFeeds", "get").mockReturnValueOnce([])
|
||||
|
||||
const wrapper = factory()
|
||||
|
||||
expect(wrapper.findAll("li").wrappers).toHaveLength(1)
|
||||
|
||||
expect(wrapper.find("li").text()).toEqual("empty")
|
||||
})
|
||||
})
|
||||
@@ -1,92 +0,0 @@
|
||||
import { shallowMount } from "@vue/test-utils"
|
||||
import inputform from "../Inputform"
|
||||
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
jest.mock("~/helpers/fb", () => ({
|
||||
__esModule: true,
|
||||
|
||||
fb: {
|
||||
writeFeeds: jest.fn(() => Promise.resolve()),
|
||||
},
|
||||
}))
|
||||
|
||||
const factory = () =>
|
||||
shallowMount(inputform, {
|
||||
mocks: {
|
||||
$t: (text) => text,
|
||||
},
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
fb.writeFeeds.mockClear()
|
||||
})
|
||||
|
||||
describe("inputform", () => {
|
||||
test("mounts properly", () => {
|
||||
const wrapper = factory()
|
||||
|
||||
expect(wrapper).toBeTruthy()
|
||||
})
|
||||
test("calls writeFeeds when submitted properly", async () => {
|
||||
const wrapper = factory()
|
||||
|
||||
const addButton = wrapper.find("button")
|
||||
const [messageInput, labelInput] = wrapper.findAll("input").wrappers
|
||||
|
||||
await messageInput.setValue("test message")
|
||||
await labelInput.setValue("test label")
|
||||
|
||||
await addButton.trigger("click")
|
||||
|
||||
expect(fb.writeFeeds).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
test("doesn't call writeFeeds when submitted without a data", async () => {
|
||||
const wrapper = factory()
|
||||
|
||||
const addButton = wrapper.find("button")
|
||||
|
||||
await addButton.trigger("click")
|
||||
|
||||
expect(fb.writeFeeds).not.toHaveBeenCalled()
|
||||
})
|
||||
test("doesn't call writeFeeds when message or label is null", async () => {
|
||||
const wrapper = factory()
|
||||
|
||||
const addButton = wrapper.find("button")
|
||||
const [messageInput, labelInput] = wrapper.findAll("input").wrappers
|
||||
|
||||
await messageInput.setValue(null)
|
||||
await labelInput.setValue(null)
|
||||
|
||||
await addButton.trigger("click")
|
||||
|
||||
expect(fb.writeFeeds).not.toHaveBeenCalled()
|
||||
})
|
||||
test("doesn't call writeFeeds when message or label is empty", async () => {
|
||||
const wrapper = factory()
|
||||
|
||||
const addButton = wrapper.find("button")
|
||||
const [messageInput, labelInput] = wrapper.findAll("input").wrappers
|
||||
|
||||
await messageInput.setValue("")
|
||||
await labelInput.setValue("")
|
||||
|
||||
await addButton.trigger("click")
|
||||
|
||||
expect(fb.writeFeeds).not.toHaveBeenCalled()
|
||||
})
|
||||
test("calls writeFeeds with correct values", async () => {
|
||||
const wrapper = factory()
|
||||
|
||||
const addButton = wrapper.find("button")
|
||||
const [messageInput, labelInput] = wrapper.findAll("input").wrappers
|
||||
|
||||
await messageInput.setValue("test message")
|
||||
await labelInput.setValue("test label")
|
||||
|
||||
await addButton.trigger("click")
|
||||
|
||||
expect(fb.writeFeeds).toHaveBeenCalledWith("test message", "test label")
|
||||
})
|
||||
})
|
||||
@@ -1,67 +0,0 @@
|
||||
import { shallowMount, createLocalVue } from "@vue/test-utils"
|
||||
import logout from "../Logout"
|
||||
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
jest.mock("~/helpers/fb", () => ({
|
||||
__esModule: true,
|
||||
|
||||
fb: {
|
||||
signOutUser: jest.fn(() => Promise.resolve()),
|
||||
},
|
||||
}))
|
||||
|
||||
const $toast = {
|
||||
info: jest.fn(),
|
||||
show: jest.fn(),
|
||||
}
|
||||
|
||||
const localVue = createLocalVue()
|
||||
|
||||
localVue.directive("close-popover", {})
|
||||
|
||||
const factory = () =>
|
||||
shallowMount(logout, {
|
||||
mocks: {
|
||||
$t: (text) => text,
|
||||
$toast,
|
||||
},
|
||||
localVue,
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
fb.signOutUser.mockClear()
|
||||
$toast.info.mockClear()
|
||||
$toast.show.mockClear()
|
||||
})
|
||||
|
||||
describe("logout", () => {
|
||||
test("mounts properly", () => {
|
||||
const wrapper = factory()
|
||||
|
||||
expect(wrapper).toBeTruthy()
|
||||
})
|
||||
|
||||
test("clicking the logout button fires the logout firebase function", async () => {
|
||||
const wrapper = factory()
|
||||
|
||||
const button = wrapper.find("button")
|
||||
|
||||
await button.trigger("click")
|
||||
|
||||
expect(fb.signOutUser).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
test("failed signout request fires a error toast", async () => {
|
||||
fb.signOutUser.mockImplementationOnce(() =>
|
||||
Promise.reject(new Error("test reject"))
|
||||
)
|
||||
|
||||
const wrapper = factory()
|
||||
const button = wrapper.find("button")
|
||||
await button.trigger("click")
|
||||
|
||||
expect($toast.show).toHaveBeenCalledTimes(1)
|
||||
expect($toast.show).toHaveBeenCalledWith("test reject", expect.anything())
|
||||
})
|
||||
})
|
||||
@@ -1,244 +0,0 @@
|
||||
<template>
|
||||
<div class="opacity-0 show-if-initialized" :class="{ initialized }">
|
||||
<pre ref="editor" :class="styles"></pre>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ace from "ace-builds"
|
||||
import "ace-builds/webpack-resolver"
|
||||
import "ace-builds/src-noconflict/ext-language_tools"
|
||||
import "ace-builds/src-noconflict/mode-graphqlschema"
|
||||
|
||||
import * as gql from "graphql"
|
||||
import { getAutocompleteSuggestions } from "graphql-language-service-interface"
|
||||
import { defineGQLLanguageMode } from "~/helpers/syntax/gqlQueryLangMode"
|
||||
import debounce from "~/helpers/utils/debounce"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
theme: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
onRunGQLQuery: {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
styles: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
initialized: false,
|
||||
editor: null,
|
||||
cacheValue: "",
|
||||
validationSchema: null,
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
value(value) {
|
||||
if (value !== this.cacheValue) {
|
||||
this.editor.session.setValue(value, 1)
|
||||
this.cacheValue = value
|
||||
}
|
||||
},
|
||||
theme() {
|
||||
this.initialized = false
|
||||
this.editor.setTheme(`ace/theme/${this.defineTheme()}`, () => {
|
||||
this.$nextTick().then(() => {
|
||||
this.initialized = true
|
||||
})
|
||||
})
|
||||
},
|
||||
options(value) {
|
||||
this.editor.setOptions(value)
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
defineGQLLanguageMode(ace)
|
||||
|
||||
const langTools = ace.require("ace/ext/language_tools")
|
||||
|
||||
const editor = ace.edit(this.$refs.editor, {
|
||||
mode: `ace/mode/gql-query`,
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
...this.options,
|
||||
})
|
||||
|
||||
// Set the theme and show the editor only after it's been set to prevent FOUC.
|
||||
editor.setTheme(`ace/theme/${this.defineTheme()}`, () => {
|
||||
this.$nextTick().then(() => {
|
||||
this.initialized = true
|
||||
})
|
||||
})
|
||||
|
||||
// Set the theme and show the editor only after it's been set to prevent FOUC.
|
||||
editor.setTheme(`ace/theme/${this.defineTheme()}`, () => {
|
||||
this.$nextTick().then(() => {
|
||||
this.initialized = true
|
||||
})
|
||||
})
|
||||
|
||||
const completer = {
|
||||
getCompletions: (
|
||||
editor,
|
||||
_session,
|
||||
{ row, column },
|
||||
_prefix,
|
||||
callback
|
||||
) => {
|
||||
if (this.validationSchema) {
|
||||
const completions = getAutocompleteSuggestions(
|
||||
this.validationSchema,
|
||||
editor.getValue(),
|
||||
{
|
||||
line: row,
|
||||
character: column,
|
||||
}
|
||||
)
|
||||
|
||||
callback(
|
||||
null,
|
||||
completions.map(({ label, detail }) => ({
|
||||
name: label,
|
||||
value: label,
|
||||
score: 1.0,
|
||||
meta: detail,
|
||||
}))
|
||||
)
|
||||
} else {
|
||||
callback(null, [])
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
langTools.setCompleters([completer])
|
||||
|
||||
if (this.value) editor.setValue(this.value, 1)
|
||||
|
||||
this.editor = editor
|
||||
this.cacheValue = this.value
|
||||
|
||||
editor.commands.addCommand({
|
||||
name: "runGQLQuery",
|
||||
exec: () => this.onRunGQLQuery(this.editor.getValue()),
|
||||
bindKey: {
|
||||
mac: "cmd-enter",
|
||||
win: "ctrl-enter",
|
||||
},
|
||||
})
|
||||
|
||||
editor.commands.addCommand({
|
||||
name: "prettifyGQLQuery",
|
||||
exec: () => this.prettifyQuery(),
|
||||
bindKey: {
|
||||
mac: "cmd-p",
|
||||
win: "ctrl-p",
|
||||
},
|
||||
})
|
||||
|
||||
editor.on("change", () => {
|
||||
const content = editor.getValue()
|
||||
this.$emit("input", content)
|
||||
this.parseContents(content)
|
||||
this.cacheValue = content
|
||||
})
|
||||
|
||||
this.parseContents(this.value)
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.editor.destroy()
|
||||
},
|
||||
|
||||
methods: {
|
||||
prettifyQuery() {
|
||||
try {
|
||||
this.$emit("update-query", gql.print(gql.parse(this.editor.getValue())))
|
||||
} catch (e) {
|
||||
this.$toast.error(`${this.$t("gql_prettify_invalid_query")}`, {
|
||||
icon: "error",
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
defineTheme() {
|
||||
if (this.theme) {
|
||||
return this.theme
|
||||
}
|
||||
const strip = (str) =>
|
||||
str.replace(/#/g, "").replace(/ /g, "").replace(/"/g, "")
|
||||
return strip(
|
||||
window
|
||||
.getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--editor-theme")
|
||||
)
|
||||
},
|
||||
|
||||
setValidationSchema(schema) {
|
||||
this.validationSchema = schema
|
||||
this.parseContents(this.cacheValue)
|
||||
},
|
||||
|
||||
parseContents: debounce(function (content) {
|
||||
if (content !== "") {
|
||||
try {
|
||||
const doc = gql.parse(content)
|
||||
|
||||
if (this.validationSchema) {
|
||||
this.editor.session.setAnnotations(
|
||||
gql
|
||||
.validate(this.validationSchema, doc)
|
||||
.map(({ locations, message }) => ({
|
||||
row: locations[0].line - 1,
|
||||
column: locations[0].column - 1,
|
||||
text: message,
|
||||
type: "error",
|
||||
}))
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
this.editor.session.setAnnotations([
|
||||
{
|
||||
row: e.locations[0].line - 1,
|
||||
column: e.locations[0].column - 1,
|
||||
text: e.message,
|
||||
type: "error",
|
||||
},
|
||||
])
|
||||
}
|
||||
} else {
|
||||
this.editor.session.setAnnotations([])
|
||||
}
|
||||
}, 2000),
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.show-if-initialized {
|
||||
&.initialized {
|
||||
@apply opacity-100;
|
||||
}
|
||||
|
||||
& > * {
|
||||
@apply transition-none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,62 +0,0 @@
|
||||
import { mount } from "@vue/test-utils"
|
||||
import RestCard from "../rest/Card"
|
||||
|
||||
const factory = (props) => {
|
||||
return mount(RestCard, {
|
||||
propsData: props,
|
||||
stubs: {
|
||||
"v-popover": {
|
||||
template: "<div><slot /><slot name='popover' :is-open=true /></div>",
|
||||
},
|
||||
},
|
||||
mocks: {
|
||||
$t: (text) => text,
|
||||
},
|
||||
directives: {
|
||||
tooltip() {
|
||||
/* stub */
|
||||
},
|
||||
closePopover() {
|
||||
/* stub */
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const url = "https://dummydata.com/get"
|
||||
const entry = {
|
||||
type: "rest",
|
||||
url,
|
||||
method: "GET",
|
||||
status: 200,
|
||||
star: false,
|
||||
}
|
||||
describe("RestCard", () => {
|
||||
test("Mounts properly if props are given", () => {
|
||||
const wrapper = factory({ entry })
|
||||
expect(wrapper).toBeTruthy()
|
||||
})
|
||||
|
||||
test("toggle-star emitted on clicking on star button", () => {
|
||||
const wrapper = factory({ entry })
|
||||
|
||||
wrapper.find("button[data-testid='star_button']").trigger("click")
|
||||
expect(wrapper.emitted("toggle-star")).toBeTruthy()
|
||||
})
|
||||
|
||||
test("use-entry emit on clicking the restore button", async () => {
|
||||
const wrapper = factory({ entry })
|
||||
await wrapper
|
||||
.find("button[data-testid='restore_history_entry']")
|
||||
.trigger("click")
|
||||
expect(wrapper.emitted("use-entry")).toBeTruthy()
|
||||
})
|
||||
|
||||
test("delete-entry emit on clicking the delete button", async () => {
|
||||
const wrapper = factory({ entry })
|
||||
await wrapper
|
||||
.find("button[data-testid=delete_history_entry]")
|
||||
.trigger("click")
|
||||
expect(wrapper.emitted("delete-entry")).toBeTruthy()
|
||||
})
|
||||
})
|
||||
@@ -1,159 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="show-on-large-screen">
|
||||
<li>
|
||||
<input
|
||||
data-testid="'url'"
|
||||
:aria-label="$t('url')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.url"
|
||||
:placeholder="$t('empty_req_name')"
|
||||
class="bg-transparent"
|
||||
/>
|
||||
</li>
|
||||
<button
|
||||
v-tooltip="{
|
||||
content: !entry.star ? $t('add_star') : $t('remove_star'),
|
||||
}"
|
||||
data-testid="star_button"
|
||||
class="icon"
|
||||
:class="{ stared: entry.star }"
|
||||
@click="$emit('toggle-star')"
|
||||
>
|
||||
<i class="material-icons">
|
||||
{{ entry.star ? "star" : "star_border" }}
|
||||
</i>
|
||||
</button>
|
||||
<button
|
||||
v-tooltip="{
|
||||
content: expand ? $t('hide_more') : $t('show_more'),
|
||||
}"
|
||||
data-testid="query_expand"
|
||||
class="icon"
|
||||
@click="expand = !expand"
|
||||
>
|
||||
<i class="material-icons">
|
||||
{{ expand ? "unfold_less" : "unfold_more" }}
|
||||
</i>
|
||||
</button>
|
||||
<v-popover>
|
||||
<button
|
||||
v-tooltip="$t('options')"
|
||||
data-testid="options"
|
||||
class="tooltip-target icon"
|
||||
>
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
data-testid="restore_history_entry"
|
||||
class="icon"
|
||||
:aria-label="$t('restore')"
|
||||
@click="$emit('use-entry')"
|
||||
>
|
||||
<i class="material-icons">restore</i>
|
||||
<span>{{ $t("restore") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
v-close-popover
|
||||
data-testid="delete_history_entry"
|
||||
class="icon"
|
||||
:aria-label="$t('delete')"
|
||||
@click="$emit('delete-entry')"
|
||||
>
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<div class="show-on-large-screen">
|
||||
<li data-testid="'query'">
|
||||
<input
|
||||
v-for="(line, index) in query"
|
||||
:key="`line-${index}`"
|
||||
:aria-label="$t('query')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="`${line}`"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div v-if="showMore" class="show-on-large-screen">
|
||||
<li>
|
||||
<input
|
||||
v-tooltip="entry.date"
|
||||
:aria-label="$t('time')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.time"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('duration')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="`Duration: ${entry.duration}ms`"
|
||||
:placeholder="$t('no_duration')"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
<!-- <li>
|
||||
<input
|
||||
:aria-label="$t('prerequest_script')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.preRequestScript"
|
||||
:placeholder="$t('no_prerequest_script')"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li> -->
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
entry: { type: Object, default: () => {} },
|
||||
showMore: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expand: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
query() {
|
||||
return this.expand
|
||||
? this.entry.query.split("\n")
|
||||
: this.entry.query.split("\n").slice(0, 2).concat(["..."])
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.stared {
|
||||
color: #f8e81c !important;
|
||||
}
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||