mirror of
https://github.com/unraid/api.git
synced 2026-01-02 06:30:02 -06:00
Compare commits
722 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be6dbe587f | ||
|
|
fb2472399a | ||
|
|
6084b9df93 | ||
|
|
c74bdd8890 | ||
|
|
5a3e8df003 | ||
|
|
62dc8294e8 | ||
|
|
7588e0e3cf | ||
|
|
6378047bc4 | ||
|
|
ad6b6589db | ||
|
|
93980f929d | ||
|
|
19208e5fab | ||
|
|
b970fd9e6c | ||
|
|
7539a3ed75 | ||
|
|
0b8df2a43e | ||
|
|
9bc8060a83 | ||
|
|
2b163b361a | ||
|
|
741e8532ab | ||
|
|
f76c0f05fb | ||
|
|
d439fcc7bb | ||
|
|
45006a1e4c | ||
|
|
4ee85eb121 | ||
|
|
eff7507605 | ||
|
|
c311a89aee | ||
|
|
b7b4a3974b | ||
|
|
b4d48335c4 | ||
|
|
797695535e | ||
|
|
16620a249b | ||
|
|
cc18239748 | ||
|
|
8374af8ee8 | ||
|
|
5b2403ad04 | ||
|
|
c519ba28e4 | ||
|
|
0c0a63b525 | ||
|
|
d6fde34365 | ||
|
|
a4b3f8c6c3 | ||
|
|
5f29e6d5e7 | ||
|
|
1e4a4f0745 | ||
|
|
608151d84c | ||
|
|
8cbb3c4718 | ||
|
|
e784391ac3 | ||
|
|
84611d7691 | ||
|
|
dabe334072 | ||
|
|
59e48ad85c | ||
|
|
13b501a342 | ||
|
|
75474bde47 | ||
|
|
7a19c9331f | ||
|
|
8a575765a9 | ||
|
|
753f1588b8 | ||
|
|
59d6c1b678 | ||
|
|
6abddd85d2 | ||
|
|
29fd61be6c | ||
|
|
92f72e33ec | ||
|
|
26639d5139 | ||
|
|
19f9261025 | ||
|
|
e7b7caae43 | ||
|
|
4f5c367fdf | ||
|
|
321703e907 | ||
|
|
a21f39d617 | ||
|
|
3c357e7e95 | ||
|
|
f22b262830 | ||
|
|
e16763b49b | ||
|
|
133c8e0d70 | ||
|
|
1392bdeecb | ||
|
|
2fce2e9a28 | ||
|
|
430656f6af | ||
|
|
d7887c2183 | ||
|
|
ebd1a391b6 | ||
|
|
1f42bbb4aa | ||
|
|
5f59d31ab3 | ||
|
|
d8478152e9 | ||
|
|
63fcde8243 | ||
|
|
2bc9af2578 | ||
|
|
5b14be6b0f | ||
|
|
9ef56d8c05 | ||
|
|
c4204d89aa | ||
|
|
048a0a88dc | ||
|
|
7b3834ca1f | ||
|
|
0e9c91af86 | ||
|
|
a6f67060b4 | ||
|
|
3c61a615f0 | ||
|
|
073a51572a | ||
|
|
c00789865c | ||
|
|
9d1442b2ee | ||
|
|
935318dda6 | ||
|
|
dfb006e696 | ||
|
|
445f3b50b1 | ||
|
|
a12181a5e0 | ||
|
|
0cb0fc9881 | ||
|
|
42610d290d | ||
|
|
9e12407565 | ||
|
|
bb92c3f9f8 | ||
|
|
5b0971ea8d | ||
|
|
7f997663f9 | ||
|
|
8b75d6cc99 | ||
|
|
b1a993a8e9 | ||
|
|
b1a1779a8b | ||
|
|
36d8399045 | ||
|
|
6beafbe8ed | ||
|
|
a502134c0a | ||
|
|
fa16dcd801 | ||
|
|
d38f3ef49b | ||
|
|
ce92cb06b7 | ||
|
|
1d5c2c8338 | ||
|
|
0163acb7f3 | ||
|
|
5347d54b11 | ||
|
|
547ae180dd | ||
|
|
05f661e0e5 | ||
|
|
5d909a856b | ||
|
|
4d45caf258 | ||
|
|
805bc5bfc0 | ||
|
|
81d33f6b3a | ||
|
|
2a82ea4765 | ||
|
|
6bb3d55e3c | ||
|
|
8251c6f2d3 | ||
|
|
ad32cffd75 | ||
|
|
2b213619db | ||
|
|
61ee689658 | ||
|
|
904cd466db | ||
|
|
6cb28d5f8f | ||
|
|
c180728696 | ||
|
|
84752043e5 | ||
|
|
c112f19c95 | ||
|
|
9acb2926da | ||
|
|
29d216ece7 | ||
|
|
5f597f9d4c | ||
|
|
d26ddef33e | ||
|
|
21208bfcf6 | ||
|
|
6c46f9413f | ||
|
|
b56b2157fa | ||
|
|
2108ed0ecd | ||
|
|
9c5e418872 | ||
|
|
c4d731401c | ||
|
|
7e5dd07d4a | ||
|
|
62824ba76f | ||
|
|
e58410bd57 | ||
|
|
e88593620b | ||
|
|
8026ef53e8 | ||
|
|
1ecac5ee4e | ||
|
|
e7d15ee5ec | ||
|
|
c3f4cf53c1 | ||
|
|
d8a5b1711a | ||
|
|
8481c9a9fb | ||
|
|
ddfc36fd73 | ||
|
|
3cc3f27dae | ||
|
|
097415f6b8 | ||
|
|
b1d9ad7ef1 | ||
|
|
c7d4e39287 | ||
|
|
0c6f44da35 | ||
|
|
4655d72fbb | ||
|
|
4b3d6a7ba3 | ||
|
|
ed18945088 | ||
|
|
69cd92f974 | ||
|
|
74b9fd0159 | ||
|
|
ff63535b00 | ||
|
|
76711be3e8 | ||
|
|
961bcc5db6 | ||
|
|
0cfdd5a61b | ||
|
|
8d905974be | ||
|
|
132840b0ef | ||
|
|
e4ebfc8a13 | ||
|
|
8483143a40 | ||
|
|
d6fa35cdee | ||
|
|
8a374b5b27 | ||
|
|
b73623e72a | ||
|
|
bddda823e1 | ||
|
|
bb37140d40 | ||
|
|
4d8f2ddac6 | ||
|
|
5afa76043f | ||
|
|
14fe30e925 | ||
|
|
eb1c62d3d9 | ||
|
|
f62f0d3a0f | ||
|
|
e7b689c546 | ||
|
|
b9249544fc | ||
|
|
cdfb3c772b | ||
|
|
f1e53831c8 | ||
|
|
32f9c50227 | ||
|
|
a8211cef7d | ||
|
|
e338eb9788 | ||
|
|
dae57389c6 | ||
|
|
44d3d939a7 | ||
|
|
6bfd8a2687 | ||
|
|
923e929878 | ||
|
|
2ad612cef8 | ||
|
|
1756cc5b4b | ||
|
|
3a8c9b13ee | ||
|
|
daf904bc1b | ||
|
|
632775e435 | ||
|
|
e33c7583f7 | ||
|
|
55100daed4 | ||
|
|
b9d9105e3e | ||
|
|
3734730bf7 | ||
|
|
c1fe95fcb6 | ||
|
|
a1351b0469 | ||
|
|
f0395bdf47 | ||
|
|
76cf6f35dc | ||
|
|
ca94cc8602 | ||
|
|
f560df0270 | ||
|
|
bb95795a31 | ||
|
|
cbb42dc85e | ||
|
|
060a1992c4 | ||
|
|
a1cf44162a | ||
|
|
1e6fb7e3e3 | ||
|
|
336478c2e0 | ||
|
|
895d5857f9 | ||
|
|
5ca225fe7a | ||
|
|
6faef27d7c | ||
|
|
bc04129342 | ||
|
|
b63720a6f2 | ||
|
|
29a8689ad8 | ||
|
|
3042ffa37e | ||
|
|
942b143fba | ||
|
|
75d7e08824 | ||
|
|
f30292484d | ||
|
|
3867dfacb2 | ||
|
|
0da77d7119 | ||
|
|
09f741557b | ||
|
|
ae753d6bea | ||
|
|
56cfa84794 | ||
|
|
065211413d | ||
|
|
1854aa9f28 | ||
|
|
cb59090698 | ||
|
|
81f051e02c | ||
|
|
11ff890bcc | ||
|
|
3abf20b347 | ||
|
|
6f5edb2406 | ||
|
|
428ad15ec7 | ||
|
|
bd584902e0 | ||
|
|
aae38e3404 | ||
|
|
e5d1146613 | ||
|
|
b3551a1b69 | ||
|
|
76a9ae9386 | ||
|
|
92799312c9 | ||
|
|
b969f3a9ab | ||
|
|
3419837eb5 | ||
|
|
2b25537e26 | ||
|
|
2d3892deb8 | ||
|
|
0ab40fefda | ||
|
|
58f65eabba | ||
|
|
89d756ef4e | ||
|
|
a1a046f900 | ||
|
|
d844903d78 | ||
|
|
29ca5829ff | ||
|
|
27049d9d91 | ||
|
|
03e336b72f | ||
|
|
c2e29dfb5f | ||
|
|
e9bd18a409 | ||
|
|
02c197f244 | ||
|
|
6f9977eea0 | ||
|
|
05e77a4bc6 | ||
|
|
a892a3ce35 | ||
|
|
33dd90af04 | ||
|
|
7fa849d2a0 | ||
|
|
7ceac1b184 | ||
|
|
3348a47470 | ||
|
|
85cdb8f525 | ||
|
|
796cb09c61 | ||
|
|
a554bde5c2 | ||
|
|
3acc0dc9c0 | ||
|
|
c163998175 | ||
|
|
4fbbbd7f6a | ||
|
|
203c2b88ac | ||
|
|
746d1a8aaa | ||
|
|
c0d3cf5782 | ||
|
|
64d3765a9a | ||
|
|
5dd36d1836 | ||
|
|
4264557789 | ||
|
|
344b023503 | ||
|
|
0331e24a74 | ||
|
|
2b597f9f02 | ||
|
|
bd31e09bcf | ||
|
|
6c73cbf4ad | ||
|
|
4b4aadb5f1 | ||
|
|
5ddecce21c | ||
|
|
6669a963af | ||
|
|
8d386043ae | ||
|
|
16f00a0d8c | ||
|
|
a4e2a77410 | ||
|
|
91a9949a5c | ||
|
|
235746c0ba | ||
|
|
e366cad0a4 | ||
|
|
83344e05c1 | ||
|
|
61ec04cb87 | ||
|
|
a947ff14fa | ||
|
|
5dfd6d5ded | ||
|
|
71e2b70678 | ||
|
|
4daa54cfb5 | ||
|
|
7ef3729769 | ||
|
|
46a368e1b5 | ||
|
|
b53bb3f197 | ||
|
|
1935ba1a7f | ||
|
|
14abc13cc8 | ||
|
|
c3548d5122 | ||
|
|
6c54fa14b1 | ||
|
|
8b93bcea08 | ||
|
|
a6cd74dc5c | ||
|
|
aa1ef1bd4c | ||
|
|
2cdc02f64a | ||
|
|
d0819b8d02 | ||
|
|
74b3e29c74 | ||
|
|
b32f84b105 | ||
|
|
806bd633ac | ||
|
|
e5e1c43bb3 | ||
|
|
3b2d61efc2 | ||
|
|
fe98295496 | ||
|
|
b9947108a4 | ||
|
|
3c27b51ab8 | ||
|
|
2327b00d30 | ||
|
|
bf3b00fbaf | ||
|
|
4f04f93033 | ||
|
|
5dc13755df | ||
|
|
69a34aca14 | ||
|
|
bbc1e02782 | ||
|
|
e77db18870 | ||
|
|
b6805d439e | ||
|
|
f37dda16c2 | ||
|
|
88be62317f | ||
|
|
6b5e012950 | ||
|
|
e05a05926d | ||
|
|
c817cc4b7e | ||
|
|
491b5fe8bc | ||
|
|
8675653e4e | ||
|
|
1f9e282880 | ||
|
|
90cf2c8a16 | ||
|
|
729ed42329 | ||
|
|
309d221542 | ||
|
|
859440386e | ||
|
|
ceac6269b3 | ||
|
|
286ffc54e5 | ||
|
|
84f4f67ce1 | ||
|
|
8827483699 | ||
|
|
f8393eeebe | ||
|
|
5d72b5a970 | ||
|
|
1f5c6424c7 | ||
|
|
39612cd978 | ||
|
|
b1b93e2783 | ||
|
|
eff6c32ccd | ||
|
|
b1ac0f9c83 | ||
|
|
d88b1e9660 | ||
|
|
124fb610b1 | ||
|
|
143515560c | ||
|
|
f0f5a3057a | ||
|
|
4404208deb | ||
|
|
f45719fa6b | ||
|
|
acba0b0365 | ||
|
|
8760a66907 | ||
|
|
5f81c4bd27 | ||
|
|
2310d53684 | ||
|
|
5b3ec8304c | ||
|
|
7a009b6be7 | ||
|
|
be7135efdd | ||
|
|
939383e4ef | ||
|
|
0042f14ab3 | ||
|
|
3e8c101edd | ||
|
|
477c113ce1 | ||
|
|
caf797cf4a | ||
|
|
73a12496d5 | ||
|
|
cea11daf15 | ||
|
|
bb6baf9bf4 | ||
|
|
5f1a61d4aa | ||
|
|
bbf28075c6 | ||
|
|
7dcf947527 | ||
|
|
4ee42a6cf6 | ||
|
|
91de6e6c1e | ||
|
|
e2a1f27b22 | ||
|
|
4e9ab645e6 | ||
|
|
7828ef2648 | ||
|
|
dfa27e2c0d | ||
|
|
9d2405bd21 | ||
|
|
e1515a118a | ||
|
|
961c343f5d | ||
|
|
6cbb9c07e4 | ||
|
|
833a99fe18 | ||
|
|
943c907d03 | ||
|
|
d28fb24d68 | ||
|
|
0c1b89ff41 | ||
|
|
cead97560c | ||
|
|
5f0446fa79 | ||
|
|
000692ca50 | ||
|
|
d8f9f03146 | ||
|
|
29035429bd | ||
|
|
5f8602b864 | ||
|
|
77558a5cd9 | ||
|
|
116efe6f72 | ||
|
|
8e0962adba | ||
|
|
d23a38960b | ||
|
|
d5f5921534 | ||
|
|
a52cc7861c | ||
|
|
0d6a0035aa | ||
|
|
0fa41f5690 | ||
|
|
45327ce01d | ||
|
|
11ce9e2644 | ||
|
|
00b8ffe87d | ||
|
|
4eda0991d6 | ||
|
|
9a869a49e3 | ||
|
|
7ef3286191 | ||
|
|
cb91fbb054 | ||
|
|
c6547a51fc | ||
|
|
24435613f8 | ||
|
|
4a29fc9dda | ||
|
|
2ef9fbb20e | ||
|
|
a09f7c935d | ||
|
|
29d9371cc3 | ||
|
|
ef82ec5af5 | ||
|
|
cf72c8b359 | ||
|
|
0705764385 | ||
|
|
ea6ae83919 | ||
|
|
478254e134 | ||
|
|
8f5814589e | ||
|
|
dab6985297 | ||
|
|
e40a9ebecd | ||
|
|
bc4708f405 | ||
|
|
99704a9dbb | ||
|
|
23b1f1ac73 | ||
|
|
a5cf63fe28 | ||
|
|
78ec4663cc | ||
|
|
a3b171f58d | ||
|
|
060fb91546 | ||
|
|
af1994cb62 | ||
|
|
bad7f71fea | ||
|
|
a355a64136 | ||
|
|
cf08627725 | ||
|
|
6962cdd214 | ||
|
|
a39da15be4 | ||
|
|
bb555f8296 | ||
|
|
9a0d63d4ee | ||
|
|
9bbab0f86c | ||
|
|
349145ba53 | ||
|
|
c12d8dae4e | ||
|
|
b1a2ba78cc | ||
|
|
2409ef2dd6 | ||
|
|
0055637602 | ||
|
|
547b75a55e | ||
|
|
c36082e82b | ||
|
|
0f3bebf859 | ||
|
|
96f3902b57 | ||
|
|
b9cd8c426d | ||
|
|
7c8e8a0e53 | ||
|
|
801abac06b | ||
|
|
3fe13d5235 | ||
|
|
eeb3289ae8 | ||
|
|
939d7a304d | ||
|
|
acccb3694c | ||
|
|
2724485989 | ||
|
|
2f4ff21986 | ||
|
|
83e00c640a | ||
|
|
abcaa5aedb | ||
|
|
4c663dc69c | ||
|
|
89eb841b20 | ||
|
|
7296195495 | ||
|
|
696b55de6c | ||
|
|
aa5fad39f3 | ||
|
|
9c38fa6a9c | ||
|
|
da5d1132d1 | ||
|
|
001be86181 | ||
|
|
ecfc797e7d | ||
|
|
dffbfc2dab | ||
|
|
e5f029830b | ||
|
|
1a33e6343a | ||
|
|
69441d890e | ||
|
|
46c82ecae3 | ||
|
|
0b469f5b3f | ||
|
|
3fc41480a2 | ||
|
|
e27776df3d | ||
|
|
abd8e09908 | ||
|
|
504283f227 | ||
|
|
ff7e09e15c | ||
|
|
deb42f6a81 | ||
|
|
95d018ea05 | ||
|
|
106b2e42c0 | ||
|
|
1c5ff58d2d | ||
|
|
d7bab9f443 | ||
|
|
902c76c759 | ||
|
|
5e50f24d70 | ||
|
|
4f0210d16a | ||
|
|
ddb8772692 | ||
|
|
787f8b9bf5 | ||
|
|
61ba324ca0 | ||
|
|
a230a33df5 | ||
|
|
84b234c9cf | ||
|
|
9bfc04c2a5 | ||
|
|
e84430471d | ||
|
|
2d60045784 | ||
|
|
e9137f2553 | ||
|
|
dbe0dd5dfb | ||
|
|
9d2796f2c9 | ||
|
|
972a19be04 | ||
|
|
c8da8fe314 | ||
|
|
353132b67a | ||
|
|
88b7cbfe95 | ||
|
|
3ed1d10c98 | ||
|
|
62693cfcc0 | ||
|
|
810708f775 | ||
|
|
08f6d6df65 | ||
|
|
da673c3f2b | ||
|
|
cb463bfdd0 | ||
|
|
7177171b75 | ||
|
|
9f0ab7fa38 | ||
|
|
a32374a3ac | ||
|
|
cb6534d9d9 | ||
|
|
2eaf175515 | ||
|
|
50376a0d66 | ||
|
|
4b2007b689 | ||
|
|
72fcaca4f3 | ||
|
|
2f48ddf942 | ||
|
|
62dfa6c83a | ||
|
|
27bb375460 | ||
|
|
cc4d5bdefb | ||
|
|
f55302c130 | ||
|
|
b8dbe3f9d9 | ||
|
|
20771f61a8 | ||
|
|
b9b8bbe871 | ||
|
|
b8e61007e3 | ||
|
|
49536032df | ||
|
|
9229cf3df6 | ||
|
|
58665a4e98 | ||
|
|
885d1537b6 | ||
|
|
198cfe5015 | ||
|
|
42189dd451 | ||
|
|
6122b3c001 | ||
|
|
cda7368d3d | ||
|
|
447cecd19d | ||
|
|
7321bd0088 | ||
|
|
67e898efe1 | ||
|
|
41e5de83a2 | ||
|
|
5c020a62d6 | ||
|
|
1393e967fa | ||
|
|
f07c14354f | ||
|
|
d42a426244 | ||
|
|
125bc29166 | ||
|
|
a6333bf5a2 | ||
|
|
e8e985ad6a | ||
|
|
1a598885cc | ||
|
|
d73f267245 | ||
|
|
7c1873249e | ||
|
|
09f33a0127 | ||
|
|
db00d7442d | ||
|
|
724159314c | ||
|
|
180f115b71 | ||
|
|
eb38eb219e | ||
|
|
3da701a53b | ||
|
|
6e5b2f1f67 | ||
|
|
812053d7a4 | ||
|
|
a929c7e3b3 | ||
|
|
c0179c8351 | ||
|
|
d5c7be54b0 | ||
|
|
32478f34c2 | ||
|
|
4daa09b340 | ||
|
|
346ce91f73 | ||
|
|
cee3a6d0ef | ||
|
|
e90f606f43 | ||
|
|
05fa344454 | ||
|
|
406c400bd2 | ||
|
|
1ae466899e | ||
|
|
5178e131ce | ||
|
|
0bd11bce5a | ||
|
|
fddde33977 | ||
|
|
1f5df845eb | ||
|
|
ef54af655e | ||
|
|
bb44862b7b | ||
|
|
9709dc82ea | ||
|
|
38f0699e19 | ||
|
|
6ca9f421eb | ||
|
|
935825571b | ||
|
|
9beaa78820 | ||
|
|
420c2c1afd | ||
|
|
7c0cb07b83 | ||
|
|
c6a7137f19 | ||
|
|
44f9ba0e7f | ||
|
|
1c61e64169 | ||
|
|
cf0eeebd31 | ||
|
|
f118597e47 | ||
|
|
6f2fcffd3e | ||
|
|
8f7748404c | ||
|
|
88c2605d4f | ||
|
|
c2d645612a | ||
|
|
b20f69c208 | ||
|
|
b9cedb70ff | ||
|
|
a11978aa33 | ||
|
|
b0efcc0d51 | ||
|
|
92b5f2226e | ||
|
|
98f2603525 | ||
|
|
cfb1d50c8e | ||
|
|
545ccf1938 | ||
|
|
0c79995107 | ||
|
|
9d3397a687 | ||
|
|
11c160835a | ||
|
|
e388b37aa6 | ||
|
|
1da882b807 | ||
|
|
d9d5a24b70 | ||
|
|
24e3cad882 | ||
|
|
323a4a17cf | ||
|
|
9968e0f7df | ||
|
|
2ccc53630b | ||
|
|
d7bb3defc3 | ||
|
|
ddb8bf8a5c | ||
|
|
6234d61ae5 | ||
|
|
a665ee3ec6 | ||
|
|
7ca3efe8b8 | ||
|
|
28f4952599 | ||
|
|
7e4022518d | ||
|
|
4d1656eaa8 | ||
|
|
5b2421cb0c | ||
|
|
0578b066f1 | ||
|
|
57fdcf3e60 | ||
|
|
eb7bdb6a85 | ||
|
|
ebd671e7b6 | ||
|
|
15a1a3ac15 | ||
|
|
9a0c7fe9c8 | ||
|
|
91bcbc3d6f | ||
|
|
b3d046f4ea | ||
|
|
0f13e34562 | ||
|
|
e18cd87180 | ||
|
|
421949a9f8 | ||
|
|
8c7c580f3f | ||
|
|
c616641044 | ||
|
|
fd16243287 | ||
|
|
7352bbe77a | ||
|
|
4d33908e01 | ||
|
|
adabe92f72 | ||
|
|
958f9e57e1 | ||
|
|
ac5032df83 | ||
|
|
5f4cc07473 | ||
|
|
38524bce88 | ||
|
|
64db2f19a7 | ||
|
|
8fe1e80bbd | ||
|
|
1c4506cf50 | ||
|
|
84fe7f6df6 | ||
|
|
5c7e650b3b | ||
|
|
6cac078e15 | ||
|
|
4e555021a7 | ||
|
|
b1e2f043b1 | ||
|
|
bc69852333 | ||
|
|
2c79ccc883 | ||
|
|
c240fab58a | ||
|
|
3c50022ac3 | ||
|
|
9201136cb1 | ||
|
|
ff52f75abf | ||
|
|
eed40f7875 | ||
|
|
754d4560ea | ||
|
|
f6d09f4ba2 | ||
|
|
a1f0dac42d | ||
|
|
fff935cf02 | ||
|
|
0849468fc2 | ||
|
|
6a57924fbf | ||
|
|
57802c2ea0 | ||
|
|
924df0dc9e | ||
|
|
d04001e052 | ||
|
|
92ec931aff | ||
|
|
30f92374d0 | ||
|
|
6bfd221cd1 | ||
|
|
ceb537ae91 | ||
|
|
81b197a9aa | ||
|
|
54b4ad0df8 | ||
|
|
e84c3ebe14 | ||
|
|
81acf1d947 | ||
|
|
80bfc231e0 | ||
|
|
b1409684db | ||
|
|
14d9448e4c | ||
|
|
924fa699eb | ||
|
|
999a8e39eb | ||
|
|
5a1c85d739 | ||
|
|
ba77ff4a4c | ||
|
|
05765495c4 | ||
|
|
f7cccc8c37 | ||
|
|
85e0f7993e | ||
|
|
d5a424ebe1 | ||
|
|
01441961c3 | ||
|
|
836f64d28f | ||
|
|
79bb4e585b | ||
|
|
409e88b727 | ||
|
|
5034a8981a | ||
|
|
e61d9f195d | ||
|
|
b3e213ba04 | ||
|
|
a7ea678683 | ||
|
|
791e16ce52 | ||
|
|
173da0e65b | ||
|
|
287aabfda7 | ||
|
|
d8656cc6b3 | ||
|
|
a3500c9bc9 | ||
|
|
b513cbe614 | ||
|
|
b5c525a9c2 | ||
|
|
648b560148 | ||
|
|
6eb34c3501 | ||
|
|
21544bd2dc | ||
|
|
3e115f84d7 | ||
|
|
ba586fc438 | ||
|
|
e6cbed14a9 | ||
|
|
f531e68b87 | ||
|
|
53f718e240 | ||
|
|
de36bfab99 | ||
|
|
1e2f57a4cd | ||
|
|
46aa3a3e24 | ||
|
|
0c627d1ade | ||
|
|
f20349fb2a | ||
|
|
dc72d63481 | ||
|
|
e9efed8067 | ||
|
|
71ce064008 | ||
|
|
b67b0ea633 | ||
|
|
bf3d46d190 | ||
|
|
a1fa3462eb | ||
|
|
c84175e763 | ||
|
|
0f9fe18379 | ||
|
|
76c0d35783 | ||
|
|
3ece0d1acc | ||
|
|
0473c9b676 | ||
|
|
1956227f63 | ||
|
|
c515d08d5c | ||
|
|
0bd9820c00 | ||
|
|
0c2299cfcd | ||
|
|
12fdfac467 | ||
|
|
3fc20ec593 | ||
|
|
69a6163e29 | ||
|
|
00294699f0 | ||
|
|
90ff980a00 | ||
|
|
17e7d2a2de | ||
|
|
d2a88df5bf | ||
|
|
9471f5c918 | ||
|
|
492d45f363 | ||
|
|
2951d68f9d | ||
|
|
4857bc0478 | ||
|
|
c794a1d1a1 | ||
|
|
d2a34acfb9 | ||
|
|
3dc60b6106 |
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
||||
@elibosley @pujitm @mdatelle @zackspear
|
||||
45
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
45
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
IMPORTANT: If your issue is related to Unraid Connect features (Flash Backup, connect.myunraid.net, mothership errors with connectivity, etc.) please submit a ticket here: [LINK TO FRESHDESK FORM FOR CONNECT] and choose Unraid Connect in the dropdown.
|
||||
-->
|
||||
|
||||
## Environment
|
||||
|
||||
**Unraid OS Version:**
|
||||
<!-- Please specify your Unraid version (e.g. 7.0.0) -->
|
||||
|
||||
**Are you using a reverse proxy?**
|
||||
<!-- Please answer Yes/No. If yes, have you tested the issue by accessing your server directly? -->
|
||||
<!-- Note: Reverse proxies are not officially supported by Unraid and can cause issues with various components of Unraid OS -->
|
||||
|
||||
## Pre-submission Checklist
|
||||
<!-- Please check all that apply by replacing [ ] with [x] -->
|
||||
|
||||
- [ ] I have verified that my Unraid OS is up to date
|
||||
- [ ] I have tested this issue by accessing my server directly (not through a reverse proxy)
|
||||
- [ ] This is not an Unraid Connect related issue (if it is, please submit via the support form instead)
|
||||
|
||||
## Issue Description
|
||||
<!-- Please provide a clear and concise description of the issue -->
|
||||
|
||||
## Steps to Reproduce
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
## Expected Behavior
|
||||
<!-- What did you expect to happen? -->
|
||||
|
||||
## Actual Behavior
|
||||
<!-- What actually happened? -->
|
||||
|
||||
## Additional Context
|
||||
<!-- Add any other context, screenshots, or error messages about the problem here -->
|
||||
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
IMPORTANT: If your feature request is related to Unraid Connect features (Flash Backup, connect.myunraid.net, etc.) please submit it here: [LINK TO FRESHDESK FORM FOR CONNECT] and choose Unraid Connect in the dropdown.
|
||||
-->
|
||||
|
||||
## Is your feature request related to a problem?
|
||||
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||
|
||||
## Describe the solution you'd like
|
||||
<!-- A clear and concise description of what you want to happen -->
|
||||
|
||||
## Describe alternatives you've considered
|
||||
<!-- A clear and concise description of any alternative solutions or features you've considered -->
|
||||
|
||||
## Additional context
|
||||
<!-- Add any other context, mockups, or screenshots about the feature request here -->
|
||||
|
||||
## Environment (if relevant)
|
||||
**Unraid OS Version:**
|
||||
<!-- Please specify your Unraid version (e.g. 7.0.0) if the feature request is version-specific -->
|
||||
|
||||
## Pre-submission Checklist
|
||||
<!-- Please check all that apply by replacing [ ] with [x] -->
|
||||
|
||||
- [ ] I have searched existing issues to ensure this feature hasn't already been requested
|
||||
- [ ] This is not an Unraid Connect related feature (if it is, please submit via the support form instead)
|
||||
- [ ] I have provided clear examples or use cases for the feature
|
||||
41
.github/ISSUE_TEMPLATE/work_intent.md
vendored
Normal file
41
.github/ISSUE_TEMPLATE/work_intent.md
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
name: Work Intent
|
||||
about: Request approval for planned development work (must be approved before starting)
|
||||
title: 'Work Intent: '
|
||||
labels: work-intent, unapproved
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
IMPORTANT: This work intent must be approved by a core developer before beginning any development work.
|
||||
The 'unapproved' label will be removed once approved.
|
||||
-->
|
||||
|
||||
## Overview
|
||||
<!-- Provide a high-level description of what you want to work on and why -->
|
||||
|
||||
## Technical Approach
|
||||
<!-- Brief description of how you plan to implement this -->
|
||||
|
||||
## Scope
|
||||
<!-- Check components that will be modified -->
|
||||
- [ ] API
|
||||
- [ ] Plugin
|
||||
- [ ] Web UI
|
||||
- [ ] Build/Deploy Process
|
||||
- [ ] Documentation
|
||||
|
||||
## Timeline & Impact
|
||||
<!-- Quick details about timing and effects -->
|
||||
- Estimated time needed:
|
||||
- Potential impacts:
|
||||
|
||||
## Pre-submission Checklist
|
||||
<!-- Please check all that apply -->
|
||||
- [ ] I have searched for similar work/issues
|
||||
- [ ] I understand this needs approval before starting
|
||||
- [ ] I am willing to make adjustments based on feedback
|
||||
|
||||
<!--
|
||||
For Reviewers: Remove 'unapproved' label and add 'approved' label if accepted
|
||||
-->
|
||||
1
.github/unraid.svg
vendored
Normal file
1
.github/unraid.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 1000 1000"><defs><linearGradient id="a" x1="-900" x2="-100" y1="-100" y2="-900" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#e32929"/><stop offset="1" stop-color="#ff8d30"/></linearGradient></defs><path fill="url(#a)" d="M1000 500.1v376.4c0 57.5-43.4 110.1-100 120.9-8.4 1.6-17.1 2.5-25.6 2.5-250.1.1-500.2.1-750.3.1-61.3 0-114.8-47-122.8-108q-.3-2.1-.6-4.1-.2-2-.3-4.1-.2-2-.3-4v-4.1C0 624.9 0 374.2 0 123.5 0 66 43.4 13.3 100 2.6 108.4 1 117.1.1 125.6.1 375.9 0 626.2 0 876.5 0 934 0 986.7 43.4 997.4 100c1.5 8.4 2.5 17.1 2.5 25.6.1 124.8.1 249.7.1 374.5z"/><path fill="#fff" d="M481.6 392.1h36.5v216.2h-36.5zm-356 0h36.5v216.2h-36.5zm178 242h36.5v82.5h-36.5zm-89.3-92.7h36.5v133.7h-36.5zm178 0h36.5V675h-36.5zm445.8-149.3h36.5v216.1h-36.5zm-178-107.8h36.5v82.6h-36.5zm89.3 41.5h36.5v133.1h-36.5zm-178.6 0h36.5v133h-36.5z"/></svg>
|
||||
|
After Width: | Height: | Size: 915 B |
59
.github/workflows/create-docusaurus-pr.yml
vendored
Normal file
59
.github/workflows/create-docusaurus-pr.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
name: Update API Documentation
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'api/docs/**'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# Add permissions for GITHUB_TOKEN
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
jobs:
|
||||
create-docs-pr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout source repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: source-repo
|
||||
|
||||
- name: Checkout docs repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: unraid/docs
|
||||
path: docs-repo
|
||||
token: ${{ secrets.DOCS_PAT_UNRAID_BOT }}
|
||||
|
||||
- name: Copy updated docs
|
||||
run: |
|
||||
if [ ! -d "source-repo/api/docs" ]; then
|
||||
echo "Source directory does not exist!"
|
||||
exit 1
|
||||
fi
|
||||
rm -rf docs-repo/docs/API/
|
||||
mkdir -p docs-repo/docs/API
|
||||
cp -r source-repo/api/docs/public/. docs-repo/docs/API/
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ secrets.DOCS_PAT_UNRAID_BOT }}
|
||||
path: docs-repo
|
||||
commit-message: 'docs: update API documentation'
|
||||
title: 'Update API Documentation'
|
||||
body: |
|
||||
This PR updates the API documentation based on changes from the main repository.
|
||||
|
||||
Changes were automatically generated from api/docs/* directory.
|
||||
|
||||
@coderabbitai ignore
|
||||
reviewers: ljm42, elibosley, pujitm, mdatelle
|
||||
branch: update-api-docs
|
||||
base: main
|
||||
delete-branch: true
|
||||
74
.github/workflows/lint-test-build-web.yml
vendored
74
.github/workflows/lint-test-build-web.yml
vendored
@@ -1,74 +0,0 @@
|
||||
name: Lint, Test, and Build Web Components
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
lint-web:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: web
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create env file
|
||||
run: |
|
||||
touch .env
|
||||
echo VITE_ACCOUNT=${{ vars.VITE_ACCOUNT }} >> .env
|
||||
echo VITE_CONNECT=${{ vars.VITE_CONNECT }} >> .env
|
||||
echo VITE_UNRAID_NET=${{ vars.VITE_UNRAID_NET }} >> .env
|
||||
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
|
||||
cat .env
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: "npm"
|
||||
cache-dependency-path: "web/package-lock.json"
|
||||
node-version-file: "web/.nvmrc"
|
||||
|
||||
- name: Installing node deps
|
||||
run: npm install
|
||||
|
||||
- name: Lint files
|
||||
run: npm run lint
|
||||
|
||||
build-web:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: web
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint-web]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create env file
|
||||
run: |
|
||||
touch .env
|
||||
echo VITE_ACCOUNT=${{ vars.VITE_ACCOUNT }} >> .env
|
||||
echo VITE_CONNECT=${{ vars.VITE_CONNECT }} >> .env
|
||||
echo VITE_UNRAID_NET=${{ vars.VITE_UNRAID_NET }} >> .env
|
||||
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
|
||||
cat .env
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: "npm"
|
||||
cache-dependency-path: "web/package-lock.json"
|
||||
node-version-file: "web/.nvmrc"
|
||||
|
||||
- name: Installing node deps
|
||||
run: npm install
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Upload build to Github artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: unraid-web
|
||||
path: web/.nuxt/nuxt-custom-elements/dist/unraid-components
|
||||
489
.github/workflows/main.yml
vendored
489
.github/workflows/main.yml
vendored
@@ -1,6 +1,7 @@
|
||||
name: CI - Main (API)
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
@@ -13,6 +14,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
release-please:
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -32,153 +34,122 @@ jobs:
|
||||
- name: Validate branch and tag
|
||||
run: exit 0
|
||||
|
||||
lint-api:
|
||||
continue-on-error: true
|
||||
defaults:
|
||||
run:
|
||||
working-directory: api
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Reconfigure git to use HTTP authenti:cation
|
||||
run: >
|
||||
git config --global url."https://github.com/".insteadOf
|
||||
ssh://git@github.com/
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: "api/.nvmrc"
|
||||
|
||||
# - name: Get npm cache directory
|
||||
# id: npm-cache
|
||||
# run: echo "::set-output name=dir::$(npm config get cache)"
|
||||
|
||||
# - name: Load npm cache
|
||||
# uses: actions/cache@v3
|
||||
# with:
|
||||
# path: ${{ steps.npm-cache.outputs.dir }}
|
||||
# key: ${{ runner.os }}-npm-cache-${{ hashFiles('**/package-lock.json') }}
|
||||
|
||||
- name: Install libvirt-dev
|
||||
run: sudo apt-get update && sudo apt-get install libvirt-dev
|
||||
|
||||
- name: Installing node deps
|
||||
run: npm install
|
||||
|
||||
- name: Lint files
|
||||
run: npm run lint
|
||||
|
||||
test-api:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: api
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Reconfigure git to use HTTP authentication
|
||||
run: >
|
||||
git config --global url."https://github.com/".insteadOf
|
||||
ssh://git@github.com/
|
||||
|
||||
- name: Build Docker Compose
|
||||
run: |
|
||||
docker network create mothership_default
|
||||
GIT_SHA=$(git rev-parse --short HEAD) IS_TAGGED=$(git describe --tags --abbrev=0 --exact-match || echo '') docker compose build builder
|
||||
|
||||
- name: Run Docker Compose
|
||||
run: GIT_SHA=$(git rev-parse --short HEAD) IS_TAGGED=$(git describe --tags --abbrev=0 --exact-match || echo '') docker compose run builder npm run coverage
|
||||
|
||||
lint-web:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: web
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create env file
|
||||
run: |
|
||||
touch .env
|
||||
echo VITE_ACCOUNT=${{ vars.VITE_ACCOUNT }} >> .env
|
||||
echo VITE_CONNECT=${{ vars.VITE_CONNECT }} >> .env
|
||||
echo VITE_UNRAID_NET=${{ vars.VITE_UNRAID_NET }} >> .env
|
||||
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
|
||||
cat .env
|
||||
|
||||
- name: Install node
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: "npm"
|
||||
cache-dependency-path: "web/package-lock.json"
|
||||
node-version-file: "web/.nvmrc"
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Installing node deps
|
||||
run: npm install
|
||||
- name: Cache APT Packages
|
||||
uses: awalsh128/cache-apt-pkgs-action@v1.4.3
|
||||
with:
|
||||
packages: bash procps python3 libvirt-dev jq zstd git build-essential
|
||||
version: 1.0
|
||||
|
||||
- name: Lint files
|
||||
run: npm run lint
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v4
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: PNPM Install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Lint
|
||||
run: pnpm run lint
|
||||
|
||||
- name: Test
|
||||
run: pnpm run coverage
|
||||
|
||||
build-api:
|
||||
name: Build and Test API
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: api
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
API_VERSION: ${{ steps.build-pack-binary.outputs.API_VERSION }}
|
||||
API_MD5: ${{ steps.set-hashes.outputs.API_MD5 }}
|
||||
API_SHA256: ${{ steps.set-hashes.outputs.API_SHA256 }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Add SSH deploy key
|
||||
uses: shimataro/ssh-key-action@v2
|
||||
with:
|
||||
key: ${{ secrets.UNRAID_BOT_SSH_KEY }}
|
||||
known_hosts: ${{ secrets.KNOWN_HOSTS }}
|
||||
|
||||
- name: Install node
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: "api/.nvmrc"
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Install libvirt-dev
|
||||
run: sudo apt-get update && sudo apt-get install libvirt-dev
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 10
|
||||
run_install: false
|
||||
|
||||
- name: Installing node deps
|
||||
run: npm install
|
||||
|
||||
- name: Install pkg and node-prune
|
||||
run: npm i -g pkg && curl -sf https://gobinaries.com/tj/node-prune | sh
|
||||
|
||||
# See https://github.com/apollographql/subscriptions-transport-ws/issues/433
|
||||
- name: Patch subscriptions-transport-ws
|
||||
run: npm run patch:subscriptions-transport-ws
|
||||
|
||||
|
||||
- name: Build and Pack
|
||||
id: build-pack-binary
|
||||
run: WORKDIR=${{ github.workspace }} && npm run build-pkg
|
||||
|
||||
- name: Set Hashes
|
||||
id: set-hashes
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: |
|
||||
API_MD5=$(md5sum ${{ github.workspace }}/api/deploy/release/*.tgz | awk '{ print $1 }')
|
||||
API_SHA256=$(sha256sum ${{ github.workspace }}/api/deploy/release/*.tgz | awk '{ print $1 }')
|
||||
echo "::set-output name=API_MD5::${API_MD5}"
|
||||
echo "::set-output name=API_SHA256::${API_SHA256}"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v4
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Cache APT Packages
|
||||
uses: awalsh128/cache-apt-pkgs-action@v1.4.3
|
||||
with:
|
||||
packages: bash procps python3 libvirt-dev jq zstd git build-essential
|
||||
version: 1.0
|
||||
|
||||
- name: PNPM Install
|
||||
run: |
|
||||
cd ${{ github.workspace }}
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
- name: Lint
|
||||
run: pnpm run lint
|
||||
|
||||
- name: Type Check
|
||||
run: pnpm run type-check
|
||||
continue-on-error: true
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build
|
||||
|
||||
- name: Get Git Short Sha and API version
|
||||
id: vars
|
||||
run: |
|
||||
GIT_SHA=$(git rev-parse --short HEAD)
|
||||
IS_TAGGED=$(git describe --tags --abbrev=0 --exact-match || echo '')
|
||||
PACKAGE_LOCK_VERSION=$(jq -r '.version' package.json)
|
||||
API_VERSION=$([[ -n "$IS_TAGGED" ]] && echo "$PACKAGE_LOCK_VERSION" || echo "${PACKAGE_LOCK_VERSION}+${GIT_SHA}")
|
||||
export API_VERSION
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build-and-pack
|
||||
|
||||
- name: Upload tgz to Github artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -186,14 +157,70 @@ jobs:
|
||||
name: unraid-api
|
||||
path: ${{ github.workspace }}/api/deploy/release/*.tgz
|
||||
|
||||
build-unraid-ui-webcomponents:
|
||||
name: Build Unraid UI Library (Webcomponent Version)
|
||||
defaults:
|
||||
run:
|
||||
working-directory: unraid-ui
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 10
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v4
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Cache APT Packages
|
||||
uses: awalsh128/cache-apt-pkgs-action@v1.4.3
|
||||
with:
|
||||
packages: bash procps python3 libvirt-dev jq zstd git build-essential
|
||||
version: 1.0
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
cd ${{ github.workspace }}
|
||||
pnpm install --frozen-lockfile --filter @unraid/ui
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build:wc
|
||||
|
||||
- name: Upload Artifact to Github
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: unraid-wc-ui
|
||||
path: unraid-ui/dist/
|
||||
|
||||
build-web:
|
||||
# needs: [build-unraid-ui]
|
||||
name: Build Web App
|
||||
environment:
|
||||
name: production
|
||||
defaults:
|
||||
run:
|
||||
working-directory: web
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: production
|
||||
needs: [lint-web]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
@@ -207,27 +234,60 @@ jobs:
|
||||
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
|
||||
cat .env
|
||||
|
||||
- name: Install node
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: "npm"
|
||||
cache-dependency-path: "web/package-lock.json"
|
||||
node-version-file: "web/.nvmrc"
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Installing node deps
|
||||
run: npm install
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 10
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v4
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: PNPM Install
|
||||
run: |
|
||||
cd ${{ github.workspace }}
|
||||
pnpm install --frozen-lockfile --filter @unraid/web --filter @unraid/ui
|
||||
|
||||
- name: Build Unraid UI
|
||||
run: |
|
||||
cd ${{ github.workspace }}/unraid-ui
|
||||
pnpm run build
|
||||
- name: Lint files
|
||||
continue-on-error: true
|
||||
run: pnpm run lint
|
||||
|
||||
- name: Test
|
||||
run: pnpm run test:ci
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
run: pnpm run build
|
||||
|
||||
- name: Upload build to Github artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: unraid-web
|
||||
name: unraid-wc-rich
|
||||
path: web/.nuxt/nuxt-custom-elements/dist/unraid-components
|
||||
|
||||
build-plugin:
|
||||
needs: [lint-api, lint-web, test-api, build-api, build-web]
|
||||
needs: [build-api, build-web, build-unraid-ui-webcomponents]
|
||||
outputs:
|
||||
tag: ${{ steps.build-plugin.outputs.tag }}
|
||||
defaults:
|
||||
run:
|
||||
working-directory: plugin
|
||||
@@ -239,34 +299,124 @@ jobs:
|
||||
timezoneLinux: "America/Los_Angeles"
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
- name: Download unraid web components
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 10
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v4
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
cd ${{ github.workspace }}
|
||||
pnpm install --frozen-lockfile --filter @unraid/connect-plugin
|
||||
|
||||
- name: Download Unraid Web Components
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: unraid-web
|
||||
pattern: unraid-wc-*
|
||||
path: ./plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components
|
||||
- name: Build Plugin
|
||||
merge-multiple: true
|
||||
- name: Download Unraid API
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: unraid-api
|
||||
path: /tmp/unraid-api/
|
||||
- name: Extract Unraid API and Build Plugin
|
||||
id: build-plugin
|
||||
run: |
|
||||
cd source/dynamix.unraid.net
|
||||
export API_VERSION=${{needs.build-api.outputs.API_VERSION}}
|
||||
export API_MD5=${{needs.build-api.outputs.API_MD5}}
|
||||
export API_SHA256=${{needs.build-api.outputs.API_SHA256}}
|
||||
bash ./pkg_build.sh s
|
||||
bash ./pkg_build.sh p
|
||||
tar -xzf /tmp/unraid-api/unraid-api.tgz -C ${{ github.workspace }}/plugin/source/dynamix.unraid.net/usr/local/unraid-api
|
||||
cd ${{ github.workspace }}/plugin
|
||||
|
||||
if [ -n "${{ github.event.pull_request.number }}" ]; then
|
||||
export TAG=PR${{ github.event.pull_request.number }}
|
||||
# Put tag into github env
|
||||
echo "TAG=${TAG}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
pnpm run build
|
||||
- name: Upload binary txz and plg to Github artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: connect-files
|
||||
path: |
|
||||
${{ github.workspace }}/plugin/archive/*.txz
|
||||
${{ github.workspace }}/plugin/plugins/*.plg
|
||||
plugin/deploy/release/plugins/
|
||||
plugin/deploy/release/archive/*.txz
|
||||
retention-days: 5
|
||||
if-no-files-found: error
|
||||
|
||||
release-pull-request:
|
||||
if: |
|
||||
github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test-api, build-plugin]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Make PR Release Folder
|
||||
run: mkdir pr-release/
|
||||
|
||||
- name: Download plugin binary tgz
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: connect-files
|
||||
|
||||
- name: Copy other release files to pr-release
|
||||
run: |
|
||||
cp archive/*.txz pr-release/
|
||||
cp plugins/pr/dynamix.unraid.net.plg pr-release/dynamix.unraid.net.plg
|
||||
|
||||
- name: Upload to Cloudflare
|
||||
uses: jakejarvis/s3-sync-action@v0.5.1
|
||||
env:
|
||||
AWS_S3_ENDPOINT: ${{ secrets.CF_ENDPOINT }}
|
||||
AWS_S3_BUCKET: ${{ secrets.CF_BUCKET_PREVIEW }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.CF_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_SECRET_ACCESS_KEY }}
|
||||
AWS_REGION: "auto"
|
||||
SOURCE_DIR: pr-release
|
||||
DEST_DIR: unraid-api/tag/${{ needs.build-plugin.outputs.tag }}
|
||||
- name: Comment URL
|
||||
uses: thollander/actions-comment-pull-request@v3
|
||||
with:
|
||||
comment-tag: prlink
|
||||
mode: recreate
|
||||
message: |
|
||||
This plugin has been deployed to Cloudflare R2 and is available for testing.
|
||||
Download it at this URL:
|
||||
```
|
||||
https://preview.dl.unraid.net/unraid-api/tag/${{ needs.build-plugin.outputs.tag }}/dynamix.unraid.net.plg
|
||||
```
|
||||
|
||||
release-staging:
|
||||
environment:
|
||||
name: staging
|
||||
# Only release if this is a push to the main branch
|
||||
if: startsWith(github.ref, 'refs/heads/main')
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-plugin]
|
||||
needs: [test-api, build-plugin]
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
@@ -275,40 +425,17 @@ jobs:
|
||||
- name: Make Staging Release Folder
|
||||
run: mkdir staging-release/
|
||||
|
||||
- name: Download unraid-api binary tgz
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: unraid-api
|
||||
path: staging-release
|
||||
|
||||
- name: Download plugin binary tgz
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: connect-files
|
||||
|
||||
- name: Parse Changelog
|
||||
id: changelog
|
||||
uses: ocavue/changelog-parser-action@v1
|
||||
with:
|
||||
removeMarkdown: false
|
||||
filePath: "./api/CHANGELOG.md"
|
||||
|
||||
- name: Run LS in unraid-api folder
|
||||
- name: Copy Files for Staging Release
|
||||
run: |
|
||||
cp archive/dynamix.unraid.net.staging-*.txz staging-release/
|
||||
cp plugins/dynamix.unraid.net.staging.plg staging-release/
|
||||
cp archive/*.txz staging-release/
|
||||
cp plugins/staging/dynamix.unraid.net.plg staging-release/dynamix.unraid.net.plg
|
||||
ls -al staging-release
|
||||
|
||||
- name: Upload Staging Plugin to DO Spaces
|
||||
uses: BetaHuhn/do-spaces-action@v2
|
||||
with:
|
||||
access_key: ${{ secrets.DO_ACCESS_KEY }}
|
||||
secret_key: ${{ secrets.DO_SECRET_KEY }}
|
||||
space_name: ${{ secrets.DO_SPACE_NAME }}
|
||||
space_region: ${{ secrets.DO_SPACE_REGION }}
|
||||
source: staging-release
|
||||
out_dir: unraid-api
|
||||
|
||||
- name: Upload Staging Plugin to Cloudflare Bucket
|
||||
uses: jakejarvis/s3-sync-action@v0.5.1
|
||||
env:
|
||||
@@ -316,40 +443,38 @@ jobs:
|
||||
AWS_S3_BUCKET: ${{ secrets.CF_BUCKET_PREVIEW }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.CF_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_SECRET_ACCESS_KEY }}
|
||||
AWS_REGION: 'auto'
|
||||
AWS_REGION: "auto"
|
||||
SOURCE_DIR: staging-release
|
||||
DEST_DIR: unraid-api
|
||||
|
||||
|
||||
create-draft-release:
|
||||
# Only create new draft if this is a version tag
|
||||
if: |
|
||||
startsWith(github.ref, 'refs/tags/v')
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-plugin]
|
||||
|
||||
needs: [test-api, build-plugin]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download unraid-api binary tgz
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: unraid-api
|
||||
|
||||
- name: Download plugin binary tgz
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: connect-files
|
||||
|
||||
- name: Move Files to Release Folder
|
||||
run: |
|
||||
mkdir -p release/
|
||||
mv unraid-api-*.tgz release/
|
||||
mv plugins/production/dynamix.unraid.net.plg release/
|
||||
mv archive/* release/
|
||||
|
||||
- name: Create Github release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: true
|
||||
prerelease: false
|
||||
files: |
|
||||
unraid-api-*.tgz
|
||||
plugins/dynamix.unraid.net*
|
||||
archive/dynamix.unraid.net*
|
||||
release/*
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
82
.github/workflows/pull-request-web.yml
vendored
82
.github/workflows/pull-request-web.yml
vendored
@@ -1,82 +0,0 @@
|
||||
name: Pull Request Web
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'web/**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-web
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint-web:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: web
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create env file
|
||||
run: |
|
||||
touch .env
|
||||
echo VITE_ACCOUNT=${{ vars.VITE_ACCOUNT }} >> .env
|
||||
echo VITE_CONNECT=${{ vars.VITE_CONNECT }} >> .env
|
||||
echo VITE_UNRAID_NET=${{ vars.VITE_UNRAID_NET }} >> .env
|
||||
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
|
||||
cat .env
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: "npm"
|
||||
cache-dependency-path: "web/package-lock.json"
|
||||
node-version-file: "web/.nvmrc"
|
||||
|
||||
- name: Installing node deps
|
||||
run: npm install
|
||||
|
||||
- name: Lint files
|
||||
run: npm run lint
|
||||
|
||||
build-web:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: web
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: production
|
||||
needs: [lint-web]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create env file
|
||||
run: |
|
||||
touch .env
|
||||
echo VITE_ACCOUNT=${{ vars.VITE_ACCOUNT }} >> .env
|
||||
echo VITE_CONNECT=${{ vars.VITE_CONNECT }} >> .env
|
||||
echo VITE_UNRAID_NET=${{ vars.VITE_UNRAID_NET }} >> .env
|
||||
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
|
||||
cat .env
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: "npm"
|
||||
cache-dependency-path: "web/package-lock.json"
|
||||
node-version-file: "web/.nvmrc"
|
||||
|
||||
- name: Installing node deps
|
||||
run: npm install
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Upload build to Github artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: unraid-web
|
||||
path: web/.nuxt/nuxt-custom-elements/dist/unraid-components
|
||||
183
.github/workflows/pull-request.yml
vendored
183
.github/workflows/pull-request.yml
vendored
@@ -1,183 +0,0 @@
|
||||
name: Pull Request
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- api/**
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint-api:
|
||||
services:
|
||||
registry: # Using a local registry is ~3x faster than exporting the image to docker agent
|
||||
image: registry:2
|
||||
ports:
|
||||
- 5000:5000
|
||||
|
||||
continue-on-error: true
|
||||
defaults:
|
||||
run:
|
||||
working-directory: api
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: true
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
# network=host driver-opt needed to push to local registry
|
||||
driver-opts: network=host
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: api
|
||||
target: builder
|
||||
push: true
|
||||
tags: localhost:5000/unraid-api:builder
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
- name: Lint
|
||||
run: |
|
||||
docker run localhost:5000/unraid-api:builder npm run lint
|
||||
|
||||
test-api:
|
||||
services:
|
||||
registry: # Using a local registry is ~3x faster than exporting the image to docker agent
|
||||
image: registry:2
|
||||
ports:
|
||||
- 5000:5000
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: api
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: true
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
# network=host driver-opt needed to push to local registry
|
||||
driver-opts: network=host
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: api
|
||||
target: builder
|
||||
push: true
|
||||
tags: localhost:5000/unraid-api:builder
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
- name: Test
|
||||
run: |
|
||||
docker run localhost:5000/unraid-api:builder npm run coverage
|
||||
|
||||
build-api:
|
||||
services:
|
||||
registry: # Using a local registry is ~3x faster than exporting the image to docker agent
|
||||
image: registry:2
|
||||
ports:
|
||||
- 5000:5000
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: api
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
API_VERSION: ${{ steps.build-pack-binary.outputs.API_VERSION }}
|
||||
API_MD5: ${{ steps.set-hashes.outputs.API_MD5 }}
|
||||
API_SHA256: ${{ steps.set-hashes.outputs.API_SHA256 }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: true
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
# network=host driver-opt needed to push to local registry
|
||||
driver-opts: network=host
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: api
|
||||
target: builder
|
||||
push: true
|
||||
tags: localhost:5000/unraid-api:builder
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Run Build
|
||||
run: docker run -e GIT_SHA=$(git rev-parse --short HEAD) -e IS_TAGGED=$(git describe --tags --abbrev=0 --exact-match) -v $(pwd)/deploy:/app/deploy/ localhost:5000/unraid-api:builder npm run build-pkg
|
||||
|
||||
- name: Set Hashes
|
||||
id: set-hashes
|
||||
run: |
|
||||
API_MD5=$(md5sum ${{ github.workspace }}/api/deploy/release/*.tgz | awk '{ print $1 }')
|
||||
API_SHA256=$(sha256sum ${{ github.workspace }}/api/deploy/release/*.tgz | awk '{ print $1 }')
|
||||
echo "::set-output name=API_MD5::${API_MD5}"
|
||||
echo "::set-output name=API_SHA256::${API_SHA256}"
|
||||
|
||||
- name: Upload tgz to Github artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: unraid-api
|
||||
path: ${{ github.workspace }}/api/deploy/release/*.tgz
|
||||
|
||||
- name: Parse Changelog
|
||||
id: changelog
|
||||
uses: ocavue/changelog-parser-action@v1
|
||||
with:
|
||||
removeMarkdown: false
|
||||
filePath: "./api/CHANGELOG.md"
|
||||
|
||||
- name: View release notes
|
||||
run: |
|
||||
escapedNotes=$(sed -e 's/[&\\/]/\\&/g; s/$/\\/' -e '$s/\\$//' <<<"${{steps.changelog.outputs.latestBody}}")
|
||||
echo "${escapedNotes}"
|
||||
build-plugin:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: plugin
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint-api, test-api, build-api]
|
||||
steps:
|
||||
- name: Set Timezone
|
||||
uses: szenius/set-timezone@v1.2
|
||||
with:
|
||||
timezoneLinux: "America/Los_Angeles"
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
- name: Build Plugin
|
||||
run: |
|
||||
cd source/dynamix.unraid.net
|
||||
export API_VERSION=${{needs.build-api.outputs.API_VERSION}}
|
||||
export API_MD5=${{needs.build-api.outputs.API_MD5}}
|
||||
export API_SHA256=${{needs.build-api.outputs.API_SHA256}}
|
||||
bash ./pkg_build.sh s
|
||||
bash ./pkg_build.sh p
|
||||
- name: Create release notes
|
||||
run: |
|
||||
LAST_RELEASE=$(git tag --list --sort=v:refname | tail -1)
|
||||
echo ${LAST_RELEASE}
|
||||
RELEASE_NOTES=$(git log "$LAST_RELEASE...HEAD" --pretty=format:"- %s [\`%h\`](http://github.com/$GITHUB_REPOSITORY/commit/%H)" --reverse)
|
||||
echo "${RELEASE_NOTES}"
|
||||
# escapedNotes=$(sed -e 's/[&\\/]/\\&/g; s/$/\\/' -e '$s/\\$//' <<<"${RELEASE_NOTES}")
|
||||
# sed -i -z -E "s/<CHANGES>(.*)<\/CHANGES>/<CHANGES>\n${escapedNotes}\n<\/CHANGES>/g" "plugins/dynamix.unraid.net.staging.plg"
|
||||
- name: Upload binary txz and plg to Github artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: connect-files
|
||||
path: |
|
||||
${{ github.workspace }}/plugin/archive/*.txz
|
||||
${{ github.workspace }}/plugin/plugins/*.plg
|
||||
retention-days: 5
|
||||
if-no-files-found: error
|
||||
57
.github/workflows/push-staging-pr-on-close.yml
vendored
Normal file
57
.github/workflows/push-staging-pr-on-close.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
name: Push Staging Plugin on PR Close
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- closed
|
||||
|
||||
jobs:
|
||||
push-staging:
|
||||
if: github.event.pull_request.merged == true
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Set Timezone
|
||||
uses: szenius/set-timezone@v1.2
|
||||
with:
|
||||
timezoneLinux: "America/Los_Angeles"
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: connect-files
|
||||
path: connect-files
|
||||
|
||||
- name: Update Downloaded Staging Plugin to New Date
|
||||
run: |
|
||||
if [ ! -f "connect-files/plugins/dynamix.unraid.net.pr.plg" ]; then
|
||||
echo "ERROR: dynamix.unraid.net.pr.plg not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
plgfile="connect-files/plugins/dynamix.unraid.net.pr.plg"
|
||||
version=$(date +"%Y.%m.%d.%H%M")
|
||||
sed -i -E "s#(<!ENTITY version \").*(\">)#\1${version}\2#g" "${plgfile}" || exit 1
|
||||
|
||||
# Change the plugin url to point to staging
|
||||
url="https://preview.dl.unraid.net/unraid-api/dynamix.unraid.net.plg"
|
||||
sed -i -E "s#(<!ENTITY pluginURL \").*(\">)#\1${url}\2#g" "${plgfile}" || exit 1
|
||||
cat "${plgfile}"
|
||||
mkdir -p pr-release
|
||||
mv "${plgfile}" pr-release/dynamix.unraid.net.plg
|
||||
|
||||
- name: Upload to Cloudflare
|
||||
uses: jakejarvis/s3-sync-action@v0.5.1
|
||||
env:
|
||||
AWS_S3_ENDPOINT: ${{ secrets.CF_ENDPOINT }}
|
||||
AWS_S3_BUCKET: ${{ secrets.CF_BUCKET_PREVIEW }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.CF_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_SECRET_ACCESS_KEY }}
|
||||
AWS_REGION: "auto"
|
||||
SOURCE_DIR: pr-release
|
||||
DEST_DIR: unraid-api/pr/${{ github.event.pull_request.number }}
|
||||
3
.github/workflows/release-production.yml
vendored
3
.github/workflows/release-production.yml
vendored
@@ -33,7 +33,6 @@ jobs:
|
||||
)
|
||||
escapedNotes=$(sed -e 's/[&\\/]/\\&/g; s/$/\\/' -e '$s/\\$//' <<<"$notes")
|
||||
sed -i -z -E "s/<CHANGES>(.*)<\/CHANGES>/<CHANGES>\n${escapedNotes}\n<\/CHANGES>/g" "dynamix.unraid.net.plg"
|
||||
sed -i -z -E "s/<CHANGES>(.*)<\/CHANGES>/<CHANGES>\n${escapedNotes}\n<\/CHANGES>/g" "dynamix.unraid.net.staging.plg"
|
||||
|
||||
- name: Upload All Release Files to DO Spaces
|
||||
uses: BetaHuhn/do-spaces-action@v2
|
||||
@@ -54,4 +53,4 @@ jobs:
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_SECRET_ACCESS_KEY }}
|
||||
AWS_REGION: 'auto'
|
||||
SOURCE_DIR: "."
|
||||
DEST_DIR: unraid-api
|
||||
DEST_DIR: unraid-api
|
||||
|
||||
71
.github/workflows/test-libvirt.yml
vendored
Normal file
71
.github/workflows/test-libvirt.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
name: Test Libvirt
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "libvirt/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- "libvirt/**"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./libvirt
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Cache APT Packages
|
||||
uses: awalsh128/cache-apt-pkgs-action@v1.4.3
|
||||
with:
|
||||
packages: libvirt-dev
|
||||
version: 1.0
|
||||
|
||||
- name: Set Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v4
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('libvirt/package.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build
|
||||
|
||||
- name: test
|
||||
run: pnpm run test
|
||||
13
.gitignore
vendored
13
.gitignore
vendored
@@ -24,6 +24,7 @@ build/Release
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
unraid-ui/node_modules/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
@@ -51,15 +52,20 @@ typings/
|
||||
|
||||
# Visual Studio Code workspace
|
||||
.vscode/sftp.json
|
||||
.history/
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Jetbrains Settings Files
|
||||
.idea
|
||||
|
||||
# Temp dir for tests
|
||||
test/__temp__/*
|
||||
|
||||
# Built files
|
||||
dist
|
||||
unraid-ui/storybook-static
|
||||
|
||||
# Typescript
|
||||
typescript
|
||||
@@ -70,7 +76,7 @@ typescript
|
||||
# Github actions
|
||||
RELEASE_NOTES.md
|
||||
|
||||
# Docker Deploy Folder
|
||||
# Docker Deploy Folder
|
||||
deploy/*
|
||||
!deploy/.gitkeep
|
||||
|
||||
@@ -85,4 +91,7 @@ deploy/*
|
||||
.env*
|
||||
!.env.example
|
||||
|
||||
fb_keepalive
|
||||
fb_keepalive
|
||||
|
||||
# pnpm store
|
||||
.pnpm-store
|
||||
|
||||
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
@@ -1,8 +1,6 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"natizyskunk.sftp",
|
||||
"davidanson.vscode-markdownlint",
|
||||
"bmewburn.vscode-intelephense-client",
|
||||
"foxundermoon.shell-format",
|
||||
"timonwong.shellcheck",
|
||||
"esbenp.prettier-vscode"
|
||||
|
||||
47
.vscode/settings.json
vendored
47
.vscode/settings.json
vendored
@@ -1,34 +1,15 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.page": "php"
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": "never",
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"workbench.colorCustomizations": {
|
||||
"activityBar.activeBackground": "#78797d",
|
||||
"activityBar.background": "#78797d",
|
||||
"activityBar.foreground": "#e7e7e7",
|
||||
"activityBar.inactiveForeground": "#e7e7e799",
|
||||
"activityBarBadge.background": "#df9fac",
|
||||
"activityBarBadge.foreground": "#15202b",
|
||||
"commandCenter.border": "#e7e7e799",
|
||||
"sash.hoverBorder": "#78797d",
|
||||
"statusBar.background": "#5f6063",
|
||||
"statusBar.foreground": "#e7e7e7",
|
||||
"statusBarItem.hoverBackground": "#78797d",
|
||||
"statusBarItem.remoteBackground": "#5f6063",
|
||||
"statusBarItem.remoteForeground": "#e7e7e7",
|
||||
"titleBar.activeBackground": "#5f6063",
|
||||
"titleBar.activeForeground": "#e7e7e7",
|
||||
"titleBar.inactiveBackground": "#5f606399",
|
||||
"titleBar.inactiveForeground": "#e7e7e799"
|
||||
},
|
||||
"peacock.color": "#5f6063",
|
||||
"i18n-ally.localesPaths": [
|
||||
"locales"
|
||||
],
|
||||
"i18n-ally.keystyle": "flat",
|
||||
"eslint.experimental.useFlatConfig": true,
|
||||
}
|
||||
"files.associations": {
|
||||
"*.page": "php"
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": "never",
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"i18n-ally.localesPaths": [
|
||||
"locales"
|
||||
],
|
||||
"i18n-ally.keystyle": "flat",
|
||||
"eslint.experimental.useFlatConfig": true
|
||||
}
|
||||
|
||||
1
.vscode/sftp-template.json
vendored
1
.vscode/sftp-template.json
vendored
@@ -19,3 +19,4 @@
|
||||
".DS_Store"
|
||||
]
|
||||
}
|
||||
|
||||
61
CONTRIBUTING.md
Normal file
61
CONTRIBUTING.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Contributing to Unraid Connect
|
||||
|
||||
Thank you for your interest in contributing to Unraid Connect! We want to make contributing to this project as easy and transparent as possible, whether it's:
|
||||
|
||||
- Reporting a bug
|
||||
- Discussing the current state of the code
|
||||
- Submitting a fix
|
||||
- Proposing new features
|
||||
|
||||
## Development Process
|
||||
|
||||
We use GitHub to host code, to track issues and feature requests, as well as accept pull requests.
|
||||
|
||||
### 1. Work Intent Process
|
||||
|
||||
**Before starting any development work**, you must submit a Work Intent and have it approved:
|
||||
|
||||
1. **Create a Work Intent**
|
||||
- Go to [Issues → New Issue → Work Intent](https://github.com/unraid/api/issues/new?template=work_intent.md)
|
||||
- Fill out the brief template describing what you want to work on
|
||||
- The issue will be automatically labeled as `work-intent` and `unapproved`
|
||||
|
||||
2. **Wait for Approval**
|
||||
- A core developer will review your Work Intent
|
||||
- They may ask questions or suggest changes
|
||||
- Once approved, the `unapproved` label will be removed
|
||||
|
||||
3. **Begin Development**
|
||||
- Only start coding after your Work Intent is approved
|
||||
- Follow the approach outlined in your approved Work Intent
|
||||
- Reference the Work Intent in your future PR
|
||||
|
||||
### 2. Making Changes
|
||||
|
||||
1. Fork the repo and create your branch from `main`
|
||||
2. Make your changes
|
||||
3. Ensure your commits are clear and descriptive
|
||||
4. Keep your changes focused - solve one thing at a time
|
||||
|
||||
### 3. Pull Request Process
|
||||
|
||||
1. Create a pull request from your fork to our `main` branch
|
||||
2. Reference the approved Work Intent in your PR description
|
||||
3. Ensure the PR description clearly describes the problem and solution
|
||||
4. Include screenshots or examples if applicable
|
||||
5. Wait for review from the core team
|
||||
|
||||
**Note:** Direct pushes to the main branch are not allowed. All changes must go through the PR process.
|
||||
|
||||
## Bug Reports and Feature Requests
|
||||
|
||||
We use GitHub issues to track bugs and feature requests:
|
||||
|
||||
- **Bug Report**: Use the [Bug Report Template](https://github.com/unraid/api/issues/new?template=bug_report.md)
|
||||
- **Feature Request**: Use the [Feature Request Template](https://github.com/unraid/api/issues/new?template=feature_request.md)
|
||||
|
||||
For Unraid Connect specific issues (Flash Backup, connect.myunraid.net, mothership connectivity), please submit through our support portal instead.
|
||||
|
||||
## License
|
||||
|
||||
By contributing, you agree that your contributions will be licensed under the same terms as the main project.
|
||||
@@ -1,11 +1,14 @@
|
||||
PATHS_UNRAID_DATA=./dev/data # Where we store plugin data (e.g. permissions.json)
|
||||
PATHS_STATES=./dev/states # Where .ini files live (e.g. vars.ini)
|
||||
PATHS_AUTH_SESSIONS=./dev/sessions # Where user sessions live
|
||||
PATHS_AUTH_KEY=./dev/keys # Auth key directory
|
||||
PATHS_DYNAMIX_BASE=./dev/dynamix # Dynamix's data directory
|
||||
PATHS_DYNAMIX_CONFIG_DEFAULT=./dev/dynamix/default.cfg # Dynamix's default config file, which ships with unraid
|
||||
PATHS_DYNAMIX_CONFIG=./dev/dynamix/dynamix.cfg # Dynamix's config file
|
||||
PATHS_MY_SERVERS_CONFIG=./dev/Unraid.net/myservers.cfg # My servers config file
|
||||
PATHS_MY_SERVERS_FB=./dev/Unraid.net/fb_keepalive # My servers flashbackup timekeeper file
|
||||
PATHS_KEYFILE_BASE=./dev/Unraid.net # Keyfile location
|
||||
PATHS_MACHINE_ID=./dev/data/machine-id
|
||||
|
||||
ENVIRONMENT="development"
|
||||
NODE_ENV="development"
|
||||
PORT="3001"
|
||||
@@ -14,5 +17,7 @@ INTROSPECTION=true
|
||||
MOTHERSHIP_GRAPHQL_LINK="http://authenticator:3000/graphql"
|
||||
NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||
BYPASS_PERMISSION_CHECKS=false
|
||||
BYPASS_CORS_CHECKS=false
|
||||
BYPASS_CORS_CHECKS=true
|
||||
CHOKIDAR_USEPOLLING=true
|
||||
LOG_TRANSPORT=console
|
||||
LOG_LEVEL=trace
|
||||
@@ -1,11 +1,13 @@
|
||||
VERSION="THIS_WILL_BE_REPLACED_WHEN_BUILT"
|
||||
|
||||
PATHS_UNRAID_DATA=./dev/data # Where we store plugin data (e.g. permissions.json)
|
||||
PATHS_STATES=./dev/states # Where .ini files live (e.g. vars.ini)
|
||||
PATHS_AUTH_SESSIONS=./dev/sessions # Where user sessions live
|
||||
PATHS_AUTH_KEY=./dev/keys # Auth key directory
|
||||
PATHS_DYNAMIX_BASE=./dev/dynamix # Dynamix's data directory
|
||||
PATHS_DYNAMIX_CONFIG_DEFAULT=./dev/dynamix/default.cfg # Dynamix's default config file, which ships with unraid
|
||||
PATHS_DYNAMIX_CONFIG=./dev/dynamix/dynamix.cfg # Dynamix's config file
|
||||
PATHS_MY_SERVERS_CONFIG=./dev/Unraid.net/myservers.cfg # My servers config file
|
||||
PATHS_MY_SERVERS_FB=./dev/Unraid.net/fb_keepalive # My servers flashbackup timekeeper file
|
||||
PATHS_KEYFILE_BASE=./dev/Unraid.net # Keyfile location
|
||||
PATHS_MACHINE_ID=./dev/data/machine-id
|
||||
PORT=5000
|
||||
NODE_ENV=test
|
||||
NODE_ENV="test"
|
||||
@@ -1,47 +0,0 @@
|
||||
/** @type {import('eslint').Linter.Config} */
|
||||
module.exports = {
|
||||
root: true,
|
||||
plugins: [
|
||||
'@typescript-eslint/eslint-plugin',
|
||||
'unused-imports',
|
||||
'eslint-plugin-unicorn',
|
||||
],
|
||||
ignorePatterns: ['src/graphql/generated/**/*.ts', '*.test.ts', 'tsup.config.ts', 'vite.config.ts'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
rules: {
|
||||
'@typescript-eslint/no-redundant-type-constituents': 'off',
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'@typescript-eslint/naming-convention': 'off',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-unsafe-return': 'off',
|
||||
'@typescript-eslint/ban-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/consistent-type-imports': [
|
||||
'warn',
|
||||
{ fixStyle: 'inline-type-imports' },
|
||||
],
|
||||
'unicorn/numeric-separators-style': [
|
||||
'error',
|
||||
{ number: { minimumDigits: 0, groupLength: 3 } },
|
||||
],
|
||||
'import/no-cycle': 'off', // Change this to "error" to find circular imports
|
||||
'@typescript-eslint/no-use-before-define': ['error'],
|
||||
'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 1 }],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts'],
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
],
|
||||
parserOptions: {
|
||||
project: true,
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
35
api/.eslintrc.ts
Normal file
35
api/.eslintrc.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import eslint from '@eslint/js';
|
||||
import noRelativeImportPaths from 'eslint-plugin-no-relative-import-paths';
|
||||
import prettier from 'eslint-plugin-prettier';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended, {
|
||||
plugins: {
|
||||
'no-relative-import-paths': noRelativeImportPaths,
|
||||
prettier: prettier,
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/no-redundant-type-constituents': 'off',
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'@typescript-eslint/naming-convention': 'off',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-unsafe-return': 'off',
|
||||
'@typescript-eslint/ban-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-empty-object-type': 'off',
|
||||
'no-use-before-define': ['off'],
|
||||
'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 1 }],
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-expressions': 'off',
|
||||
'import/no-unresolved': 'off',
|
||||
'import/extensions': 'off',
|
||||
'import/no-absolute-path': 'off',
|
||||
'import/prefer-default-export': 'off',
|
||||
'no-relative-import-paths/no-relative-import-paths': [
|
||||
'error',
|
||||
{ allowSameFolder: false, rootDir: 'src', prefix: '@app' },
|
||||
],
|
||||
'prettier/prettier': 'error',
|
||||
},
|
||||
ignores: ['src/graphql/generated/client/**/*'],
|
||||
});
|
||||
84
api/.gitignore
vendored
Normal file
84
api/.gitignore
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
# Logs
|
||||
./logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
coverage-ts
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# Visual Studio Code workspace
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Temp dir for tests
|
||||
test/__temp__/*
|
||||
|
||||
# Built files
|
||||
dist
|
||||
|
||||
# Typescript
|
||||
typescript
|
||||
|
||||
# Ultra runner
|
||||
.ultra.cache.json
|
||||
|
||||
# Github actions
|
||||
RELEASE_NOTES.md
|
||||
|
||||
# Docker Deploy Folder
|
||||
deploy/*
|
||||
!deploy/.gitkeep
|
||||
|
||||
# pkg cache
|
||||
.pkg-cache
|
||||
|
||||
# IDE Settings Files
|
||||
.idea
|
||||
|
||||
!**/*.login.*
|
||||
@@ -1 +0,0 @@
|
||||
18.19.1
|
||||
7
api/.prettierignore
Normal file
7
api/.prettierignore
Normal file
@@ -0,0 +1,7 @@
|
||||
!src/*
|
||||
|
||||
# Downloaded Fixtures (For File Modifications)
|
||||
src/unraid-api/unraid-file-modifier/modifications/__fixtures__/downloaded/*
|
||||
|
||||
# Generated Types
|
||||
src/graphql/generated/client/*.ts
|
||||
38
api/.prettierrc.cjs
Normal file
38
api/.prettierrc.cjs
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @see https://prettier.io/docs/en/configuration.html
|
||||
* @type {import("prettier").Config}
|
||||
*/
|
||||
module.exports = {
|
||||
trailingComma: 'es5',
|
||||
tabWidth: 4,
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
printWidth: 105,
|
||||
plugins: ['@ianvs/prettier-plugin-sort-imports'],
|
||||
// decorators-legacy lets the import sorter transform files with decorators
|
||||
importOrderParserPlugins: ['typescript', 'decorators-legacy'],
|
||||
importOrder: [
|
||||
/**----------------------
|
||||
* Nest.js & node.js imports
|
||||
*------------------------**/
|
||||
'<TYPES>^@nestjs(/.*)?$',
|
||||
'^@nestjs(/.*)?$', // matches imports starting with @nestjs
|
||||
'<TYPES>^(node:)',
|
||||
'<BUILTIN_MODULES>', // Node.js built-in modules
|
||||
'',
|
||||
/**----------------------
|
||||
* Third party packages
|
||||
*------------------------**/
|
||||
'<TYPES>',
|
||||
'<THIRD_PARTY_MODULES>', // Imports not matched by other special words or groups.
|
||||
'',
|
||||
/**----------------------
|
||||
* Application Code
|
||||
*------------------------**/
|
||||
'<TYPES>^@app(/.*)?$', // matches type imports starting with @app
|
||||
'^@app(/.*)?$',
|
||||
'',
|
||||
'<TYPES>^[.]',
|
||||
'^[.]', // relative imports
|
||||
],
|
||||
};
|
||||
7
api/.vscode/settings.json
vendored
Normal file
7
api/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"eslint.lintTask.options": "--flag unstable_ts_config",
|
||||
"eslint.options": {
|
||||
"flags": ["unstable_ts_config"],
|
||||
"overrideConfigFile": ".eslintrc.ts"
|
||||
}
|
||||
}
|
||||
575
api/CHANGELOG.md
575
api/CHANGELOG.md
@@ -2,6 +2,581 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [4.1.0](https://github.com/unraid/api/compare/v4.0.1...v4.1.0) (2025-02-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add category.json ([c9e87e2](https://github.com/unraid/api/commit/c9e87e2e5b47a8801b7865ed586c803d0b470915))
|
||||
* add developer docs ([#1128](https://github.com/unraid/api/issues/1128)) ([bb2e340](https://github.com/unraid/api/commit/bb2e340b68268d5121db650b27e8b2580c7966bb))
|
||||
* add unraid-ui documentation ([#1142](https://github.com/unraid/api/issues/1142)) ([c557806](https://github.com/unraid/api/commit/c55780680ae905558b79dfefa91b116aef22b105))
|
||||
* attempt to resolve performance issues with rm earlier in build … ([#1152](https://github.com/unraid/api/issues/1152)) ([2a1aa95](https://github.com/unraid/api/commit/2a1aa95bd62ebfe42b62b8e7105c7a92b00cfca9))
|
||||
* auto-docusaurus-prs ([#1127](https://github.com/unraid/api/issues/1127)) ([1147e76](https://github.com/unraid/api/commit/1147e762ae2fed6dea198fa38d6bcc514a1e66fb))
|
||||
* bug report template ([f1ee8b2](https://github.com/unraid/api/commit/f1ee8b27b11fa969d0e6891590e44047c76eedb5))
|
||||
* contributing guide ([c912476](https://github.com/unraid/api/commit/c912476b431750834c64bdec80a61fda23e6c490))
|
||||
* convert to pnpm monorepo ([#1137](https://github.com/unraid/api/issues/1137)) ([8d89f8b](https://github.com/unraid/api/commit/8d89f8b20d6f3983d4e85b33827a857aa862db37))
|
||||
* feature request template ([72a042c](https://github.com/unraid/api/commit/72a042c4fab295cf561807102c9eb9a78273bd83))
|
||||
* fix docusaurus build + update snapshot ([23b27bd](https://github.com/unraid/api/commit/23b27bd63ea99f4137538eab40501daa67d7e3f5))
|
||||
* public index ([f0641ea](https://github.com/unraid/api/commit/f0641ea7ca0919884dc3b8642c2e6694398e3246))
|
||||
* reorder index ([858553f](https://github.com/unraid/api/commit/858553f0debb6424ae0614640b82a050c33f175a))
|
||||
* simplify docs ([d428030](https://github.com/unraid/api/commit/d428030b806f55b62421559d434fc723786b03ad))
|
||||
* upgrade workflow and auto-assign reviewers ([58a419e](https://github.com/unraid/api/commit/58a419ed36926d121e405a3de37bcb39f26f50b1))
|
||||
* **web:** improve notification count syncing ([#1148](https://github.com/unraid/api/issues/1148)) ([af2057c](https://github.com/unraid/api/commit/af2057c643640270e3e152ff8e08c3045e622437))
|
||||
* work intent ([feee4be](https://github.com/unraid/api/commit/feee4bebfe97620c73e6a6093065f22ea26ee8b9))
|
||||
* work intent process ([b04a97a](https://github.com/unraid/api/commit/b04a97a493f06c450949c674629e8a787164464b))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api:** change log output location for diagnostic compatibility ([#1130](https://github.com/unraid/api/issues/1130)) ([cba1551](https://github.com/unraid/api/commit/cba155138379d47bc3151c7c27d745ba6a345d83))
|
||||
* **api:** logrotate modification & permissions ([#1145](https://github.com/unraid/api/issues/1145)) ([5209df2](https://github.com/unraid/api/commit/5209df2776e1a985e82bedc655fe28acf1fd0bde))
|
||||
* connect breaks default css of header ([#1155](https://github.com/unraid/api/issues/1155)) ([4ac9aa3](https://github.com/unraid/api/commit/4ac9aa3e409d0d89f2be61bfbafb8d7b5a5b3b00))
|
||||
* create PR ignored ([bdfefa8](https://github.com/unraid/api/commit/bdfefa808f5f1d85ff957a78a624edcef3afb47a))
|
||||
* **deps:** update dependency dockerode to v4 ([#830](https://github.com/unraid/api/issues/830)) ([c331ecd](https://github.com/unraid/api/commit/c331ecd50c4910fd6c35e5ad92b3f676d552febc))
|
||||
* docs creation workflow ([86134c6](https://github.com/unraid/api/commit/86134c60856c130dab9f96b718d9afa5bbab1e50))
|
||||
* make public not a part of folder structure in PR ([099a88e](https://github.com/unraid/api/commit/099a88eb4970da48e57dafbc3807e16f1987d7fc))
|
||||
* PHP Warning in state.php ([#1126](https://github.com/unraid/api/issues/1126)) ([c154b4e](https://github.com/unraid/api/commit/c154b4e0ad2d0627b1541a7f9ee5e55235d4dd5e))
|
||||
* revert dockerode upgrade ([#1140](https://github.com/unraid/api/issues/1140)) ([a74a379](https://github.com/unraid/api/commit/a74a379a93fd15a315e31191de1bf69c5879f8a6)), closes [unraid/api#830](https://github.com/unraid/api/issues/830)
|
||||
* shorten work intent form ([95fe671](https://github.com/unraid/api/commit/95fe671717ab856518f5b4893dfbcbade0d0f2ed))
|
||||
* simplify api setup index ([701b1fb](https://github.com/unraid/api/commit/701b1fbd9096c9675475062eaf32a2cbfb0567b9))
|
||||
* simplify upcoming features ([8af79b2](https://github.com/unraid/api/commit/8af79b27501b42e1c1f7697756a56a9001000d8f))
|
||||
* storybook resolution issue ([#1153](https://github.com/unraid/api/issues/1153)) ([52c70b9](https://github.com/unraid/api/commit/52c70b9d85469008894d44788429ba298b082ac7))
|
||||
* upload to correct tag directory on build ([c5fe723](https://github.com/unraid/api/commit/c5fe723a0abee0d0fc494a5b512c995001ae0615))
|
||||
* **web:** broken modals ([aebf339](https://github.com/unraid/api/commit/aebf3392595d45c84a84668f461c632a2d62e7dd))
|
||||
* **web:** name of toaster component ([e093242](https://github.com/unraid/api/commit/e093242d20ddd72567396f4a53238250f2199a64))
|
||||
|
||||
### [4.0.1](https://github.com/unraid/api/compare/v4.0.0...v4.0.1) (2025-02-06)
|
||||
|
||||
## [4.0.0](https://github.com/unraid/api/compare/v3.11.0...v4.0.0) (2025-02-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* actual install url ([89d667e](https://github.com/unraid/api/commit/89d667e33bffb17df43c768f12c21302571270ff))
|
||||
* actually exit on stop and start ([bce5fde](https://github.com/unraid/api/commit/bce5fde64278dd853e71c022c03b9f6888dccfcf))
|
||||
* add api key creation logic ([81382bc](https://github.com/unraid/api/commit/81382bcf1d26364ad9c5445530f648209101cf91))
|
||||
* add command to package.json scripts ([0dfb07f](https://github.com/unraid/api/commit/0dfb07f9eb519e60441f4123423f65acfdffca3b))
|
||||
* add csrf support to api & web components ([#999](https://github.com/unraid/api/issues/999)) ([19241ed](https://github.com/unraid/api/commit/19241ed55f5112f878b9890d8695badf7eb1c3eb))
|
||||
* add date formatting helper ([#938](https://github.com/unraid/api/issues/938)) ([b8c8b00](https://github.com/unraid/api/commit/b8c8b005410bbb612014f34ada51ca23cae67a30))
|
||||
* add deletion & update methods to NotificationService ([ac82b08](https://github.com/unraid/api/commit/ac82b08a9e865cd095cfb5c484404f9e7383391e))
|
||||
* add description flag, remove console log, and update readme ([c416c30](https://github.com/unraid/api/commit/c416c30951de4ed6b8d7a8c014403772db1c2015))
|
||||
* add deviceCount to serverAccountPayload for callbacks ([0fb8b87](https://github.com/unraid/api/commit/0fb8b87ff2645ec642d2f038e5f941a880274817))
|
||||
* add ecosystem.config.json to files ([913febc](https://github.com/unraid/api/commit/913febc0e461bfe052fe116e76d9871e54584aa2))
|
||||
* add exclude to vite.config ([e64dde7](https://github.com/unraid/api/commit/e64dde7a23414a2e649bef999de8e2164c7b507f))
|
||||
* add ID prefix plugin to prefix IDs with server identifier ([066e93a](https://github.com/unraid/api/commit/066e93a52afa17f53df2f238065d853ce2945a1e))
|
||||
* add line about recommendation for sso command ([44727a8](https://github.com/unraid/api/commit/44727a8d1a7c16c566678da43119b17a6303e375))
|
||||
* add log rotation ([f5c7ad9](https://github.com/unraid/api/commit/f5c7ad9221f80e4630e69f78d57f08f4c7252719))
|
||||
* add logging around fixture downloads ([a1ce27b](https://github.com/unraid/api/commit/a1ce27b17c970657f52635600f0d13116523f928))
|
||||
* add logrotate cron again ([4f85f66](https://github.com/unraid/api/commit/4f85f6687f920dae50277e726e2db2c3d946e867))
|
||||
* add patch for auth-request.php ([ec6ec56](https://github.com/unraid/api/commit/ec6ec562f43aac9947de2e9c269181303f42b2db))
|
||||
* add user with cli ([37458cd](https://github.com/unraid/api/commit/37458cd7408a1ad8aedca66a55ff13ac19ee30db))
|
||||
* add validation step to ensure that variables are set ([e3e9b2b](https://github.com/unraid/api/commit/e3e9b2bf404cb6f3bcae83db0395be272e4b79e3))
|
||||
* add web gitignore ([8b49190](https://github.com/unraid/api/commit/8b491900947c9a7a63b7ad61e7d355ff2fd1f801))
|
||||
* address log level feedback ([49774aa](https://github.com/unraid/api/commit/49774aae459797f04ef2866ca064050aa476ae91))
|
||||
* allow csrf passing through querystring ([dba38c0](https://github.com/unraid/api/commit/dba38c0d149a77e4104c718c53d426330a17f2fa))
|
||||
* allow deletion and creation of files with patches ([32c9524](https://github.com/unraid/api/commit/32c952402c25e8340b1c628b4d0fdc4816b28ade))
|
||||
* almost working ([df1fc6d](https://github.com/unraid/api/commit/df1fc6dffaa242d85d8ab79f2bfe9e9b1de4b261))
|
||||
* also copy in other files ([599b365](https://github.com/unraid/api/commit/599b365e8b668d9fba9d88f3d0d03fb7f63244cb))
|
||||
* always ensureDirectory for keys exists ([c6e9f80](https://github.com/unraid/api/commit/c6e9f804c58e44b46bce9f0da2260888544354cd))
|
||||
* always start the API and run npm link from script path ([30133ac](https://github.com/unraid/api/commit/30133acb0514a480177f563d4aee364a8a3fab1b))
|
||||
* **api:** add default dynamix config to dev docker container ([0aeea34](https://github.com/unraid/api/commit/0aeea34427805a9b61a762efbd01c938016be28c))
|
||||
* **api:** graphql sandbox on unraid servers ([#1047](https://github.com/unraid/api/issues/1047)) ([ec504f3](https://github.com/unraid/api/commit/ec504f39297c92b64d9d3cc2f8f482cc1f3a2e44))
|
||||
* **api:** omit tz from sys time date format by default ([b2acde3](https://github.com/unraid/api/commit/b2acde3351d7afe18a2902e90b672537aadabffd))
|
||||
* **api:** rm 2fa & t2fa from myservers config type ([#996](https://github.com/unraid/api/issues/996)) ([89e791a](https://github.com/unraid/api/commit/89e791ad2e6f0395bee05e3f8bdcb2c8d72305dd))
|
||||
* **api:** sort notifications file listing by date (latest first) ([cae8d0b](https://github.com/unraid/api/commit/cae8d0bc07a465d73f0242a8d68816fd0a6042c7))
|
||||
* array iteration for restoring files ([036e97b](https://github.com/unraid/api/commit/036e97bb02e463872b3c2f4b5f1aa3b4bf525d1e))
|
||||
* async disk mapping ([bbb27e6](https://github.com/unraid/api/commit/bbb27e686897e4f9a0c926553d75aa046d7a8323))
|
||||
* async hypervisor and FIXED vm listing ([e79f4dd](https://github.com/unraid/api/commit/e79f4ddbc7061c249efb8214a311bb629628f669))
|
||||
* attempt to fix pm2 ([ab67717](https://github.com/unraid/api/commit/ab67717d5954ae3965c1e4082605af5e42f73ca2))
|
||||
* attempt to start unraid-api with background task ([2a102fc](https://github.com/unraid/api/commit/2a102fc9944f3080af66a8ebadee35059bce2009))
|
||||
* **Auth:** add cookie guard to check for valid sessions ([3dffc0c](https://github.com/unraid/api/commit/3dffc0c663cfbe8c4368ab98c834baf611a8910a))
|
||||
* **auth:** make cors aware of authenticated sessions ([f9c23aa](https://github.com/unraid/api/commit/f9c23aa8852a8335640bbd16caa783e9a38b449c))
|
||||
* automatic session setup for dev ([36d630e](https://github.com/unraid/api/commit/36d630e89bbf9bc7e3ae64bdf5cf73a8536d44ab))
|
||||
* back to callbackUrl ([e39b120](https://github.com/unraid/api/commit/e39b1203a315889c5b5232ecfd32c7377ae04800))
|
||||
* begin building plugin with node instead of bash ([#1120](https://github.com/unraid/api/issues/1120)) ([253b65a](https://github.com/unraid/api/commit/253b65a85ab9c5f53d53ef265b41aa132678f278))
|
||||
* begin fixing dark mode in the webcomponents ([5f7dcdb](https://github.com/unraid/api/commit/5f7dcdb1a7e7bce87b29add7849c94a0353c2c96))
|
||||
* begin nuking alpha beta gamma ([25acd4b](https://github.com/unraid/api/commit/25acd4b39fff9a0cb573f9e90c52830fef41d737))
|
||||
* better patch application ([a3e7daa](https://github.com/unraid/api/commit/a3e7daa6a6565ac81004ffd13da35d8b95b429cf))
|
||||
* better pm2 calls, log lines ([338ce30](https://github.com/unraid/api/commit/338ce3061310dfc42ad5f65edacbe5272de4afc7))
|
||||
* build and pack in docker ([2a322d1](https://github.com/unraid/api/commit/2a322d12570ba3e797fb84289a42b010f3f88467))
|
||||
* buildx build caching ([b38be3c](https://github.com/unraid/api/commit/b38be3ceb7c7299fe30c90ed5a75e131af3b33da))
|
||||
* checkout correct branch on close ([#1123](https://github.com/unraid/api/issues/1123)) ([a20b812](https://github.com/unraid/api/commit/a20b812b020adfade129ebd9fb0e6536004f8bee))
|
||||
* cleanup config entries ([943e73f](https://github.com/unraid/api/commit/943e73fa696b6ecec3227be914ab4962c4fee79d))
|
||||
* cleanup disclaimer and command to add users ([6be3af8](https://github.com/unraid/api/commit/6be3af8d7569d9c413dd9349df52e3fa4cb4f631))
|
||||
* cleanup unused variables ([b50e289](https://github.com/unraid/api/commit/b50e2896f765cecfe631aa839186a6124beb41a3))
|
||||
* cli Commands ([f8e5367](https://github.com/unraid/api/commit/f8e5367f3eb47daa5bcbd7711ae5835369502a1d))
|
||||
* CLI options for adding and deleting users ([16bf6d4](https://github.com/unraid/api/commit/16bf6d4c27ae8fa8d6d05ec4b28ce49a12673278))
|
||||
* code review changes ([fe38acc](https://github.com/unraid/api/commit/fe38acc92e4b1891b0b61fdb4947ec91070cb535))
|
||||
* codeowners ([ab090b4](https://github.com/unraid/api/commit/ab090b48ec7291597a135a72b8e55c2d1bb389f3))
|
||||
* coderabbit suggestion ([11ac36c](https://github.com/unraid/api/commit/11ac36c3616a90853d91467526fd39ecba17db88))
|
||||
* comment URL for plugin on PR ([9840b33](https://github.com/unraid/api/commit/9840b334b4466a4f72e3e57055338a3d5557553d))
|
||||
* configure PM2 on startup ([2b908f1](https://github.com/unraid/api/commit/2b908f100b9eefaccf2264d5ff9945667568acf0))
|
||||
* copy ([7e33e5c](https://github.com/unraid/api/commit/7e33e5ca32e95168bb82f090c1acaee43bce1f25))
|
||||
* copy node modules ([bb0436c](https://github.com/unraid/api/commit/bb0436c7fec54be9ea63681104e720bb5b499f58))
|
||||
* copy only needed files for nodejs ([acf587a](https://github.com/unraid/api/commit/acf587aa53ca25a3beae86afc608fc9ed68919ef))
|
||||
* create key cli command logic and add to index command list ([9b2a62d](https://github.com/unraid/api/commit/9b2a62d642b0942e3787e4ddd582a66e40321ab2))
|
||||
* csv validation ([84aae15](https://github.com/unraid/api/commit/84aae15a73014592c226fa3701e34e57c7b60b46))
|
||||
* default value for option ([6513fc4](https://github.com/unraid/api/commit/6513fc49de61c836e1aabf32a874d7da7da18adb))
|
||||
* delete unused imports ([97a3772](https://github.com/unraid/api/commit/97a3772d95aff534d85c410e58391d30494d9237))
|
||||
* diff ([02c0c5f](https://github.com/unraid/api/commit/02c0c5f8e09476ddcd207c49e1c7d6c764c40d69))
|
||||
* disable button on submit ([2ceb5da](https://github.com/unraid/api/commit/2ceb5da3c70826cc50df476decb6b117025f46c0))
|
||||
* disable casbin logging ([2518e7c](https://github.com/unraid/api/commit/2518e7c506f0d3aa9f44031d61dce95d9db0a4cf))
|
||||
* do not move upgradepkg ([ea16419](https://github.com/unraid/api/commit/ea16419929e0233e2c1ce37e2f4b79e3e64ce619))
|
||||
* docstrings ([b836ba7](https://github.com/unraid/api/commit/b836ba72516c554ee8973d69aaaa4ed35b465fa7))
|
||||
* don't remove directory, only files ([c2227cb](https://github.com/unraid/api/commit/c2227cbaadbbfe3dda6a89690a396db5bd6db444))
|
||||
* dont pass entire server state for privacy ([54e3f17](https://github.com/unraid/api/commit/54e3f17bd9e541f50970c696bbe8b602ec38a748))
|
||||
* download fixtures from the web ([1258c2b](https://github.com/unraid/api/commit/1258c2bc1813f0fa3cd52b4932302ad12b4edd01))
|
||||
* download nodejs and install on legacy OS versions ([2a95e4b](https://github.com/unraid/api/commit/2a95e4beb2364510003f187459e28bb610583c41))
|
||||
* eliminate all alpha beta gamma variable usage ([fbdbce9](https://github.com/unraid/api/commit/fbdbce97ec2171ec7057f0f159e73032e984705a))
|
||||
* enable PR releases on non-mainline merges ([7ae8d03](https://github.com/unraid/api/commit/7ae8d03166952a602f0b7ebaf1cc65a9a8d27e7b))
|
||||
* enable sandbox in dev mode ([4536d70](https://github.com/unraid/api/commit/4536d7092d77c68f5a996fd63bf74ce6e64f5efe))
|
||||
* enable sandbox with developer command ([c354d48](https://github.com/unraid/api/commit/c354d482283295547afeb99c5e110b0181197c44))
|
||||
* enable token sign in with comma separated subs in myservers.config ([ebed5bd](https://github.com/unraid/api/commit/ebed5bddea1445d9aaaee60d54758dc74b77271e))
|
||||
* error state outside of button ([18c63e0](https://github.com/unraid/api/commit/18c63e0b0c7451c99eacabb504e18f8070ff7dc2))
|
||||
* error when nodejs download fails ([6a9b14c](https://github.com/unraid/api/commit/6a9b14c68170d6430328cbb793d750f3177bdb32))
|
||||
* exit after running status ([12f551c](https://github.com/unraid/api/commit/12f551c9d91692b40b73d96133d45c04f795548e))
|
||||
* exit cli after running command ([04bf528](https://github.com/unraid/api/commit/04bf528616fcbdf916916734a12d5fd32db9a06d))
|
||||
* expose mutations for notifications over graphql ([59dc330](https://github.com/unraid/api/commit/59dc33029d03c3d3cda5b4c2a60772e2b7d01811))
|
||||
* extensive file checking ([ab881c8](https://github.com/unraid/api/commit/ab881c8aed8dd4aa9fd71c32b50d3514d1496fa5))
|
||||
* extract node to usr/local/ ([4c0b55b](https://github.com/unraid/api/commit/4c0b55b269f47a9d8f746344ae701e353d80509a))
|
||||
* fallback to local ([a2579c2](https://github.com/unraid/api/commit/a2579c2a7f80f54b4cc61533aec9ecc41a7e7f54))
|
||||
* faster failure logic ([b439434](https://github.com/unraid/api/commit/b439434f1574e174fcf23f3a5f5b8df8e092eb1e))
|
||||
* fix header strategy ([4187b77](https://github.com/unraid/api/commit/4187b77a107c0f37e47a1e272c5acb9b798ad3be))
|
||||
* fix issues with permissions and invalid modules ([e0cfb40](https://github.com/unraid/api/commit/e0cfb40c847a53def1057ae00c97f9306713c3d1))
|
||||
* fix missing flash line ([6897aad](https://github.com/unraid/api/commit/6897aad67f5c8b38450aa81e612b8aa98a9328c7))
|
||||
* fix missing import in ESM ([8e99bdd](https://github.com/unraid/api/commit/8e99bdd8f97e772b07374d833debff4eadbf6501))
|
||||
* fix more imports ([028df06](https://github.com/unraid/api/commit/028df06cd2279d219bd0b3039ad8680de6138b83))
|
||||
* fix pm2 setup and add link command ([de9500f](https://github.com/unraid/api/commit/de9500ffa6f3aa1842152e0ab26f54c8c5c6e5cb))
|
||||
* force linting on build ([43e6639](https://github.com/unraid/api/commit/43e663998a55e83c142067cb64ae7a331395fe68))
|
||||
* generate key one time ([afe53c3](https://github.com/unraid/api/commit/afe53c30ea9987e6d8728faa2cb7291f8a126ecb))
|
||||
* glob for files ([3fe281f](https://github.com/unraid/api/commit/3fe281f1ae28e3cbc089b5244a6ae2863b20adcb))
|
||||
* hide sign in from the dropdown text ([3e68aaf](https://github.com/unraid/api/commit/3e68aaf8cdc0fb20c6e1b819a8571f419d94a811))
|
||||
* hypervisor async imports ([32686ca](https://github.com/unraid/api/commit/32686ca4f0c25c43c6a9f7162bb8179b39e58f7e))
|
||||
* ID prefixer improvement ([ed55b32](https://github.com/unraid/api/commit/ed55b32645d7414657c7775d5a786fa2653294d5))
|
||||
* ignore generated code ([68265a2](https://github.com/unraid/api/commit/68265a26efa588b60001310b9a11b398f04ae88f))
|
||||
* implement mutations for updating many notifications at once ([6c90508](https://github.com/unraid/api/commit/6c90508c64e453849d06818cca2a3f6f7dfbf172))
|
||||
* improve packing ([9ef02d5](https://github.com/unraid/api/commit/9ef02d53666b70d41fdd186364808deac715e1ff))
|
||||
* initial patcher implementation using the diff tool ([c87acbb](https://github.com/unraid/api/commit/c87acbb146c2e4e30997c964cd8be325dee68cea))
|
||||
* initial setup of permissions on keys ([#1068](https://github.com/unraid/api/issues/1068)) ([cf0fa85](https://github.com/unraid/api/commit/cf0fa850954ea2f018e338a132149f872b966df4))
|
||||
* initial version of modification service ([b80469d](https://github.com/unraid/api/commit/b80469d38e519a7ba0e6eae636cda2a821e2d465))
|
||||
* inject after form ([a4b276f](https://github.com/unraid/api/commit/a4b276f7874580bbf9827025730777715c9983da))
|
||||
* install nghttp3 ([7e6cf85](https://github.com/unraid/api/commit/7e6cf858b270e615ec3eeddd394d0c2e6d810e21))
|
||||
* install node ([4b85338](https://github.com/unraid/api/commit/4b853389d4ee7d0fb8e539d948dac21e748f642a))
|
||||
* integrate cross-domain authentication to api ([7749783](https://github.com/unraid/api/commit/77497830c13d8e3ce1c348a8c79d8835ad5e3eb2))
|
||||
* kill timeout extended ([22d4026](https://github.com/unraid/api/commit/22d40264a02672a818053b5280d63a03ff7336b9))
|
||||
* linting continues on error ([a3499d6](https://github.com/unraid/api/commit/a3499d6feee56319657c37bb77277d5c637ee0b5))
|
||||
* log size and only tar files ([731f2f8](https://github.com/unraid/api/commit/731f2f8e77a77b544a7f526c78aabfacca71eee4))
|
||||
* logrotate test ([4504c39](https://github.com/unraid/api/commit/4504c39a2bbcf51385578b69a9fdc7b81a950e98))
|
||||
* lots of progress on colors ([dc8b2ee](https://github.com/unraid/api/commit/dc8b2ee01b454d307e779d495dbcf11227760480))
|
||||
* make notification id logic ([d5e0b3a](https://github.com/unraid/api/commit/d5e0b3a81ef3406b40e3376b5bca2fd101aa9c11))
|
||||
* manually install libvirt in build process to ensure it is included in the final build ([e695481](https://github.com/unraid/api/commit/e695481363f0d5d7add9d0e0d50d1e113b3024f6))
|
||||
* massive rc.unraid-api updates to facilitate installing and linking ([ded03d8](https://github.com/unraid/api/commit/ded03d86b25b51af98de2b7e7397a641dd0c082a))
|
||||
* more cleanup ([9f6aeec](https://github.com/unraid/api/commit/9f6aeecfd90d069a0b2a642f99ef9622f4e0526d))
|
||||
* more pm2 fixes ([8257bdf](https://github.com/unraid/api/commit/8257bdff3624211ee645349abdec303bf271538e))
|
||||
* more process improvements ([9491be1](https://github.com/unraid/api/commit/9491be1038ee2e0e24be111bd8e8c78ec2890124))
|
||||
* mount git folder to builder ([91350ea](https://github.com/unraid/api/commit/91350ea8535511c964d5869bd74a37830fc1bc40))
|
||||
* move fixtures into __test__ folder ([22a901d](https://github.com/unraid/api/commit/22a901de9b0c274d3f75ed4b4618cd6cd90324ba))
|
||||
* move ssoenabled to a boolean flag rather than ids ([404a02b](https://github.com/unraid/api/commit/404a02b26bae6554d15e317f613ebc727c8f702f))
|
||||
* move to singular build and test step ([c9c8e86](https://github.com/unraid/api/commit/c9c8e8653321eaa0292a16e970d6dd4e79a3928f))
|
||||
* move variable declarations to theme.ts ([3c82ee1](https://github.com/unraid/api/commit/3c82ee1e9acc197c9768a624cdef8c2e23c56d00))
|
||||
* myservers_fb keepalive location ([e07e7f3](https://github.com/unraid/api/commit/e07e7f335c8ea4a73966ada90c26b7c82dbb025e))
|
||||
* name package with PR number ([a642bf1](https://github.com/unraid/api/commit/a642bf15fd813dca522808765994414e4ed5a56c))
|
||||
* nghttp3 sha256 missing ([589cc9b](https://github.com/unraid/api/commit/589cc9b4624d9d0e00ec3b86873d8ecb6a861427))
|
||||
* nodejs issues with version 2 ([9c6e52c](https://github.com/unraid/api/commit/9c6e52c2fa46e7504bc3fa500770373d8c1d1690))
|
||||
* **NotificationService:** endpoint to manually recalculate notification overview ([18e150f](https://github.com/unraid/api/commit/18e150f908b937cccd13171830fc418c3600cdbe))
|
||||
* **NotificationsService:** use existing notifier script to create notifications when possible ([2f1711f](https://github.com/unraid/api/commit/2f1711f06a2fa0a679aeae12176cb2dd763494a4))
|
||||
* nuxt config simplification and formatting ([02ffde2](https://github.com/unraid/api/commit/02ffde24d19594949faa97f9d070383b498fdcbe))
|
||||
* only run mainline build ([b6ee6f9](https://github.com/unraid/api/commit/b6ee6f9c9f7740e91856754caecb6630bc62f37b))
|
||||
* only write config when a specific config update action occurs ([ec29778](https://github.com/unraid/api/commit/ec29778e37a50f43eb164991bcf2a6ff9c266033))
|
||||
* or button on sign in page ([1433e93](https://github.com/unraid/api/commit/1433e938d7ac01af326e2875c582a6aa6d622615))
|
||||
* pack everything in API ([178a6f6](https://github.com/unraid/api/commit/178a6f6b0d7cf2fc4b2ad4cfbd9a928f880c222c))
|
||||
* package scripts ([123aa77](https://github.com/unraid/api/commit/123aa77fe6f21e64809083d8b872ef2152be1ad1))
|
||||
* pass env into builder ([e75ac99](https://github.com/unraid/api/commit/e75ac99d8e19e7ea66671c211bd4cf85ec3b81b0))
|
||||
* plg builder improvements to be more explicit ([78c2f03](https://github.com/unraid/api/commit/78c2f035da0f0c6aaaedbee11c8c4f2a8cd42d0f))
|
||||
* **plugin:** rm Date & Time format settings from Notification Settings ([e2148f3](https://github.com/unraid/api/commit/e2148f3c2eaf77ad707eddb7989cc20ec8df70ab))
|
||||
* pm2 fixes ([5b322b4](https://github.com/unraid/api/commit/5b322b4faed6e8f0bb0742832cb94c8027d0e12b))
|
||||
* pm2 fully working ([ecb642b](https://github.com/unraid/api/commit/ecb642b6a88bd66c3ccd1f4e1dcd2c92d7ff4b35))
|
||||
* pm2 initial setup ([3cee381](https://github.com/unraid/api/commit/3cee381c442032d24c9c33dfa6d8a43581061fca))
|
||||
* PR builds ([0025852](https://github.com/unraid/api/commit/00258524fa3f7ed745abfe471dfdb780b6d2b365))
|
||||
* process env fixed and copy gql files ([8b90620](https://github.com/unraid/api/commit/8b90620d28378caabc7bbc1745ca43a1ddf8bd87))
|
||||
* properly read log level from environment ([b5151e9](https://github.com/unraid/api/commit/b5151e9ba76a6814e24e8da34e8a3c1bf1cc2144))
|
||||
* properly set outputs ([aa6904e](https://github.com/unraid/api/commit/aa6904e0a455a75a8187259d491b04366ad50fb0))
|
||||
* rem converter ([d2489df](https://github.com/unraid/api/commit/d2489df6eaaa267a2f51b896c6c14ac9c5b00f85))
|
||||
* remove apiKey from server ([b110a11](https://github.com/unraid/api/commit/b110a118fb153c0af09a74755deb468b3760ba27))
|
||||
* remove console log disabler ([0cf24d2](https://github.com/unraid/api/commit/0cf24d2a212e1f44e0b379221c93aa436c3b7179))
|
||||
* remove many unneded simple libraries ([483e6dc](https://github.com/unraid/api/commit/483e6dc28d70b933dc956b4ffd6da4ade8ab7eb9))
|
||||
* remove more unused calls ([5d2923f](https://github.com/unraid/api/commit/5d2923f8ee5bfd574420fca85e2c4aefbe7b33d6))
|
||||
* remove nghttp3 and only bundle nodejs ([8d8df15](https://github.com/unraid/api/commit/8d8df1592e5af127a992d5634ee9d344055cdf2c))
|
||||
* remove sso if disabled on Unraid-API start ([3bc407c](https://github.com/unraid/api/commit/3bc407c54e8e7aeadebd9ac223d71f21ef97fca1))
|
||||
* remove sso user command ([bbd809b](https://github.com/unraid/api/commit/bbd809b83826e81eef38a06e66f3393e4f83e81e))
|
||||
* remove sso user options ([e34041f](https://github.com/unraid/api/commit/e34041f86ef7ab6cf5e2fdf7efb86458d190edc1))
|
||||
* remove unused config sections ([f0b9c4f](https://github.com/unraid/api/commit/f0b9c4f44ab0ee8f75bf96fde2413988ef4f6a8c))
|
||||
* remove unused fields ([d2d0f7c](https://github.com/unraid/api/commit/d2d0f7cd9acb53ea2372245d7ef669c7ca24ee8a))
|
||||
* remove unused vars ([0507713](https://github.com/unraid/api/commit/0507713972e344ad47bd077554d5888269669e9c))
|
||||
* remove wtfnode ([cbdcc47](https://github.com/unraid/api/commit/cbdcc476b617539611478cf6f29bbb57d0be83b3))
|
||||
* rename api key resource back to api_key ([ee9666b](https://github.com/unraid/api/commit/ee9666b317d7feb5c15d53e2a6b902c7771c8c7a))
|
||||
* rename modification file ([70a93f2](https://github.com/unraid/api/commit/70a93f2cc63e0e62242be6fe1a717515a6fbec85))
|
||||
* responsive notifications ([d427054](https://github.com/unraid/api/commit/d427054443176563faa3e44249219c1d938e4b07))
|
||||
* restart the API when an SSO user is added ([a6b0c90](https://github.com/unraid/api/commit/a6b0c906a423df048401750943f02dfdc9bc2619))
|
||||
* restoring sso error ([234bf7d](https://github.com/unraid/api/commit/234bf7dfa4b0be88b6cc13996d8f29ec819da26e))
|
||||
* revert local api key value ([ff40e7a](https://github.com/unraid/api/commit/ff40e7ae392052d3d9e1b084c5f4851e8ebd529e))
|
||||
* right workin directory ([0d99ab0](https://github.com/unraid/api/commit/0d99ab0d74356e4ea309cb86dfc710ed93ab70e7))
|
||||
* rollback if patch exists before applying ([c2f4e8d](https://github.com/unraid/api/commit/c2f4e8d4e5c758601bd20ba491fd077b434ba45e))
|
||||
* secondary changes ([d75331a](https://github.com/unraid/api/commit/d75331a67e3566875ce8642fce80195e79932a4c))
|
||||
* separate install process ([b90a516](https://github.com/unraid/api/commit/b90a51600c3f70615b117f157d41585e55ef49de))
|
||||
* server identifier changes ([b9686e9](https://github.com/unraid/api/commit/b9686e9c67f2a48df419848e18c5451123813185))
|
||||
* service tests for modifier service ([08c1502](https://github.com/unraid/api/commit/08c150259f2b4630d973803f4edff69c8bf0ec3a))
|
||||
* session issues ([5981693](https://github.com/unraid/api/commit/5981693abd605337f9174ba4c85fd1bfc243edeb))
|
||||
* set background color on webcomponents ([b66e684](https://github.com/unraid/api/commit/b66e6847c895f216a5dec42410186b81a31af1a9))
|
||||
* shared call to createPatch ([eb3e263](https://github.com/unraid/api/commit/eb3e263fb32a748bfa06ec6d119ee51d242707cf))
|
||||
* sidebar notification count ([694f01b](https://github.com/unraid/api/commit/694f01b6c4ab83c4131ae42bc11002d0300497c5))
|
||||
* simplify getting version ([8fb8cb3](https://github.com/unraid/api/commit/8fb8cb304ee1b0f007b81a679dc3eadf098f6b4b))
|
||||
* sso button token exchange ([f6f2390](https://github.com/unraid/api/commit/f6f2390b0169ceaf90ab88edfab3f2809bfe86b5))
|
||||
* sso testing page and form disable on submit ([ffc6d8a](https://github.com/unraid/api/commit/ffc6d8a286d7c6ba751894464000f9870784507c))
|
||||
* start command path ([a7aece5](https://github.com/unraid/api/commit/a7aece5570d3fdb073bda1dc7a89b7ea6e7eedf6))
|
||||
* state using crypto ([afce130](https://github.com/unraid/api/commit/afce13099f5018d0c39765bfdd181adc8383a105))
|
||||
* style improvements ([b0f395e](https://github.com/unraid/api/commit/b0f395ef76f11047eaa13091df277df0459e9d8f))
|
||||
* substantial docs updates ([928bd03](https://github.com/unraid/api/commit/928bd03a4853a28a6b563ed82f95681a7f712b3a))
|
||||
* swap to action ([ef7281b](https://github.com/unraid/api/commit/ef7281b2a863422593de5e948fcfad1a6df489f2))
|
||||
* swap to async exit hook ([4302f31](https://github.com/unraid/api/commit/4302f316820a109c76408092994727b2dc030a15))
|
||||
* switch to nest-commander ([1ab2ab5](https://github.com/unraid/api/commit/1ab2ab5b58a1f49cd6b05aaa84bfeced49d68e8e))
|
||||
* track node version in slackware ([42b010e](https://github.com/unraid/api/commit/42b010e4a141f2a338d65f4f727bf1d15521a5c6))
|
||||
* try catch restart ([89abee6](https://github.com/unraid/api/commit/89abee680bdbdaa9946ddb991f0e6b5ada9ccdf7))
|
||||
* **ui:** webgui-compatible web component library ([#1075](https://github.com/unraid/api/issues/1075)) ([1c7b2e0](https://github.com/unraid/api/commit/1c7b2e091b0975438860a8e1fc3db5fd8d3fcf93))
|
||||
* unnecessary comment ([0c52256](https://github.com/unraid/api/commit/0c5225612875b96319b28ef447db69ecab15cfda))
|
||||
* unraid single sign on with account app ([5183104](https://github.com/unraid/api/commit/5183104b322a328eea3e4b2f6d86fd9d4b1c76e3))
|
||||
* unraid ui component library ([#976](https://github.com/unraid/api/issues/976)) ([03e2fee](https://github.com/unraid/api/commit/03e2feebc73d620b21e54912e0bbddc1826880e1))
|
||||
* update based on review feedback ([4383971](https://github.com/unraid/api/commit/43839711e3365e31120e156abac3746c55e8e694))
|
||||
* Update plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/include/state.php ([42c0d58](https://github.com/unraid/api/commit/42c0d58da4d0570b7d865a8774964c18120ed585))
|
||||
* upgrade dependencies ([0a0cac3](https://github.com/unraid/api/commit/0a0cac3da74c2fe20f7100a9ad5d1caafa74b157))
|
||||
* upload files directly to cloudflare ([1982fc2](https://github.com/unraid/api/commit/1982fc238fefa1c67323bdc11ec1fb9c9f43c387))
|
||||
* use execa for start and stop ([46ab014](https://github.com/unraid/api/commit/46ab0144d41b425015487c251c1884744223ba29))
|
||||
* use plugin file for install and uninstall ([c9ac3a5](https://github.com/unraid/api/commit/c9ac3a5a0a3103fbd9c33a5d909fa475614a704a))
|
||||
* use state passing to validate requests ([4480c14](https://github.com/unraid/api/commit/4480c14c932fd8b42ba44989abdbecb49252e6f3))
|
||||
* use text-secondary-foreground instead of gray ([463a1f7](https://github.com/unraid/api/commit/463a1f7b611599a19a23d3c75156c0a16da83312))
|
||||
* use zod to parse config ([19cf1be](https://github.com/unraid/api/commit/19cf1be079f2ccb9e0cfa10f2fb97a18f15c5729))
|
||||
* validate entries correctly ([b101a69](https://github.com/unraid/api/commit/b101a695e18d71ddd170462b3d49289352166489))
|
||||
* validate token format in both PHP and CLI ([6ef05a3](https://github.com/unraid/api/commit/6ef05a3d7770f799e7d587c2cef8d29f6058bee1))
|
||||
* viewport watch refactor ([9aefa38](https://github.com/unraid/api/commit/9aefa382ec64f08b1da8a3748ce16f637d562c8c))
|
||||
* vite ([c78ba4a](https://github.com/unraid/api/commit/c78ba4a774d053d4a9dca938020e4393c5a1fc75))
|
||||
* vite dev mode ([7646c6b](https://github.com/unraid/api/commit/7646c6b6c437a2b523245a29d829ead44fb57d28))
|
||||
* warning on missing fields ([0ef9aec](https://github.com/unraid/api/commit/0ef9aecccdde879e3be44d0b2a0fa4d8befc53b5))
|
||||
* **web:** activation modal steps, updated copy ([#1079](https://github.com/unraid/api/issues/1079)) ([8af9d8c](https://github.com/unraid/api/commit/8af9d8c58895010e3ddc03cc5fa075ac1e264f50))
|
||||
* **web:** add an 'all' option to notification filter ([7c2a72e](https://github.com/unraid/api/commit/7c2a72e0c9537827c3c96df7b6378c03e2cc2852))
|
||||
* **web:** add confirmation before archiving or deleting all notifications ([d16f08c](https://github.com/unraid/api/commit/d16f08c266953ddb84223f90f1275d19c9d3c380))
|
||||
* **web:** add count labels to notification tabs ([4caea3d](https://github.com/unraid/api/commit/4caea3dfc2c7067062f3ce8d863f9385ad030dbd))
|
||||
* **web:** add delete all notifications button to archive view in notifications sidebar ([3bda9d6](https://github.com/unraid/api/commit/3bda9d6a4ca01cc5580012b0133e72929d6dab40))
|
||||
* **web:** add empty state to notifications list ([5675fe1](https://github.com/unraid/api/commit/5675fe14d9d36ab638cb5e1b907f24bcf71cb7f1))
|
||||
* **web:** add gql archival mutations to notifications sidebar & item ([5f93be9](https://github.com/unraid/api/commit/5f93be9f55f3262502951a726f8fc015d73abc92))
|
||||
* **web:** add link to settings in notification sidebar ([f1a4d87](https://github.com/unraid/api/commit/f1a4d873481c212ffde1af7e38327a53a7e41d43))
|
||||
* **web:** add loading and error states to notification sidebar ([2e9183a](https://github.com/unraid/api/commit/2e9183a479e0ec5f7cfc34bb81ccfd05e4bd2b29))
|
||||
* **web:** clear notifications indicator after opening sidebar ([68958d1](https://github.com/unraid/api/commit/68958d17b78220c77c3cda4f0f4068b3ce623688))
|
||||
* **web:** delete notifications from archive view ([c8fc15d](https://github.com/unraid/api/commit/c8fc15d20bae527193ed289aef622a953a0d00bc))
|
||||
* **web:** display error when a notification mutation fails ([838ed86](https://github.com/unraid/api/commit/838ed86ffa47207ca2282a9ddabe245da713ba23))
|
||||
* **web:** enhance notifications indicator in UPC ([#950](https://github.com/unraid/api/issues/950)) ([6376848](https://github.com/unraid/api/commit/63768486e4ec64ab32666a26adf96f4db4a53e81))
|
||||
* **web:** implement notification filtering ([fa5156b](https://github.com/unraid/api/commit/fa5156bbc1f6bcc6c2e71b64b1e063120a868410))
|
||||
* **web:** make empty notification message clearer ([abab00d](https://github.com/unraid/api/commit/abab00ddccb7e485f2603b554704f531be79dd45))
|
||||
* **web:** make notifications list scrollable inside the sheet & tabs ([4c5d97b](https://github.com/unraid/api/commit/4c5d97b380de5574226e653c372c45ce61ea3ebb))
|
||||
* **web:** move notification indicator icons to top-right of bell icon ([2fe4303](https://github.com/unraid/api/commit/2fe4303387023d303d7e50fc4d9a41f1eafdcc45))
|
||||
* **web:** open official release notes via header os version ([54a893f](https://github.com/unraid/api/commit/54a893f396b29251b982ff1f26d376d24b962b93))
|
||||
* **web:** pull date format from display/date and time settings ([b058067](https://github.com/unraid/api/commit/b058067b628ca7866a9ba0a6c4c5e4d5505d98cb))
|
||||
* **web:** reconcile pagination with notifications apollo cache ([e38bc2c](https://github.com/unraid/api/commit/e38bc2c1218019cd1632123709620808c7543d11))
|
||||
* **web:** remove notification indicator pulse ([f320a77](https://github.com/unraid/api/commit/f320a77330c8cc7b92e170b0099d6c7f93b11c0e))
|
||||
* **web:** rm api-key validation from connect sign in ([#986](https://github.com/unraid/api/issues/986)) ([7b105d1](https://github.com/unraid/api/commit/7b105d18678e88a064f0643d6e857704789e0ee8))
|
||||
* **web:** rm old notification bell upon plugin installation ([#979](https://github.com/unraid/api/issues/979)) ([e09c07c](https://github.com/unraid/api/commit/e09c07c5070d59ac032baeff1ed253b5c00f4163))
|
||||
* **web:** support markdown in notification messages ([90cbef7](https://github.com/unraid/api/commit/90cbef774962e9d8ede47df7a4c1ca06f2a6651b))
|
||||
* **web:** update cache & view when archiving notifications ([08ab4d1](https://github.com/unraid/api/commit/08ab4d1a96c729c47feb868c10f398cad6dee5ba))
|
||||
* **web:** use Markdown helper class to interact with markdown ([f9c2d35](https://github.com/unraid/api/commit/f9c2d353133b01e74fe1bfbc420df3980d944012))
|
||||
* **web:** wip query api for notifications ([dec48b2](https://github.com/unraid/api/commit/dec48b2b0081362c5d0435eaabff1fb657d5f431))
|
||||
* WIP create teleport composable ([20e795e](https://github.com/unraid/api/commit/20e795ed6921337ae7875b483f2ab94860b74797))
|
||||
* wip Notification UI starter ([2f9e2ee](https://github.com/unraid/api/commit/2f9e2eef2db61221be66683caa4e75368aa475e0))
|
||||
* WIP notifications w/ shadcn ([5a90b32](https://github.com/unraid/api/commit/5a90b3285ad8524cea58cbaca8293675b3dc257b))
|
||||
* WIP sidebar filter select ([0c214fa](https://github.com/unraid/api/commit/0c214faaf69a69fc4da10a4a71b9c7cf7bd128c2))
|
||||
* workflow changes ([c97bfb8](https://github.com/unraid/api/commit/c97bfb8794d779ef253236fbdb7bb9909f4dfbca))
|
||||
* working ([29d7bd7](https://github.com/unraid/api/commit/29d7bd729bdfed79a3ce9c50014b3f1f32f9ac4e))
|
||||
* wrap Notifications in a GraphQL Node & implement notification overviews ([bf89178](https://github.com/unraid/api/commit/bf89178cb7e359e73da8c8f27253734be982dcc8))
|
||||
* zod config no longer any ([c32c5f5](https://github.com/unraid/api/commit/c32c5f57127b9469bde8806d78dc364562e73d9f))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 12 hour timestamp logic corrected ([03be43b](https://github.com/unraid/api/commit/03be43b4579f1dcf6a666a144f75b3063576748a))
|
||||
* actually install dependencies ([0895420](https://github.com/unraid/api/commit/089542061294e354b0e63a9f41001b77c0d62fed))
|
||||
* add another missing symlink ([4e7f3ff](https://github.com/unraid/api/commit/4e7f3ff4d9aa0e4af417a50e2b30537dda3c759c))
|
||||
* add ecosystem config ([7dd5531](https://github.com/unraid/api/commit/7dd553174e1c3aaaf71380abfe57348f30815bde))
|
||||
* add error check to nodejs ([c8e0fe8](https://github.com/unraid/api/commit/c8e0fe87a34d7f066b7d0900dda205a40616bfb6))
|
||||
* add max var ([ed681e1](https://github.com/unraid/api/commit/ed681e1d27fb7fa13bc8cbb5238da06e453a7c3b))
|
||||
* add return to resolver and update jsdoc for getNotifications ([a5e7d29](https://github.com/unraid/api/commit/a5e7d2956074376ef8e708b2bb7416cd2af3fe12))
|
||||
* allow concurrent testing with a shared patcher instance ([623846e](https://github.com/unraid/api/commit/623846ef46eb24a32c62516de58e8bc5d0219833))
|
||||
* always mangle ([e3a1eec](https://github.com/unraid/api/commit/e3a1eec5b62d010d05bb0908ba15fd8cb4f9d717))
|
||||
* **api:** append time to formatted date when a custom date format is selected ([0ac8ed9](https://github.com/unraid/api/commit/0ac8ed9d9e7e239e471eedf466832aed0270d123))
|
||||
* **api:** delay pm2 start until server has booted ([bd3188e](https://github.com/unraid/api/commit/bd3188efea4d3656994ffae32bd53f821c96358d))
|
||||
* **api:** exclude duplicates from legacy script in archive retrieval ([8644e13](https://github.com/unraid/api/commit/8644e130979ed8740c5a8da0b3984266e2b3684c))
|
||||
* **api:** improve defaults in PM2 service ([#1116](https://github.com/unraid/api/issues/1116)) ([57526de](https://github.com/unraid/api/commit/57526dede69e3a6547d05183e43c5b36dd1cae89))
|
||||
* **api:** load dynamix config in the same way as the webgui ([2c4fd24](https://github.com/unraid/api/commit/2c4fd2419ce05a10c8543a7f679852b54df3d10f)), closes [/github.com/unraid/webgui/blob/95c6913c62e64314b985e08222feb3543113b2ec/emhttp/plugins/dynamix/include/Wrappers.php#L42](https://github.com/unraid//github.com/unraid/webgui/blob/95c6913c62e64314b985e08222feb3543113b2ec/emhttp/plugins/dynamix/include/Wrappers.php/issues/L42)
|
||||
* **api:** make cookie recognition during websocket connection more ([353e012](https://github.com/unraid/api/commit/353e012db8ab5280863f32392c520b4a330c13cc))
|
||||
* **api:** pm2 start script & limit auto restarts ([#1040](https://github.com/unraid/api/issues/1040)) ([ebcd347](https://github.com/unraid/api/commit/ebcd3479e735724626ffc6907c338d5080898bee))
|
||||
* **api:** retry mothership connection up to 3x before logout ([#1069](https://github.com/unraid/api/issues/1069)) ([c27bb1b](https://github.com/unraid/api/commit/c27bb1be4c7a9ab201585586f3bc5e4afa1c7791))
|
||||
* **api:** sanitize incoming user session id's ([f5e3424](https://github.com/unraid/api/commit/f5e3424b79702e8f959b5519e83370a9e1d2033b))
|
||||
* **api:** slow init of unraid-api cli ([#1022](https://github.com/unraid/api/issues/1022)) ([5dbbae7](https://github.com/unraid/api/commit/5dbbae796792a62234497d056eac019aa084b21c))
|
||||
* **api:** strip server id prefixes from graphql request variables ([326d054](https://github.com/unraid/api/commit/326d0540f0865735f220e0fc7c5822913a7865ea))
|
||||
* **api:** update deploy-dev script to dist instead of src ([55cce09](https://github.com/unraid/api/commit/55cce09e65521762a6fe388d5b9b88ace1337c26))
|
||||
* **api:** validate cookie session data ([491f680](https://github.com/unraid/api/commit/491f680607ce7244d9e47a457e44cde711fbe00c))
|
||||
* apollo client lint issues ([a6d6dcc](https://github.com/unraid/api/commit/a6d6dcc2acc2b529c6f6821ce57865e521b84075))
|
||||
* app running ([5f71670](https://github.com/unraid/api/commit/5f716701715595f93fd0bc63b92ecf02335daa41))
|
||||
* apply and rollback error handling ([e22191b](https://github.com/unraid/api/commit/e22191bc77bc09f5c6c4ad57e5073829cf966ba4))
|
||||
* attempt to restore upgradepkg if install failed ([19c2a79](https://github.com/unraid/api/commit/19c2a79ce6c31c989f3d7f70cf7d8e2c219517b2))
|
||||
* authorization type error ([#987](https://github.com/unraid/api/issues/987)) ([7a4799e](https://github.com/unraid/api/commit/7a4799e9cd4caef6acfc3661d205a377fcf499ab))
|
||||
* back to default configs ([b5711c9](https://github.com/unraid/api/commit/b5711c91284072991bcf409ac6126cd4b46afc7c))
|
||||
* backup restore formatting ([15210f6](https://github.com/unraid/api/commit/15210f64b0938ec884a3ef4379d245c661eab9a3))
|
||||
* basic test fixed ([2f38035](https://github.com/unraid/api/commit/2f38035520ca0fe796c981d08b9136d89ffc5888))
|
||||
* better js file handling ([ddf160e](https://github.com/unraid/api/commit/ddf160e878a352842e813154b607945ccc7b4081))
|
||||
* better loader functionality and error handling ([8a57d2d](https://github.com/unraid/api/commit/8a57d2dccbcb9c2effc5df5d8c69ad02713de24a))
|
||||
* better logging when error ([6e4e3f8](https://github.com/unraid/api/commit/6e4e3f85abf64f8d799e33c33823810e71ef13e2))
|
||||
* build issues based on removed code ([59c1d5a](https://github.com/unraid/api/commit/59c1d5a3f991c4e3625a8853ade17d2ca8936474))
|
||||
* builder cache ([56771f6](https://github.com/unraid/api/commit/56771f6ee210297406d6bddff04de816ba0bb2d5))
|
||||
* capitalize name ([31166b3](https://github.com/unraid/api/commit/31166b3483dc01847ad555618c43f8248411bdfa))
|
||||
* changelog parser ([6fecec8](https://github.com/unraid/api/commit/6fecec8d4af3a4fccf2886791188711e1d2db77b))
|
||||
* check width before changing viewport ([f07381b](https://github.com/unraid/api/commit/f07381b243501ecc6d54063881faad77a99a7655))
|
||||
* cleaner logs for starting API ([79f26ef](https://github.com/unraid/api/commit/79f26ef251cb42e7f2106d00c6c05e2bf17b8227))
|
||||
* cleanup commands ([052aea0](https://github.com/unraid/api/commit/052aea06a0d30963532f29f9961fce0ffc7fa3e8))
|
||||
* clearer error messaging ([e373849](https://github.com/unraid/api/commit/e37384966c5b9079bb507052dcaba56232c1c42a))
|
||||
* code review feedback ([c66079e](https://github.com/unraid/api/commit/c66079e9a8e0ef47e5054118d0581bec708ac604))
|
||||
* completion script registration ([05c8c9b](https://github.com/unraid/api/commit/05c8c9bf078ece2061ad8ae32497f52b8c9b94dc))
|
||||
* connect key role ([2dcfc1c](https://github.com/unraid/api/commit/2dcfc1c19a1d085df84f0b1b50c096e3220205dd))
|
||||
* connect plugin location ([7867a93](https://github.com/unraid/api/commit/7867a932eb0bda43d3fb3613bdba227717510e4a))
|
||||
* convert updateId function to iterative instead of recursive ([65c20d2](https://github.com/unraid/api/commit/65c20d210987bc4dbb19f3e200fffa655b5fe2f4))
|
||||
* **CookieService:** potential race condition in unit tests ([1f2a380](https://github.com/unraid/api/commit/1f2a380b775adf44fdb3c85278fe0151584284f1))
|
||||
* **cors:** excessive instantiation of CookieService to improve memory overhead ([28c553d](https://github.com/unraid/api/commit/28c553d4c8d7c744e2b5554b1254cdd2bfda5ff5))
|
||||
* create api key for connect on startup ([58329bc](https://github.com/unraid/api/commit/58329bc29521ebc26b27ee20013ac3926c5088c2))
|
||||
* create api key permissions ([cefb644](https://github.com/unraid/api/commit/cefb644bd7fa513f553ca0ca4c49f0fb42a74112))
|
||||
* create connect key ([6b1ab7b](https://github.com/unraid/api/commit/6b1ab7b74ae1d2938fa9105180a5f66e9604fd41))
|
||||
* cwd on ecosystem.config.json ([dfd0da4](https://github.com/unraid/api/commit/dfd0da4ca23078f6de2e54d5e5bd6cba06334abc))
|
||||
* dark theme as array ([1021d0d](https://github.com/unraid/api/commit/1021d0da0d7a919dedec70656bb52775575aa9e7))
|
||||
* default overwrite false test ([cf59107](https://github.com/unraid/api/commit/cf59107e568d91be684176335db5300bee9be865))
|
||||
* delete .original files ([a9eb21a](https://github.com/unraid/api/commit/a9eb21aac0f373990aaa3f7a99731612540533cf))
|
||||
* delete boot script and update nvmrc ([ecd6b44](https://github.com/unraid/api/commit/ecd6b443c7dee8c5c5dee959f9ff3ace192204c7))
|
||||
* delete unused line ([de4882e](https://github.com/unraid/api/commit/de4882ea17f54e788049cc5bb96b99b16822b6b4))
|
||||
* delete upgradepkg ([74f0177](https://github.com/unraid/api/commit/74f0177ba0fd57722caa3ec14318d35167d3c6f7))
|
||||
* deprecated version warning ([89d0bd2](https://github.com/unraid/api/commit/89d0bd2e6da35fb1e8d95627d38edb54f82e0c6b))
|
||||
* **deps:** update apollo graphql packages ([7b1ee99](https://github.com/unraid/api/commit/7b1ee9940cca46e563bb79c7056996315f9decc5))
|
||||
* **deps:** update dependency @apollo/client to v3.12.6 ([22ce615](https://github.com/unraid/api/commit/22ce61574f862eac4cdf8c00141bfbf1ac948055))
|
||||
* **deps:** update dependency @apollo/client to v3.12.6 ([bb7800a](https://github.com/unraid/api/commit/bb7800a8c088705fd8310671a9896cbe9b0184e5))
|
||||
* **deps:** update dependency @apollo/client to v3.12.9 ([6607cf2](https://github.com/unraid/api/commit/6607cf20c10a091d466c6a8031eebc17feb3e3fc))
|
||||
* **deps:** update dependency @floating-ui/dom to v1.6.13 ([08798d2](https://github.com/unraid/api/commit/08798d2f77683412807d684d7a8e63f1aadb0c34))
|
||||
* **deps:** update dependency @floating-ui/dom to v1.6.13 ([4d4c218](https://github.com/unraid/api/commit/4d4c218ac78e82a18679ec7b4939523db032b99b))
|
||||
* **deps:** update dependency @floating-ui/vue to v1.1.6 ([b4b7d89](https://github.com/unraid/api/commit/b4b7d898b62f746180b7f5730b5d9b5033dcecc2))
|
||||
* **deps:** update dependency @floating-ui/vue to v1.1.6 ([4c07d38](https://github.com/unraid/api/commit/4c07d389523f277950b8d2d359102f889587e5ce))
|
||||
* **deps:** update dependency @graphql-tools/load-files to v7.0.1 ([4e5c724](https://github.com/unraid/api/commit/4e5c7242e43cc356f1c69adcfcd25b57896af476))
|
||||
* **deps:** update dependency @nestjs/schedule to v4.1.2 ([faf0de5](https://github.com/unraid/api/commit/faf0de5a19256efb83dc45a484e3cba65596ccd7))
|
||||
* **deps:** update dependency chokidar to v4.0.3 ([d63a93c](https://github.com/unraid/api/commit/d63a93c55004d17b6d17634c55ffbc5670ebbec7))
|
||||
* **deps:** update dependency dotenv to v16.4.7 ([c66a650](https://github.com/unraid/api/commit/c66a6502b027853046d126a14ddee870ffabd10c))
|
||||
* **deps:** update dependency execa to v9.5.2 ([d487c90](https://github.com/unraid/api/commit/d487c90ccc20162c76f0cdf49a736c1fee4271bd))
|
||||
* **deps:** update dependency express to v4.21.2 ([a070306](https://github.com/unraid/api/commit/a07030684c8777e47eb4a51be0ea680b7f217e74))
|
||||
* **deps:** update dependency focus-trap to v7.6.4 ([41ff232](https://github.com/unraid/api/commit/41ff232a3232dda66e5cdc2d4808a820a90a5d34))
|
||||
* **deps:** update dependency focus-trap to v7.6.4 ([f0e3038](https://github.com/unraid/api/commit/f0e3038ee7426aafb6cef01b85b47893c2238302))
|
||||
* **deps:** update dependency got to v14.4.5 ([975a47c](https://github.com/unraid/api/commit/975a47c7d47841c49443f46264feb54abf53698c))
|
||||
* **deps:** update dependency graphql-ws to v5.16.2 ([a189a03](https://github.com/unraid/api/commit/a189a0308a734e66750fe5059f7c59d8c9532bd8))
|
||||
* **deps:** update dependency graphql-ws to v5.16.2 ([25d8f08](https://github.com/unraid/api/commit/25d8f085b67c2e53876d837c739214dc874116b8))
|
||||
* **deps:** update dependency ini to v4.1.3 ([4c88cbe](https://github.com/unraid/api/commit/4c88cbee4b2d5f6717241dadac23bfe90ce15193))
|
||||
* **deps:** update dependency node-window-polyfill to v1.0.4 ([8bfa88f](https://github.com/unraid/api/commit/8bfa88f4bc932eb82dd9b33a494811ea15764758))
|
||||
* **deps:** update dependency openid-client to v6.1.7 ([0f50517](https://github.com/unraid/api/commit/0f50517a8544e1eb9b08ad1b3f05f798491b7f23))
|
||||
* **deps:** update dependency p-retry to v6.2.1 ([c6f3241](https://github.com/unraid/api/commit/c6f324155019e066701723a57b642c6e3ba8332d))
|
||||
* **deps:** update dependency pm2 to v5.4.3 ([a754090](https://github.com/unraid/api/commit/a75409026dd4e3d9ed120802012b67b179327448))
|
||||
* **deps:** update dependency radix-vue to v1.9.12 ([0fd433f](https://github.com/unraid/api/commit/0fd433fe2a6b3f787624cb5a98efeae0f6c31cfd))
|
||||
* **deps:** update dependency radix-vue to v1.9.13 ([249feff](https://github.com/unraid/api/commit/249feff5cfe0bbb60bfa8f943b76b9c16c6c161b))
|
||||
* **deps:** update dependency uuid to v11.0.5 ([7e3398b](https://github.com/unraid/api/commit/7e3398b2efabf1a5407d6e20c165eb4923b3bab2))
|
||||
* **deps:** update graphql-tools monorepo ([cd7e2fe](https://github.com/unraid/api/commit/cd7e2feea199276a1d431cf355e54e12e5960d9a))
|
||||
* **deps:** update graphqlcodegenerator monorepo ([0446c59](https://github.com/unraid/api/commit/0446c5924a6a9dd15b875628ca0f1197cfe521c4))
|
||||
* **deps:** update graphqlcodegenerator monorepo ([15c789d](https://github.com/unraid/api/commit/15c789dbb34b85bed55c2731fb8ae8260f5f311f))
|
||||
* **deps:** update nest monorepo to v10.4.15 ([07b1ea9](https://github.com/unraid/api/commit/07b1ea9a10634a597909ae1d237cc3b1e7f959b7))
|
||||
* **deps:** update nest-graphql monorepo to v12.2.2 ([91aabd9](https://github.com/unraid/api/commit/91aabd9ffbfb8c2ceb4110217dfc05de8859077d))
|
||||
* detection script path bin instead of sbin ([7138fd2](https://github.com/unraid/api/commit/7138fd297abc1435f61e7e4c8f4a5a91662c64f0))
|
||||
* dev mode ([fd64e01](https://github.com/unraid/api/commit/fd64e01e0c87db03fc2d4d0f32a0e8205fbe8b84))
|
||||
* disable permissions bypass to avoid incorrect role assignment to api keys ([343489e](https://github.com/unraid/api/commit/343489e52c526757c1449a6f5074def50e73a380))
|
||||
* dnserr on new line ([a3398a2](https://github.com/unraid/api/commit/a3398a29e15269be006e887fba6366c81b1d00f5))
|
||||
* do not process.exit on restart or stop command ([933575f](https://github.com/unraid/api/commit/933575fc2badbb09b3a9d3c66724e37a9ee246f2))
|
||||
* docker formatting and build mkdir issues ([f447739](https://github.com/unraid/api/commit/f447739585e8ed8449653802c1f0d4d11d6c65de))
|
||||
* don't check code for execa ([508a5eb](https://github.com/unraid/api/commit/508a5eb49d9514dca9953317d9fa93314fe63e4c))
|
||||
* don't LS in the release folder ([ab9d969](https://github.com/unraid/api/commit/ab9d9695394a300d6b0799e9b644dd5d0f969d72))
|
||||
* dont remove login file without a backup presetn ([0370e4f](https://github.com/unraid/api/commit/0370e4f7ea3e3df0d2264264324d8e53ffc0c086))
|
||||
* downgrade marked to fix changelog preview issue ([cfb3a45](https://github.com/unraid/api/commit/cfb3a45533d3c1bd31c44094f7ae2912e77a673e))
|
||||
* edit settings padding issue ([adf349b](https://github.com/unraid/api/commit/adf349b76560b5f1fd4c320da35b3c6f660895fb))
|
||||
* ensure directory exists before making connect key ([9e27ec9](https://github.com/unraid/api/commit/9e27ec98b68a49bdd6dc4b03de8c0cc3a1470a5e))
|
||||
* env correct ([9929856](https://github.com/unraid/api/commit/99298566382313f1da9c374dbec3652c1b2812d3))
|
||||
* env input ([c182c06](https://github.com/unraid/api/commit/c182c06d9443597521eaacd2052d905e0138cac4))
|
||||
* EOF ([25ac1b5](https://github.com/unraid/api/commit/25ac1b5f0772d3ce63d47eb8a1dc640be125b68b))
|
||||
* eslint config ([b28a605](https://github.com/unraid/api/commit/b28a605300cee1e9ce1f5db3a165b4d0d2080316))
|
||||
* excess spacing in api-key.service ([1deb002](https://github.com/unraid/api/commit/1deb0023287a39d40e52e89c515a28e62352f62c))
|
||||
* execa upgrade snapshots fixed ([d8244f7](https://github.com/unraid/api/commit/d8244f7aac02dd97c756a9784391cd661f3536ba))
|
||||
* extra log line ([1183063](https://github.com/unraid/api/commit/1183063aa7063afd8222def18f5e1fd6077e8c88))
|
||||
* extra spacing in config.ts ([f3ee7be](https://github.com/unraid/api/commit/f3ee7be80f2c60266fbb13597a70f0a389fb577f))
|
||||
* file modification service fixes ([aa5b3f4](https://github.com/unraid/api/commit/aa5b3f4e47ed88df23af00dfcccb7b64786b6231))
|
||||
* find by key, not ID ([3c3fa1e](https://github.com/unraid/api/commit/3c3fa1e27cfabbe6926c3da8870751397eed1def))
|
||||
* floating-ui fixes ([1c3b43b](https://github.com/unraid/api/commit/1c3b43b4464662e1a1b21695e601cd7f7e4fd734))
|
||||
* forced restarting on commands ([925866d](https://github.com/unraid/api/commit/925866d389e337fcb8c249ead929e1f65854465b))
|
||||
* format authrequest mod as other files ([180a81d](https://github.com/unraid/api/commit/180a81dbae8e749eae237fc8cee2950c790eedf0))
|
||||
* formatting issue ([42ca969](https://github.com/unraid/api/commit/42ca9691f7547a4340501863c1882efc0aee4c60))
|
||||
* further resolve sso sub ids issues ([ef3d0ea](https://github.com/unraid/api/commit/ef3d0ead687d4a6071da290c0df29c12163303e1))
|
||||
* handle special chars better ([d364bb1](https://github.com/unraid/api/commit/d364bb1fc4c042469ce4b0ca6001a807d0b002da))
|
||||
* improve typing and format lookup ([c6097f8](https://github.com/unraid/api/commit/c6097f86e42fcc57209c1344029abe854198edca))
|
||||
* initial feedback about report addressed ([5dee09c](https://github.com/unraid/api/commit/5dee09c77ad375de2eca59f650e5fea2070087b5))
|
||||
* install as-integrations/fastify ([ff4546d](https://github.com/unraid/api/commit/ff4546d6692d2a4799f2dbeef0d5e5c6bac62561))
|
||||
* install syntax error ([ec83480](https://github.com/unraid/api/commit/ec83480eb6aea09b98b9135516dc1fc8cdd6c692))
|
||||
* integration of `unraid-ui` tailwind config in `web` ([#1074](https://github.com/unraid/api/issues/1074)) ([f3cd85b](https://github.com/unraid/api/commit/f3cd85bd3f02bdbe4c44136189d1c61935015844))
|
||||
* invalid type ([e13794f](https://github.com/unraid/api/commit/e13794f8e56081335ebc16b00a2f8631f9639909))
|
||||
* length ([83579f1](https://github.com/unraid/api/commit/83579f1fbd03ffe929d009c20d214b4de62835c6))
|
||||
* lint ([0f218b8](https://github.com/unraid/api/commit/0f218b8b72e397734823efab8f2141973a3a80ce))
|
||||
* lint ([82bca54](https://github.com/unraid/api/commit/82bca54c594265ddf23a298691bd7ef6d4b47f32))
|
||||
* lint ([ceb443d](https://github.com/unraid/api/commit/ceb443da15d177a950c36af61b93a7126cf4ca85))
|
||||
* lint ([da04e7c](https://github.com/unraid/api/commit/da04e7ce0873d7802a936952d91e9867f0868a6e))
|
||||
* lint ([7d87f0e](https://github.com/unraid/api/commit/7d87f0eee23dfa0f391fd342d38ed9084f18d8d4))
|
||||
* lint issues ([48e482b](https://github.com/unraid/api/commit/48e482b913d4f27f49ae669c7c19dc0714d3c0c7))
|
||||
* linter error ([6dba28d](https://github.com/unraid/api/commit/6dba28dd1bbe0125f842271eeae9daf54826b063))
|
||||
* load builder image to cache ([5497bc3](https://github.com/unraid/api/commit/5497bc3235bd3c8b427b3418a7be2e3ece4c4abc))
|
||||
* load notifications from file system instead of redux state ([53a37cd](https://github.com/unraid/api/commit/53a37cd1d20bb2b738bdeda832a42196d662b8a4))
|
||||
* load PM2 from node_modules ([5a07e8c](https://github.com/unraid/api/commit/5a07e8cae5ce9ced9980a9df950d053196edf65b))
|
||||
* local variable assignment ([f7d9ccc](https://github.com/unraid/api/commit/f7d9ccc0820f0fe8efa55b1c2d75f79819c764c4))
|
||||
* logging location ([572b922](https://github.com/unraid/api/commit/572b922f4d72759a5ed7d06ddfa4af3bfb655c6b))
|
||||
* logrotate error ([8c64dd2](https://github.com/unraid/api/commit/8c64dd2f2c65aa83ce0e2d501357ee595c976e56))
|
||||
* lowercase or ([386cbde](https://github.com/unraid/api/commit/386cbdef5c9158290e03c670efb992cf11d5af1b))
|
||||
* make cli.js executable ([644db0e](https://github.com/unraid/api/commit/644db0ef3315b00361524ea0fe440083f35088a0))
|
||||
* marked single input ([ceacbbe](https://github.com/unraid/api/commit/ceacbbe5d46466627df0fccc5ca8e7c56fa36a37))
|
||||
* missing ip-regex module ([fde7202](https://github.com/unraid/api/commit/fde720264bf395c0047356c3084878c8878aadfa))
|
||||
* missing server type ([f1b721b](https://github.com/unraid/api/commit/f1b721bd72b875d9ff8c0bca2cc1eee506ba7697))
|
||||
* mock ensureDirSync ([7e012e6](https://github.com/unraid/api/commit/7e012e6a2eb96ccddf5a1f69d7580b4bdfe7a0a9))
|
||||
* more color work ([c48f826](https://github.com/unraid/api/commit/c48f8268def64ef8828dea556360b375b8cb32c7))
|
||||
* more filename fixes and PR var passing ([088dbed](https://github.com/unraid/api/commit/088dbed9b2fabfaf55b003fb1fa9c10c558f21d5))
|
||||
* more generic test ([0f651db](https://github.com/unraid/api/commit/0f651dbf61a1822b492aa80030f0bc231bc6f606))
|
||||
* more verbose logging for node install to find issues ([445af0c](https://github.com/unraid/api/commit/445af0c147ef641dac05ebeb2d44e63e8a4df799))
|
||||
* mv paths() to top of NotificationsService to make it more intuitive ([7138568](https://github.com/unraid/api/commit/713856818dfaf7d7f5807eacc3b7d61561888082))
|
||||
* no more node_dl_server ([77779a6](https://github.com/unraid/api/commit/77779a655f18e9d474ad8a7e61c8ef51090a49d8))
|
||||
* no nodehost ([6787ec7](https://github.com/unraid/api/commit/6787ec7d65ecef27652ca48193fe64f2ea82ca4e))
|
||||
* no vite-node in non-dev mode ([023f73f](https://github.com/unraid/api/commit/023f73f3992b42f60aa56d8dd51a5e698c140306))
|
||||
* node install process improvements ([b8540dd](https://github.com/unraid/api/commit/b8540ddeb888678edd24db31a6747583761d5aa9))
|
||||
* node_txz naming ([b7c24ca](https://github.com/unraid/api/commit/b7c24ca861e92bf01118a17bc7e2322063e6a800))
|
||||
* **NotificationItem:** icon & text alignment in header ([98716f7](https://github.com/unraid/api/commit/98716f70a6a2c29610e1ed7cda1aedad5065134d))
|
||||
* **NotificationService:** file watcher initialization ([b7e3f8e](https://github.com/unraid/api/commit/b7e3f8e42ae4bf488228503b4e5234b1e7a38180))
|
||||
* **NotificationsService:** edge-case in deleteAllNotifications by adding fs-extra package ([fef763a](https://github.com/unraid/api/commit/fef763a3298b9bf4aae2e18db4722637ce9bd7e4))
|
||||
* **NotificationsSidebar:** occupy full viewport on small screens ([1f81fb8](https://github.com/unraid/api/commit/1f81fb8b92bef102b0b7d2daf562c9b4e296473e))
|
||||
* oauth2 api prefix ([ec00add](https://github.com/unraid/api/commit/ec00adde20d4d9eca28f6b18615073305f491a73))
|
||||
* only instantiate service one time ([933dc81](https://github.com/unraid/api/commit/933dc81b6c50db5a33f586f7094e1ea524b9a9fa))
|
||||
* only test if API was changed ([5871143](https://github.com/unraid/api/commit/5871143b809d6a6784e949e20212599a54afc71f))
|
||||
* only test when API is changed ([ddea0e8](https://github.com/unraid/api/commit/ddea0e8e11816c58e5b50cb611e5796fbca3fecf))
|
||||
* only toast unread notifications, not archived ones ([cc59be6](https://github.com/unraid/api/commit/cc59be6cb3efc71226ee50f9f04e37a2e4b50de6))
|
||||
* padding and glob function issues ([1d3f2eb](https://github.com/unraid/api/commit/1d3f2eb8213115c3385ac2d29ee8f53560347ba8))
|
||||
* pass env through to docker ([200be38](https://github.com/unraid/api/commit/200be384f9dec86a1e77f46a0e6a336e86ba7563))
|
||||
* pass ssoSubIds only ([5adf13e](https://github.com/unraid/api/commit/5adf13ee070bdcd849339460b9888e51d224e765))
|
||||
* pass token to password field ([499b023](https://github.com/unraid/api/commit/499b023d359ed5181450ee9e04cbbf4531a4a680))
|
||||
* patch-utils unused ([047808d](https://github.com/unraid/api/commit/047808dce0cd9e9b4b273a9124dbd45ca9446208))
|
||||
* paths now correct, better download logic ([16db2d9](https://github.com/unraid/api/commit/16db2d908dcb2c65508b367712c51bf9872a95e5))
|
||||
* pkg_build ([d4bff0e](https://github.com/unraid/api/commit/d4bff0ee96e6e0974978465573e72e68d09fd829))
|
||||
* plugin download route and add env node to cli script ([78bd982](https://github.com/unraid/api/commit/78bd9820200a0996d9b8c5f718a97c20ed4feab4))
|
||||
* PR build missing files ([57f9b95](https://github.com/unraid/api/commit/57f9b95134be5c3dd8053f57f82e91a0e0622d3e))
|
||||
* production env for web build ([b4107f6](https://github.com/unraid/api/commit/b4107f6c4d4db47d7331f4b3d30a4ace724a8f0e))
|
||||
* proper directory in rc.unraid-api ([a3add5a](https://github.com/unraid/api/commit/a3add5ae165b09dd695a2ddabf6131ac8700825f))
|
||||
* proper file replacements ([e0042f3](https://github.com/unraid/api/commit/e0042f353b47cfa72a485d6a58ad0b956ea6dbc2))
|
||||
* properly log error with template string ([3781f1f](https://github.com/unraid/api/commit/3781f1f41c7f0eef604daee0402ed9a2bb27cd46))
|
||||
* properly restart the API when installed ([765593a](https://github.com/unraid/api/commit/765593a3da1e3b8bee1ae6c8aa1d9d0f2498d41c))
|
||||
* pull node version directly from nvmrc ([b2e6948](https://github.com/unraid/api/commit/b2e694881218c08765b26ada08ed6ab325177b1e))
|
||||
* pull token from query not params ([2e827e7](https://github.com/unraid/api/commit/2e827e7cabe4a6a069d4e8779015e5896d8a1d1d))
|
||||
* race condition when updating notification types ([f048f56](https://github.com/unraid/api/commit/f048f566627e91947cc98550412ca68d728c52c7))
|
||||
* re-add type-check ([60e9d1d](https://github.com/unraid/api/commit/60e9d1d912c983cf04e3e6cf15e221c39938612a))
|
||||
* recreate package-lock to fix issues ([ad5a537](https://github.com/unraid/api/commit/ad5a53793d25ac9f63bae6df6c2a30d8d2780c67))
|
||||
* remove console log ([8e75b82](https://github.com/unraid/api/commit/8e75b8254bbda93ded786750226090b769bed5c4))
|
||||
* remove console logs with vue plugin ([2b2e923](https://github.com/unraid/api/commit/2b2e9236ce55cfc3ca10f708ed08e09dcfd402d1))
|
||||
* remove devDependencies from output package json ([294869b](https://github.com/unraid/api/commit/294869bbea7f8a1863f8aafae6b074330e057679))
|
||||
* remove extra space ([a99ee03](https://github.com/unraid/api/commit/a99ee03fc37059b3a018db289c43fc419a634524))
|
||||
* remove isNaN in favor of number.isNaN ([03e3a46](https://github.com/unraid/api/commit/03e3a46092db613281176b88cae284f6448027c6))
|
||||
* remove line from or in button ([1a1bce7](https://github.com/unraid/api/commit/1a1bce7b64b1cf90505f811e11b585ff87476f72))
|
||||
* remove memory key generation ([b84db13](https://github.com/unraid/api/commit/b84db1322104c7f26f7b6378f25a2757b3010c6d))
|
||||
* remove uneeded env variable ([f688a35](https://github.com/unraid/api/commit/f688a350d3d0a1c47be5896e6fbf92eeb8433967))
|
||||
* remove unused constructor ([e0e2a7b](https://github.com/unraid/api/commit/e0e2a7b41c5e599ed4cf3bf49c7faea3b71f0b70))
|
||||
* remove unused date-fns ([fe94ef5](https://github.com/unraid/api/commit/fe94ef5ba88df56aad87089081dd5fe4518fa414))
|
||||
* remove unused disableProductionConsoleLogs call ([691661b](https://github.com/unraid/api/commit/691661b952394e61a1b79c41419745fbf6caba20))
|
||||
* remove unused imports ([65c1891](https://github.com/unraid/api/commit/65c18917563745cab9711e9900086e90ab44e284))
|
||||
* remove unused job dependency ([84533d8](https://github.com/unraid/api/commit/84533d8fa56dc19635ea33d79bd8e644e539edd2))
|
||||
* remove unused login entries ([7833b5d](https://github.com/unraid/api/commit/7833b5db386f724318857fc31d825fb3534c84b9))
|
||||
* remove usage of Role.UPC ([d1e2f6e](https://github.com/unraid/api/commit/d1e2f6e0b391cb4eca75a0997b41cb99a9953d42))
|
||||
* render function fixed ([8008ab4](https://github.com/unraid/api/commit/8008ab46fb2f231b68201758a258fd43e2e1672e))
|
||||
* replace express cookie parser with fastify's ([0acebb0](https://github.com/unraid/api/commit/0acebb0dd25e919f3cc132eb7f96927992fc4151))
|
||||
* report issues + pm2 issues ([28c383e](https://github.com/unraid/api/commit/28c383e1d111d4ac4226d7d966533ba80ca5d9a1))
|
||||
* reset config to be closer to default ([b7fbb0b](https://github.com/unraid/api/commit/b7fbb0b6af0453f5f6a17087bb7e68c393b9fe3f))
|
||||
* resource busy when removing all subdirectories ([29936c9](https://github.com/unraid/api/commit/29936c90938fb83bc2f154315ca63a9d7cc98552))
|
||||
* restart command elegant ([296117b](https://github.com/unraid/api/commit/296117b51aac8a4c15366f2271af858868b6e071))
|
||||
* restore upgradepkg before install ([fddca27](https://github.com/unraid/api/commit/fddca2738c0ec016e744169d88b35a55dea092fa))
|
||||
* revert changes to indicator.vue ([84d2a83](https://github.com/unraid/api/commit/84d2a832c0f64e52be05670eb438b21bff2e5163))
|
||||
* revert myservers.cfg ([d0896f3](https://github.com/unraid/api/commit/d0896f3ef8aebdd9c76d805ed6a35b4a5d5a1b08))
|
||||
* rm getServerIdentifier wrapping Notifications id ([eaea306](https://github.com/unraid/api/commit/eaea306d54f633f563c7340f8a992e03b631f903))
|
||||
* rm rf to fix build issues ([a27cbe0](https://github.com/unraid/api/commit/a27cbe00d813ede6f31d4824fd63ff29a1ef6972))
|
||||
* sandbox defaults in dev mode wrong ([2a24919](https://github.com/unraid/api/commit/2a2491936cf85013be836450ab7ed0cc11207e11))
|
||||
* sequential test execution for generic-modification ([79ee1f7](https://github.com/unraid/api/commit/79ee1f7552cee47c6f5a8eb5942468292212e2f2))
|
||||
* shell path to unraid-api ([15d11e4](https://github.com/unraid/api/commit/15d11e477bb2a08d785a7b22bd51900279a55508))
|
||||
* staging build issues ([e6bcb8d](https://github.com/unraid/api/commit/e6bcb8de7daee463f7ac0dbf977e085e108302ba))
|
||||
* start command simplification ([e1faf3a](https://github.com/unraid/api/commit/e1faf3aa8db5973eb1bb0ea7a4844f820504618d))
|
||||
* stop command exits ([2dbfdb6](https://github.com/unraid/api/commit/2dbfdb670a773114c0fdc68c7cf9d29fa4e28a9b))
|
||||
* strip components from tar line ([911cd5b](https://github.com/unraid/api/commit/911cd5bc0b0983df4ca8c9057bea5166f7d1c7f1))
|
||||
* subdependenies ([f1ad3b0](https://github.com/unraid/api/commit/f1ad3b0af13345189e10973b422f4e5c6b5d7839))
|
||||
* swap to flexible IDs in tests ([b95559d](https://github.com/unraid/api/commit/b95559d9a1e743f92bc3b776892286e8d7abfc1e))
|
||||
* swap to placeholder key ([d1864d0](https://github.com/unraid/api/commit/d1864d0020ed56ab2368d23b48604b55cff21ae4))
|
||||
* switch to useToggle ([848233f](https://github.com/unraid/api/commit/848233f05465053876ac6f9f6ac4bfad2a48abff))
|
||||
* test issues ([e4b55b1](https://github.com/unraid/api/commit/e4b55b133bb2dc4bf2ccfd6fd2fc244daadbea53))
|
||||
* test simplification to ensure no redownloads ([e07dad3](https://github.com/unraid/api/commit/e07dad3a6947aa186c4ac03032b5b3813cd046b6))
|
||||
* tests ([25c1c1a](https://github.com/unraid/api/commit/25c1c1a55a3fb32b76bf5cb7257a4ba44f717a89))
|
||||
* tests and validate token clears screen ([7f48ddd](https://github.com/unraid/api/commit/7f48dddcd2e2ea1ae3a55ecc54d5ac274535b714))
|
||||
* text classes ([1e17cfc](https://github.com/unraid/api/commit/1e17cfc2bca5e8431188804b28f4645eb42cdc9f))
|
||||
* theme store now uses singular variables object ([5ca6e40](https://github.com/unraid/api/commit/5ca6e40b2d4942385b12a4325d6b8a551cb3f44b))
|
||||
* thorw on invalid token body ([f1af763](https://github.com/unraid/api/commit/f1af763eaf0dd8215eed470293d3a7f98784f38a))
|
||||
* trigger loading correctly ([e18f3d3](https://github.com/unraid/api/commit/e18f3d3e566011054163ec7827494fa047b26ec9))
|
||||
* type & build errors ([800969a](https://github.com/unraid/api/commit/800969a87a45d1d3ca9eca65657fddeccba66f28))
|
||||
* type error on element render ([a2563eb](https://github.com/unraid/api/commit/a2563eb8e710a9ac7259c4260cad9a3454565dae))
|
||||
* type for generic test ([e856535](https://github.com/unraid/api/commit/e85653592a9d6eadcd0be89bf90a96c5d313fda3))
|
||||
* unit test failure ([fed165e](https://github.com/unraid/api/commit/fed165eab0358fe032a99e5afbdb19813b00b741))
|
||||
* unit test issues ([c58f7a7](https://github.com/unraid/api/commit/c58f7a7f246902c7d354eb51d1c87c8ea3b636a3))
|
||||
* unit tests updated ([9548505](https://github.com/unraid/api/commit/954850535bec6b09aaf66b01d3ee749c8a22de5d))
|
||||
* unneeded await on api-key service ([0325be7](https://github.com/unraid/api/commit/0325be757ee4c04b5c23365ff592f521a492595b))
|
||||
* unraid-api in usr/bin ([580babd](https://github.com/unraid/api/commit/580babdafddd89ee2fb0b07aa7f5dff865be37d2))
|
||||
* unused import ([83fbea5](https://github.com/unraid/api/commit/83fbea5632b1de71afa4d0ca3224a946bf76fd23))
|
||||
* unused imports ([a5447aa](https://github.com/unraid/api/commit/a5447aa2f4c99968651fa3750d6bf0e8d68678de))
|
||||
* unused node dl line ([7ea1c3a](https://github.com/unraid/api/commit/7ea1c3a8f24e47f2e10994ffe629135dc4614159))
|
||||
* upc header text color ([f989026](https://github.com/unraid/api/commit/f9890260d1c4abe69dac3ac4c05ebab17aab5161))
|
||||
* update tests ([d0696a9](https://github.com/unraid/api/commit/d0696a93810893ccd6c676df1c639ca279992428))
|
||||
* upgradepkg ([90cf1a8](https://github.com/unraid/api/commit/90cf1a8eea67d3dbc736ecdfba47e0025b1dc31c))
|
||||
* use an enum and defaults for sandbox value ([eb56483](https://github.com/unraid/api/commit/eb56483ba2693944d39f4409c91b75ee82a7d30b))
|
||||
* use batchProcess ([ffbb9d7](https://github.com/unraid/api/commit/ffbb9d7750568bfa849d21e051503d1fcca5355f))
|
||||
* use correct ini encoder in notification service ([d1f8c61](https://github.com/unraid/api/commit/d1f8c61f1b9ea5745acdfd2d60de4725b4dffe05))
|
||||
* use cwd when running application ([e016652](https://github.com/unraid/api/commit/e01665264b6f45366cdacf60c0f3553adfbd85d3))
|
||||
* use foreground text color for UPC ([87b8165](https://github.com/unraid/api/commit/87b816550d413dc9023c5057efe18b9cb26761e7))
|
||||
* use placeholder in test API key ([c6b7755](https://github.com/unraid/api/commit/c6b7755214de8bedd5c0f2735473c2a559b1e26f))
|
||||
* use unraid binary path to call unraid commands ([555087d](https://github.com/unraid/api/commit/555087dcdd2bc9e5a6f2ccbdaff30a1bc89ad712))
|
||||
* used TGZ instead of TXZ for nghttp3 ([09ad394](https://github.com/unraid/api/commit/09ad39483fed7a8155176b6568114b4e6679d587))
|
||||
* variable naming ([dbffc0d](https://github.com/unraid/api/commit/dbffc0d293cefcb8d923cbcb17ad1f1a1d5e302d))
|
||||
* variables passed properly ([e0875e7](https://github.com/unraid/api/commit/e0875e7a1b273969939d6902a55f4a9772640078))
|
||||
* version and EOF key ([cafa47d](https://github.com/unraid/api/commit/cafa47d283d9b637c1e8dfbd7407186e58233358))
|
||||
* watch all events to load keys ([59ca177](https://github.com/unraid/api/commit/59ca17787e4d36113b0a8c5ef2117acfc491c49c))
|
||||
* **web:** add default values to optional vue component props ([d3092e4](https://github.com/unraid/api/commit/d3092e487ead2ca4647928008ee54f3cd6b333c2))
|
||||
* **web:** dedupe incoming notifications during cache merge ([4a40729](https://github.com/unraid/api/commit/4a40729e3721d01ac45614f4b7d1c48aec483cbc))
|
||||
* **web:** display error message in sidebar when api is offline ([#984](https://github.com/unraid/api/issues/984)) ([125c0a1](https://github.com/unraid/api/commit/125c0a140b4e9b5401bacf1addab1820c412917e))
|
||||
* **web:** edge case where archived notifications don't appear ([0a8c574](https://github.com/unraid/api/commit/0a8c5746fc2b8f8639643f013c1f19f0d7236d41))
|
||||
* **web:** env var typo ([22cf90b](https://github.com/unraid/api/commit/22cf90b27fadec3024d9d038c53683e8f8a723bc))
|
||||
* **web:** escaping html-encoded symbols like apostrophes in translations ([#1002](https://github.com/unraid/api/issues/1002)) ([04a3362](https://github.com/unraid/api/commit/04a33621e1d406d75ed0ff9af9f1f945813a1e8d))
|
||||
* **web:** flash of disconnected api state on page load ([a8c02f4](https://github.com/unraid/api/commit/a8c02f4c49433b440a6f9c70f269bf69076655dc))
|
||||
* **web:** infinite scroll loop when there's only 1 page of notifications ([e9f2fc4](https://github.com/unraid/api/commit/e9f2fc424c350d07c756ae7573e90f615bcae25b))
|
||||
* **web:** infinite trigger at bottom of infinite scroll ([eb691d3](https://github.com/unraid/api/commit/eb691d3514d8dc079987bfa566de4aa86094ef67))
|
||||
* **web:** inline shadcn variables into tailwind config to simplify build ([07fd7fe](https://github.com/unraid/api/commit/07fd7fe120f42ddf15c19f2a7df135fb9741187b))
|
||||
* **web:** notification styles & alignment ([#968](https://github.com/unraid/api/issues/968)) ([0d65e12](https://github.com/unraid/api/commit/0d65e12cede3324261fd3b219745b1e7793a33de))
|
||||
* **web:** refetch notifications for sidebar when new notifications arrive ([591bf4a](https://github.com/unraid/api/commit/591bf4a643ccc13c151c0a8cafad833d3137043e))
|
||||
* **web:** remove unused infinite-scroll emit from SheetContent ([95db23f](https://github.com/unraid/api/commit/95db23f8e13574a50e0ba3860bbfd54fd663c20e))
|
||||
* **web:** remove warn and error console log removal ([#1086](https://github.com/unraid/api/issues/1086)) ([9375639](https://github.com/unraid/api/commit/9375639e4a71ecfe8d4b877301c1f9bb22800a72))
|
||||
* **web:** replace incorrect custom types with codegen from gql & update values to match expected shapes ([fc93ef8](https://github.com/unraid/api/commit/fc93ef8e32607c807f9bd8529088a69937bdaefc))
|
||||
* **web:** replace manual height hack in notifications infinite scroll ([de1e272](https://github.com/unraid/api/commit/de1e272357264afc0f7f5fdd653c6a865105d710))
|
||||
* **web:** reset infinite scroll when notification filters change ([da6de2c](https://github.com/unraid/api/commit/da6de2ccdb710772a199c8cba8952adc247412db))
|
||||
* **web:** sanitize changelog markup after parsing ([c960292](https://github.com/unraid/api/commit/c96029273283f5970a5029eea1d7f451bbd0071b))
|
||||
* **web:** stop opening notification sidebar to archive tab ([325e75f](https://github.com/unraid/api/commit/325e75f5d444908a2227fbe2e94be9ab5196ad8e))
|
||||
* **web:** theme header differences ([#1085](https://github.com/unraid/api/issues/1085)) ([1ccdd8d](https://github.com/unraid/api/commit/1ccdd8dc71ee5e1e3aacabd113d1cf213ca7c7ae))
|
||||
* **web:** track 'notification seen' state across tabs & page loads ([#1121](https://github.com/unraid/api/issues/1121)) ([64cf6ec](https://github.com/unraid/api/commit/64cf6ecc6aec25cd8edee5659efb09f288bb9908))
|
||||
* **web:** update unread total immediately upon archiving ([#982](https://github.com/unraid/api/issues/982)) ([ff5fd8e](https://github.com/unraid/api/commit/ff5fd8e5eb8eb4803db1265e31b0c1352af20251))
|
||||
|
||||
## [3.11.0](https://github.com/unraid/api/compare/v3.10.1...v3.11.0) (2024-09-11)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
###########################################################
|
||||
# Development/Build Image
|
||||
###########################################################
|
||||
FROM node:18.19.1-bookworm-slim As development
|
||||
FROM node:20-bookworm-slim AS development
|
||||
|
||||
# Install build tools and dependencies
|
||||
RUN apt-get update -y && apt-get install -y \
|
||||
@@ -19,22 +19,18 @@ WORKDIR /app
|
||||
|
||||
# Set app env
|
||||
ENV NODE_ENV=development
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
|
||||
# Setup cache for pkg
|
||||
ENV PKG_CACHE_PATH /app/.pkg-cache
|
||||
RUN mkdir -p ${PKG_CACHE_PATH}
|
||||
# Install pnpm
|
||||
RUN corepack enable && corepack prepare pnpm@8.15.4 --activate && npm i -g npm@latest
|
||||
|
||||
COPY tsconfig.json tsup.config.ts .eslintrc.cjs .npmrc .env.production .env.staging ./
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
|
||||
# Install pkg
|
||||
RUN npm i -g pkg zx
|
||||
COPY tsconfig.json .eslintrc.ts .prettierrc.cjs .npmrc .env.production .env.staging package.json pnpm-lock.yaml .npmrc ./
|
||||
|
||||
# Install deps
|
||||
RUN npm i
|
||||
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
|
||||
|
||||
EXPOSE 4000
|
||||
EXPOSE 3001
|
||||
|
||||
###########################################################
|
||||
# Builder Image
|
||||
@@ -42,6 +38,8 @@ EXPOSE 4000
|
||||
|
||||
FROM development AS builder
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD ["npm", "run", "build-pkg"]
|
||||
CMD ["pnpm", "run", "build-and-pack"]
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
## Installation
|
||||
|
||||
Install the production plugin via the apps tab (search for "my servers") on Unraid 6.9.2 or later.
|
||||
Install the production plugin via the apps tab (search for "Unraid Connect")
|
||||
|
||||
Manual install can be done with the following routes:
|
||||
[production](https://stable.dl.unraid.net/unraid-api/dynamix.unraid.net.plg)
|
||||
[staging](https://preview.dl.unraid.net/unraid-api/dynamix.unraid.net.staging.plg)
|
||||
|
||||
## CLI
|
||||
|
||||
@@ -13,11 +17,11 @@ root@Devon:~# unraid-api
|
||||
|
||||
Unraid API
|
||||
|
||||
Thanks for using the official Unraid API
|
||||
Thanks for using the official Unraid API
|
||||
|
||||
Usage:
|
||||
|
||||
$ unraid-api command <options>
|
||||
$ unraid-api command <options>
|
||||
|
||||
Commands:
|
||||
|
||||
@@ -25,34 +29,48 @@ Commands:
|
||||
|
||||
Options:
|
||||
|
||||
-h, --help Prints this usage guide.
|
||||
-d, --debug Enabled debug mode.
|
||||
-p, --port string Set the graphql port.
|
||||
--environment production/staging/development Set the working environment.
|
||||
--log-level ALL/TRACE/DEBUG/INFO/WARN/ERROR/FATAL/MARK/OFF Set the log level.
|
||||
-h, --help Prints this usage guide.
|
||||
-d, --debug Enabled debug mode.
|
||||
-p, --port string Set the graphql port.
|
||||
--environment production/staging/development Set the working environment.
|
||||
--log-level ALL/TRACE/DEBUG/INFO/WARN/ERROR/FATAL/MARK/OFF Set the log level.
|
||||
|
||||
Copyright © 2022 Lime Technology, Inc.
|
||||
Copyright © 2024 Lime Technology, Inc.
|
||||
|
||||
```
|
||||
|
||||
## Key
|
||||
|
||||
To create and work with Unraid API keys, used for the local API, run the following command to view all available options. These options may change over time.
|
||||
|
||||
```sh
|
||||
unraid-api key --help
|
||||
```
|
||||
|
||||
## Report
|
||||
|
||||
To view the current status of the unraid-api and its connection to mothership, run:
|
||||
```
|
||||
|
||||
```sh
|
||||
unraid-api report
|
||||
```
|
||||
|
||||
To view verbose data (anonymized), run:
|
||||
```
|
||||
|
||||
```sh
|
||||
unraid-api report -v
|
||||
```
|
||||
|
||||
To view non-anonymized verbose data, run:
|
||||
```
|
||||
|
||||
```sh
|
||||
unraid-api report -vv
|
||||
```
|
||||
|
||||
## Secrets
|
||||
|
||||
If you found this file you're likely a developer. If you'd like to know more about the API and when it's available please join [our discord](https://discord.unraid.net/).
|
||||
|
||||
## License
|
||||
Copyright 2019-2022 Lime Technology Inc. All rights reserved.
|
||||
|
||||
Copyright Lime Technology Inc. All rights reserved.
|
||||
|
||||
105
api/codegen.ts
Normal file
105
api/codegen.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import type { CodegenConfig } from '@graphql-codegen/cli';
|
||||
|
||||
const config: CodegenConfig = {
|
||||
overwrite: true,
|
||||
emitLegacyCommonJSImports: false,
|
||||
verbose: true,
|
||||
config: {
|
||||
namingConvention: {
|
||||
typeNames: './fix-array-type.cjs',
|
||||
enumValues: 'change-case#upperCase',
|
||||
useTypeImports: true,
|
||||
},
|
||||
scalars: {
|
||||
DateTime: 'string',
|
||||
Long: 'number',
|
||||
JSON: '{ [key: string]: any }',
|
||||
URL: 'URL',
|
||||
Port: 'number',
|
||||
UUID: 'string',
|
||||
},
|
||||
},
|
||||
generates: {
|
||||
'src/graphql/generated/client/': {
|
||||
documents: './src/graphql/mothership/*.ts',
|
||||
schema: {
|
||||
[process.env.MOTHERSHIP_GRAPHQL_LINK as string]: {
|
||||
headers: {
|
||||
origin: 'https://forums.unraid.net',
|
||||
},
|
||||
},
|
||||
},
|
||||
preset: 'client',
|
||||
presetConfig: {
|
||||
gqlTagName: 'graphql',
|
||||
},
|
||||
config: {
|
||||
useTypeImports: true,
|
||||
withObjectType: true,
|
||||
},
|
||||
plugins: [
|
||||
{ add: { content: '/* eslint-disable */' } },
|
||||
],
|
||||
},
|
||||
// Generate Types for the API Server
|
||||
'src/graphql/generated/api/types.ts': {
|
||||
schema: [
|
||||
'./src/graphql/types.ts',
|
||||
'./src/graphql/schema/types/**/*.graphql',
|
||||
],
|
||||
plugins: [
|
||||
'typescript',
|
||||
'typescript-resolvers',
|
||||
{ add: { content: '/* eslint-disable */' } },
|
||||
],
|
||||
config: {
|
||||
contextType: '@app/graphql/schema/utils#Context',
|
||||
useIndexSignature: true,
|
||||
},
|
||||
},
|
||||
// Generate Operations for any built-in API Server Operations (e.g., report.ts)
|
||||
'src/graphql/generated/api/operations.ts': {
|
||||
documents: './src/graphql/client/api/*.ts',
|
||||
schema: [
|
||||
'./src/graphql/types.ts',
|
||||
'./src/graphql/schema/types/**/*.graphql',
|
||||
],
|
||||
preset: 'import-types',
|
||||
presetConfig: {
|
||||
typesPath: '@app/graphql/generated/api/types',
|
||||
},
|
||||
plugins: [
|
||||
'typescript-validation-schema',
|
||||
'typescript-operations',
|
||||
'typed-document-node',
|
||||
{ add: { content: '/* eslint-disable */' } },
|
||||
],
|
||||
config: {
|
||||
importFrom: '@app/graphql/generated/api/types',
|
||||
strictScalars: false,
|
||||
schema: 'zod',
|
||||
withObjectType: true,
|
||||
},
|
||||
},
|
||||
'src/graphql/generated/client/validators.ts': {
|
||||
schema: {
|
||||
[process.env.MOTHERSHIP_GRAPHQL_LINK as string]: {
|
||||
headers: {
|
||||
origin: 'https://forums.unraid.net',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
'typescript-validation-schema',
|
||||
{ add: { content: '/* eslint-disable */' } },
|
||||
],
|
||||
config: {
|
||||
importFrom: '@app/graphql/generated/client/graphql',
|
||||
strictScalars: false,
|
||||
schema: 'zod',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -1,77 +0,0 @@
|
||||
overwrite: true
|
||||
emitLegacyCommonJSImports: false
|
||||
verbose: true
|
||||
require:
|
||||
- ts-node/register
|
||||
config:
|
||||
namingConvention:
|
||||
typeNames: './fix-array-type.cjs'
|
||||
enumValues: 'change-case#upperCase'
|
||||
useTypeImports: true
|
||||
scalars:
|
||||
DateTime: string
|
||||
Long: number
|
||||
JSON: "{ [key: string]: any }"
|
||||
URL: URL
|
||||
Port: number
|
||||
UUID: string
|
||||
|
||||
generates:
|
||||
src/graphql/generated/client/:
|
||||
documents: './src/graphql/mothership/*.ts'
|
||||
schema:
|
||||
'${MOTHERSHIP_GRAPHQL_LINK}':
|
||||
headers:
|
||||
origin: 'https://forums.unraid.net'
|
||||
preset: client
|
||||
presetConfig:
|
||||
gqlTagName: graphql
|
||||
config:
|
||||
useTypeImports: true
|
||||
withObjectType: true
|
||||
plugins:
|
||||
- add: { content: '/* eslint-disable */' }
|
||||
|
||||
# Generate Types for the API Server
|
||||
src/graphql/generated/api/types.ts:
|
||||
schema:
|
||||
- './src/graphql/types.ts'
|
||||
- './src/graphql/schema/types/**/*.graphql'
|
||||
plugins:
|
||||
- typescript
|
||||
- typescript-resolvers
|
||||
- add: { content: '/* eslint-disable */' }
|
||||
config:
|
||||
contextType: '@app/graphql/schema/utils#Context'
|
||||
useIndexSignature: true
|
||||
# Generate Operations for any built in API Server Operations (ie report.ts)
|
||||
src/graphql/generated/api/operations.ts:
|
||||
documents: './src/graphql/client/api/*.ts'
|
||||
schema:
|
||||
- './src/graphql/types.ts'
|
||||
- './src/graphql/schema/types/**/*.graphql'
|
||||
preset: import-types
|
||||
presetConfig:
|
||||
typesPath: '@app/graphql/generated/api/types'
|
||||
plugins:
|
||||
- typescript-validation-schema
|
||||
- typescript-operations
|
||||
- typed-document-node
|
||||
- add: { content: '/* eslint-disable */' }
|
||||
config:
|
||||
importFrom: '@app/graphql/generated/api/types'
|
||||
strictScalars: false
|
||||
schema: 'zod'
|
||||
withObjectType: true
|
||||
src/graphql/generated/client/validators.ts:
|
||||
schema:
|
||||
'${MOTHERSHIP_GRAPHQL_LINK}':
|
||||
headers:
|
||||
origin: 'https://forums.unraid.net'
|
||||
plugins:
|
||||
- typescript-validation-schema
|
||||
- add: { content: '/* eslint-disable */'}
|
||||
config:
|
||||
importFrom: '@app/graphql/generated/client/graphql'
|
||||
strictScalars: false
|
||||
schema: 'zod'
|
||||
@@ -1,21 +1,20 @@
|
||||
[api]
|
||||
version="3.8.1+d06e215a"
|
||||
version="4.0.1"
|
||||
extraOrigins="https://google.com,https://test.com"
|
||||
[local]
|
||||
[notifier]
|
||||
apikey="unnotify_30994bfaccf839c65bae75f7fa12dd5ee16e69389f754c3b98ed7d5"
|
||||
sandbox="yes"
|
||||
[remote]
|
||||
wanaccess="yes"
|
||||
wanport="8443"
|
||||
upnpEnabled="no"
|
||||
apikey="_______________________BIG_API_KEY_HERE_________________________"
|
||||
localApiKey="_______________________LOCAL_API_KEY_HERE_________________________"
|
||||
email="test@example.com"
|
||||
username="zspearmint"
|
||||
avatar="https://via.placeholder.com/200"
|
||||
regWizTime="1611175408732_0951-1653-3509-FBA155FA23C0"
|
||||
idtoken=""
|
||||
accesstoken=""
|
||||
idtoken=""
|
||||
refreshtoken=""
|
||||
dynamicRemoteAccessType="DISABLED"
|
||||
[upc]
|
||||
apikey="unupc_fab6ff6ffe51040595c6d9ffb63a353ba16cc2ad7d93f813a2e80a5810"
|
||||
ssoSubIds=""
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
{
|
||||
"admin": {
|
||||
"extends": "user",
|
||||
"permissions": [
|
||||
{
|
||||
"resource": "apikey",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "array",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "cpu",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "device",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "device/unassigned",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "disk",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "disk/settings",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "display",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "docker/container",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "docker/network",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "info",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "license-key",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "machine-id",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "memory",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "notifications",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "online",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "os",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "parity-history",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "permission",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "servers",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "service",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "service/emhttpd",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "service/unraid-api",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "services",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "share",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "software-versions",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "unraid-version",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "user",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "var",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "vars",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "vm/domain",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "vm/network",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
}
|
||||
]
|
||||
},
|
||||
"user": {
|
||||
"extends": "guest",
|
||||
"permissions": [
|
||||
{
|
||||
"resource": "apikey",
|
||||
"action": "read:own",
|
||||
"attributes": "*"
|
||||
},
|
||||
{
|
||||
"resource": "permission",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
}
|
||||
]
|
||||
},
|
||||
"guest": {
|
||||
"permissions": [
|
||||
{
|
||||
"resource": "welcome",
|
||||
"action": "read:any",
|
||||
"attributes": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
80
api/dev/dynamix/default.cfg
Normal file
80
api/dev/dynamix/default.cfg
Normal file
@@ -0,0 +1,80 @@
|
||||
[confirm]
|
||||
down="1"
|
||||
stop="1"
|
||||
[display]
|
||||
width=""
|
||||
font=""
|
||||
tty="15"
|
||||
date="%c"
|
||||
time="%R"
|
||||
number=".,"
|
||||
unit="C"
|
||||
scale="-1"
|
||||
resize="0"
|
||||
wwn="0"
|
||||
total="1"
|
||||
banner=""
|
||||
header=""
|
||||
background=""
|
||||
tabs="1"
|
||||
users="Tasks:3"
|
||||
usage="0"
|
||||
text="1"
|
||||
warning="70"
|
||||
critical="90"
|
||||
hot="45"
|
||||
max="55"
|
||||
hotssd="60"
|
||||
maxssd="70"
|
||||
power=""
|
||||
theme="white"
|
||||
locale=""
|
||||
raw=""
|
||||
rtl=""
|
||||
headermetacolor=""
|
||||
headerdescription="yes"
|
||||
showBannerGradient="yes"
|
||||
[parity]
|
||||
mode="0"
|
||||
hour="0 0"
|
||||
dotm="1"
|
||||
month="1"
|
||||
day="0"
|
||||
cron=""
|
||||
write="NOCORRECT"
|
||||
[notify]
|
||||
display="0"
|
||||
life="5"
|
||||
date="d-m-Y"
|
||||
time="H:i"
|
||||
position="top-right"
|
||||
path="/tmp/notifications"
|
||||
system="*/1 * * * *"
|
||||
entity="1"
|
||||
normal="1"
|
||||
warning="1"
|
||||
alert="1"
|
||||
unraid="1"
|
||||
plugin="1"
|
||||
docker_notify="1"
|
||||
language_notify="1"
|
||||
report="1"
|
||||
unraidos=""
|
||||
version=""
|
||||
docker_update=""
|
||||
language_update=""
|
||||
status=""
|
||||
[ssmtp]
|
||||
root=""
|
||||
RcptTo=""
|
||||
SetEmailPriority="True"
|
||||
Subject="Unraid Status: "
|
||||
server="smtp.gmail.com"
|
||||
port="465"
|
||||
UseTLS="YES"
|
||||
UseSTARTTLS="NO"
|
||||
UseTLSCert="NO"
|
||||
TLSCert=""
|
||||
AuthMethod="login"
|
||||
AuthUser=""
|
||||
AuthPass=""
|
||||
@@ -1,5 +1,6 @@
|
||||
[display]
|
||||
date="%c"
|
||||
time="%I:%M %p"
|
||||
number=".,"
|
||||
scale="-1"
|
||||
tabs="1"
|
||||
|
||||
11
api/dev/keys/b5b4aa3d-8e40-4c92-bc40-d50182071886.json
Normal file
11
api/dev/keys/b5b4aa3d-8e40-4c92-bc40-d50182071886.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"createdAt": "2025-01-27T16:22:56.501Z",
|
||||
"description": "API key for Connect user",
|
||||
"id": "b5b4aa3d-8e40-4c92-bc40-d50182071886",
|
||||
"key": "_______________________LOCAL_API_KEY_HERE_________________________",
|
||||
"name": "Connect",
|
||||
"permissions": [],
|
||||
"roles": [
|
||||
"connect"
|
||||
]
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
timestamp=1683971161
|
||||
event=Unraid Parity check
|
||||
subject=Notice [UNRAID] - Parity check finished (0 errors)
|
||||
description=Canceled
|
||||
importance=warning
|
||||
@@ -3,3 +3,4 @@ event=Unraid Parity check
|
||||
subject=Notice [UNRAID] - Parity check finished (0 errors)
|
||||
description=Canceled
|
||||
importance=warning
|
||||
link=/
|
||||
|
||||
1
api/dev/sessions/sess_mockusersession
Normal file
1
api/dev/sessions/sess_mockusersession
Normal file
@@ -0,0 +1 @@
|
||||
unraid_login|i:1736523078;unraid_user|s:4:"root";locale|s:0:"";buildDate|s:8:"20241202";
|
||||
@@ -1,24 +1,24 @@
|
||||
[api]
|
||||
version="3.8.1+d06e215a"
|
||||
version="4.0.1"
|
||||
extraOrigins="https://google.com,https://test.com"
|
||||
[local]
|
||||
[notifier]
|
||||
apikey="unnotify_30994bfaccf839c65bae75f7fa12dd5ee16e69389f754c3b98ed7d5"
|
||||
sandbox="yes"
|
||||
[remote]
|
||||
wanaccess="no"
|
||||
wanaccess="yes"
|
||||
wanport="8443"
|
||||
upnpEnabled="no"
|
||||
apikey="_______________________BIG_API_KEY_HERE_________________________"
|
||||
localApiKey="_______________________LOCAL_API_KEY_HERE_________________________"
|
||||
email="test@example.com"
|
||||
username="zspearmint"
|
||||
avatar="https://via.placeholder.com/200"
|
||||
regWizTime="1611175408732_0951-1653-3509-FBA155FA23C0"
|
||||
idtoken=""
|
||||
accesstoken=""
|
||||
idtoken=""
|
||||
refreshtoken=""
|
||||
dynamicRemoteAccessType="DISABLED"
|
||||
ssoSubIds=""
|
||||
allowedOrigins="/var/run/unraid-notifications.sock, /var/run/unraid-php.sock, /var/run/unraid-cli.sock, http://localhost:8080, https://localhost:4443, https://tower.local:4443, https://192.168.1.150:4443, https://tower:4443, https://192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net:4443, https://85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net:8443, https://10-252-0-1.hash.myunraid.net:4443, https://10-252-1-1.hash.myunraid.net:4443, https://10-253-3-1.hash.myunraid.net:4443, https://10-253-4-1.hash.myunraid.net:4443, https://10-253-5-1.hash.myunraid.net:4443, https://10-100-0-1.hash.myunraid.net:4443, https://10-100-0-2.hash.myunraid.net:4443, https://10-123-1-2.hash.myunraid.net:4443, https://221-123-121-112.hash.myunraid.net:4443, https://google.com, https://test.com, https://connect.myunraid.net, https://connect-staging.myunraid.net, https://dev-my.myunraid.net:4000, https://studio.apollographql.com"
|
||||
dynamicRemoteAccessType="STATIC"
|
||||
[upc]
|
||||
apikey="unupc_fab6ff6ffe51040595c6d9ffb63a353ba16cc2ad7d93f813a2e80a5810"
|
||||
[connectionStatus]
|
||||
minigraph="CONNECTED"
|
||||
minigraph="PRE_INIT"
|
||||
upnpStatus=""
|
||||
|
||||
@@ -1,28 +1,12 @@
|
||||
version: '3.8'
|
||||
|
||||
x-volumes: &volumes
|
||||
x-common: &common
|
||||
volumes:
|
||||
- ./dev:/app/dev
|
||||
- ./src:/app/src
|
||||
- ./patches:/app/patches
|
||||
- ./package.json:/app/package.json
|
||||
- ./package-lock.json:/app/package-lock.json
|
||||
- ./tsconfig.json:/app/tsconfig.json
|
||||
- ./tsup.config.ts:/app/tsup.config.ts
|
||||
- ./vite.config.ts:/app/vite.config.ts
|
||||
- ./dist/:/app/dist/
|
||||
- ./deploy/:/app/deploy/
|
||||
- ./README.md:/app/README.md
|
||||
- ./scripts/:/app/scripts/
|
||||
- ../.git/:/app/.git/
|
||||
- ./.env.production:/app/.env.production
|
||||
- ./.env.staging:/app/.env.staging
|
||||
- ./.env.test:/app/.env.test
|
||||
- ./.env.development:/app/.env.development
|
||||
- ./.pkg-cache:/app/.pkg-cache
|
||||
- ./codegen.yml:/app/codegen.yml
|
||||
- ./fix-array-type.cjs:/app/fix-array-type.cjs
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./:/app
|
||||
- pnpm-store:/pnpm/store
|
||||
- ../libvirt:/libvirt
|
||||
environment:
|
||||
- IS_DOCKER=true
|
||||
- GIT_SHA=${GIT_SHA:-unknown}
|
||||
- IS_TAGGED=${IS_TAGGED:-false}
|
||||
|
||||
services:
|
||||
|
||||
@@ -34,14 +18,10 @@ services:
|
||||
context: .
|
||||
target: development
|
||||
dockerfile: Dockerfile
|
||||
<<: *volumes
|
||||
<<: *common
|
||||
stdin_open: true
|
||||
tty: true
|
||||
entrypoint: /bin/bash
|
||||
environment:
|
||||
- IS_DOCKER=true
|
||||
- GIT_SHA=${GIT_SHA:?err}
|
||||
- IS_TAGGED=${IS_TAGGED}
|
||||
profiles:
|
||||
- builder
|
||||
|
||||
@@ -53,24 +33,23 @@ services:
|
||||
context: .
|
||||
target: development
|
||||
dockerfile: Dockerfile
|
||||
<<: *volumes
|
||||
<<: *common
|
||||
command: npm run start:dev
|
||||
environment:
|
||||
- IS_DOCKER=true
|
||||
- GIT_SHA=${GIT_SHA:?err}
|
||||
- IS_TAGGED=${IS_TAGGED}
|
||||
profiles:
|
||||
- builder
|
||||
|
||||
builder:
|
||||
image: unraid-api:builder
|
||||
environment:
|
||||
- GIT_SHA=${GIT_SHA:?err}
|
||||
- IS_TAGGED=${IS_TAGGED}
|
||||
build:
|
||||
context: .
|
||||
target: builder
|
||||
dockerfile: Dockerfile
|
||||
<<: *volumes
|
||||
<<: *common
|
||||
profiles:
|
||||
- builder
|
||||
- builder
|
||||
|
||||
volumes:
|
||||
pnpm-store:
|
||||
name: "pnpm-store"
|
||||
pnpm-cache:
|
||||
name: "pnpm-cache"
|
||||
116
api/docs/developer/development.md
Normal file
116
api/docs/developer/development.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# Development
|
||||
|
||||
## Installation
|
||||
|
||||
Manual install can be done with the following routes:
|
||||
[production](https://stable.dl.unraid.net/unraid-api/dynamix.unraid.net.plg)
|
||||
[staging](https://preview.dl.unraid.net/unraid-api/dynamix.unraid.net.staging.plg)
|
||||
|
||||
## Connecting to the API
|
||||
|
||||
### HTTP
|
||||
|
||||
This can be accessed by default via `http://tower.local/graphql`.
|
||||
|
||||
See <https://graphql.org/learn/serving-over-http/#http-methods-headers-and-body>
|
||||
|
||||
## Building in Docker
|
||||
|
||||
To get a development environment for testing start by running this docker command:
|
||||
|
||||
`npm run build:docker`
|
||||
`npm run start:ddev`
|
||||
|
||||
which will give you an interactive shell inside of the newly build linux container.
|
||||
|
||||
To automatically build the plugin run the command below:
|
||||
|
||||
`npm run build:docker`
|
||||
|
||||
The builder command will build the plugin into deploy/release, and the interactive plugin lets you build the plugin or install node modules how you like.
|
||||
|
||||
## Logs
|
||||
|
||||
Logging can be configured via environment variables.
|
||||
|
||||
Log levels can be set when the api starts via `LOG_LEVEL=all/trace/debug/info/warn/error/fatal/mark/off`.
|
||||
|
||||
Additional detail for the log entry can be added with `LOG_CONTEXT=true` (warning, generates a lot of data).
|
||||
|
||||
By default, logs will be sent to syslog. Or you can set `LOG_TRANSPORT=file` to have logs saved in `/var/log/unraid-api/stdout.log`. Or enable debug mode to view logs inline.
|
||||
|
||||
Examples:
|
||||
|
||||
- `unraid-api start`
|
||||
- `LOG_LEVEL=debug unraid-api start --debug`
|
||||
- `LOG_LEVEL=trace LOG_CONTEXT=true LOG_TRANSPORT=file unraid-api start`
|
||||
|
||||
## Viewing data sent to mothership
|
||||
|
||||
If the environment variable `LOG_MOTHERSHIP_MESSAGES=true` exists, any data the unraid-api sends to mothership will be saved in clear text here: `/var/log/unraid-api/relay-messages.log`
|
||||
|
||||
Examples:
|
||||
|
||||
- `LOG_MOTHERSHIP_MESSAGES=true unraid-api start`
|
||||
- `LOG_MOTHERSHIP_MESSAGES=true LOG_LEVEL=debug unraid-api start --debug`
|
||||
|
||||
## Debug Logging
|
||||
|
||||
To view debug logs, change the log level when starting the API. Then type unraid-api logs to trail the logs.
|
||||
Examples:
|
||||
|
||||
- `LOG_LEVEL=debug unraid-api start`
|
||||
- `unraid-api logs`
|
||||
|
||||
## Switching between staging and production environments
|
||||
|
||||
1. Stop the api: `unraid-api stop`
|
||||
2. Switch environments: `unraid-api switch-env`
|
||||
3. Start the api: `unraid-api start`
|
||||
4. Confirm the environment: `unraid-api report`
|
||||
|
||||
## Playground
|
||||
|
||||
The playground can be access via `http://tower.local/graphql` while in debug mode.
|
||||
To get your API key open a terminal on your server and run `cat /boot/config/plugins/dynamix.my.servers/myservers.cfg | grep apikey=\"unraid | cut -d '"' -f2`. Add that API key in the "HTTP headers" panel of the playground.
|
||||
|
||||
```json
|
||||
{
|
||||
"x-api-key": "__REPLACE_ME_WITH_API_KEY__"
|
||||
}
|
||||
```
|
||||
|
||||
Next add the query you want to run and hit the play icon.
|
||||
|
||||
```gql
|
||||
query welcome {
|
||||
welcome {
|
||||
message
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You should get something like this back.
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"welcome": {
|
||||
"message": "Welcome root to this Unraid 6.10.0 server"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Click the "Schema" and "Docs" button on the right side of the playground to learn more.
|
||||
|
||||
## Create a new release
|
||||
|
||||
To create a new version run `npm run release` and then run **ONLY** the `git push` section of the commands it returns.
|
||||
To create a new prerelease run `npm run release -- --prerelease alpha`.
|
||||
|
||||
Pushing to this repo will cause an automatic "rolling" release to be built which can be accessed via the page for the associated Github action run.
|
||||
|
||||
## Using a custom version (e.g. testing a new release)
|
||||
|
||||
Find the Pull Request you'd like to install, and a link will be present as a comment to install a PR-specific version.
|
||||
82
api/docs/developer/repo-organization.md
Normal file
82
api/docs/developer/repo-organization.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Repository Organization
|
||||
|
||||
This document describes the high-level architecture of the Unraid API repository.
|
||||
|
||||
## Overview
|
||||
|
||||
The repository consists of:
|
||||
|
||||
- API Server (NestJS)
|
||||
- Redux Store
|
||||
- Core Modules
|
||||
- Tests
|
||||
|
||||
## API Server Architecture
|
||||
|
||||
The API server is built with NestJS and provides the core functionality for interacting with Unraid systems.
|
||||
|
||||
### Key Components:
|
||||
|
||||
- `src/unraid-api/` - Core NestJS implementation
|
||||
- `src/core/` - Legacy business logic and utilities
|
||||
- `src/store/` - Redux store and state management
|
||||
- `src/common/` - Shared utilities and types
|
||||
|
||||
## Redux Store
|
||||
|
||||
The store manages application state through several modules:
|
||||
|
||||
### Store Modules
|
||||
|
||||
- `config` - User settings, authentication, and API configuration
|
||||
- `emhttp` - Unraid system and array state
|
||||
- `registration` - License management
|
||||
- `cache` - Application caching
|
||||
- `docker` - Container management
|
||||
- `upnp` - UPnP functionality
|
||||
- `dynamix` - Plugin state
|
||||
- `minigraph` - Mothership connectivity
|
||||
- `notifications` - System notifications
|
||||
|
||||
### Store Listeners
|
||||
|
||||
Key listeners that handle side effects:
|
||||
|
||||
- Array state changes
|
||||
- Configuration updates
|
||||
- Remote access changes
|
||||
- Server state updates
|
||||
- UPnP changes
|
||||
- WAN access changes
|
||||
|
||||
### Store Synchronization
|
||||
|
||||
The store syncs data in two ways:
|
||||
|
||||
- Flash Storage - Persistent configuration
|
||||
- Memory Storage - Runtime state
|
||||
|
||||
## Project Structure
|
||||
|
||||
The repository is organized into several packages:
|
||||
|
||||
- `api/` - NestJS API server
|
||||
- `plugin/` - Unraid plugin package
|
||||
- `web/` - Frontend application
|
||||
- `unraid-ui/` - Shared UI components
|
||||
|
||||
## Development Flow
|
||||
|
||||
New development should focus on the NestJS implementation in `src/unraid-api/`:
|
||||
|
||||
1. Create new features in `src/unraid-api/` using NestJS patterns
|
||||
2. Use dependency injection and NestJS modules
|
||||
3. Legacy code in `src/core/` should be gradually migrated
|
||||
4. State management still uses Redux store when needed
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Follow NestJS architectural patterns
|
||||
2. Use TypeScript decorators and strong typing
|
||||
3. Implement proper dependency injection
|
||||
4. Write unit tests for new services
|
||||
@@ -1,34 +0,0 @@
|
||||
# How to enable introspection and view possible API endpoints for the Unraid API
|
||||
|
||||
1. Install the API on your machine
|
||||
2. Stop the running api with `unraid-api stop`
|
||||
3. Enable an allowed origin for Apollo Studio:
|
||||
|
||||
- Edit the file at `/boot/config/plugins/dynamix.my.servers/myservers.cfg
|
||||
- Add the line `extraOrigins="studio.apollographql.com"` inside of the `[api]` block
|
||||
|
||||
```ini
|
||||
[api]
|
||||
...
|
||||
extraOrigins="studio.apollographql.com"
|
||||
[local]
|
||||
...rest
|
||||
```
|
||||
|
||||
- Also copy out the `[upc] -> apikey` setting, it should look something like `unupc_52e45431703b1e79cef709bfaf7ddc469bafc12e091b7c9bca0f6e96dc`
|
||||
|
||||
4. Enable introspection
|
||||
|
||||
```sh
|
||||
INTROSPECTION=true LOG_LEVEL=trace LOG_TYPE=pretty unraid-api start --debug
|
||||
```
|
||||
|
||||
- If you run this command and it says the Unraid API is already started, run `unraid-api stop` before trying it again.
|
||||
|
||||
5. Use introspection to your server with Apollo Sandbox:
|
||||
- Navigate your *Chrome* browser to [Apollo Sandbox](https://studio.apollographql.com/sandbox/explorer/)
|
||||
- Click the settings icon in the top right corner and set the URL to your servers URL + /graphql. For example a server URL might be: `https://192-168-1-3.277ace5dd0892eacd83f517b39fb3d1dd32078b5.myunraid.net:8443/graphql` or `http://tower.local/graphql`
|
||||
- Also set the API key you copied earlier in the header section. Set the key as `x-api-key` and the value to the API key you copied in Step 2.
|
||||

|
||||
|
||||
6. Now that your server should be connected, you should see the schema populate. To perform queries, click the plus icon on the field on the left side to add them to a query and then click to run icon on the right.
|
||||
@@ -1,229 +0,0 @@
|
||||
# Development
|
||||
|
||||
## Installation
|
||||
|
||||
Install the [production](https://unraid-dl.sfo2.digitaloceanspaces.com/unraid-api/dynamix.unraid.net.plg) or [staging](https://unraid-dl.sfo2.digitaloceanspaces.com/unraid-api/dynamix.unraid.net.staging.plg) plugin on Unraid 6.9.0-rc1 or later (6.9.2 or higher recommended).
|
||||
|
||||
## Connecting to the API
|
||||
|
||||
### HTTP
|
||||
|
||||
This can be accessed by default via `http://tower.local/graphql`.
|
||||
|
||||
See <https://graphql.org/learn/serving-over-http/#http-methods-headers-and-body>
|
||||
|
||||
### WS
|
||||
|
||||
If you're using the ApolloClient please see <https://github.com/apollographql/subscriptions-transport-ws#full-websocket-transport> otherwise see <https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md>
|
||||
|
||||
<br>
|
||||
<hr>
|
||||
<br>
|
||||
|
||||
## Building in Docker
|
||||
|
||||
To get a development environment for testing start by running this docker command:
|
||||
|
||||
``docker compose run build-interactive``
|
||||
|
||||
which will give you an interactive shell inside of the newly build linux container.
|
||||
|
||||
To automatically build the plugin run the command below:
|
||||
|
||||
``docker compose run builder``
|
||||
|
||||
The builder command will build the plugin into deploy/release, and the interactive plugin lets you build the plugin or install node modules how you like.
|
||||
|
||||
## Logs
|
||||
|
||||
Logging can be configured via environment variables.
|
||||
|
||||
Log levels can be set when the api starts via `LOG_LEVEL=all/trace/debug/info/warn/error/fatal/mark/off`.
|
||||
|
||||
Additional detail for the log entry can be added with `LOG_CONTEXT=true` (warning, generates a lot of data).
|
||||
|
||||
By default, logs will be sent to syslog. Or you can set `LOG_TRANSPORT=file` to have logs saved in `/var/log/unraid-api/stdout.log`. Or enable debug mode to view logs inline.
|
||||
|
||||
Examples:
|
||||
|
||||
* `unraid-api start`
|
||||
* `LOG_LEVEL=debug unraid-api start --debug`
|
||||
* `LOG_LEVEL=trace LOG_CONTEXT=true LOG_TRANSPORT=file unraid-api start`
|
||||
|
||||
Log levels can be increased without restarting the api by issuing this command:
|
||||
|
||||
```
|
||||
kill -s SIGUSR2 `pidof unraid-api`
|
||||
```
|
||||
|
||||
and decreased via:
|
||||
|
||||
```
|
||||
kill -s SIGUSR1 `pidof unraid-api`
|
||||
```
|
||||
|
||||
<br>
|
||||
<hr>
|
||||
<br>
|
||||
|
||||
## Viewing data sent to mothership
|
||||
|
||||
If the environment variable `LOG_MOTHERSHIP_MESSAGES=true` exists, any data the unraid-api sends to mothership will be saved in clear text here: `/var/log/unraid-api/relay-messages.log`
|
||||
|
||||
Examples:
|
||||
|
||||
* `LOG_MOTHERSHIP_MESSAGES=true unraid-api start`
|
||||
* `LOG_MOTHERSHIP_MESSAGES=true LOG_LEVEL=debug unraid-api start --debug`
|
||||
<br>
|
||||
|
||||
<hr>
|
||||
<br>
|
||||
|
||||
## Debug mode
|
||||
|
||||
Debug mode can be enabled with the `-d` or `--debug` flag.
|
||||
This will enable the graphql playground and prevent the application starting as a daemon. Logs will be shown inline rather than saved to a file.
|
||||
|
||||
Examples:
|
||||
|
||||
* `unraid-api start --debug`
|
||||
* `LOG_LEVEL=debug unraid-api start --debug`
|
||||
|
||||
<br>
|
||||
<hr>
|
||||
<br>
|
||||
|
||||
## Crash API On Demand
|
||||
|
||||
The `PLEASE_SEGFAULT_FOR_ME` env var can be to used to make the api crash after 30 seconds:
|
||||
|
||||
Examples:
|
||||
|
||||
* `PLEASE_SEGFAULT_FOR_ME=true LOG_LEVEL=debug unraid-api start --debug`
|
||||
* `PLEASE_SEGFAULT_FOR_ME=true unraid-api start`
|
||||
|
||||
The crash log will be stored here:
|
||||
|
||||
* `/var/log/unraid-api/crash.log`
|
||||
* `/var/log/unraid-api/crash.json`
|
||||
|
||||
`crash.json` just includes the most recent crash, while the reports get appended to `crash.log`.
|
||||
|
||||
<br>
|
||||
<hr>
|
||||
<br>
|
||||
|
||||
## Switching between staging and production environments
|
||||
|
||||
1. Stop the api: `unraid-api stop`
|
||||
2. Switch environments: `unraid-api switch-env`
|
||||
3. Start the api: `unraid-api start`
|
||||
4. Confirm the environment: `unraid-api report`
|
||||
|
||||
<br>
|
||||
<hr>
|
||||
<br>
|
||||
|
||||
## Playground
|
||||
|
||||
The playground can be access via `http://tower.local/graphql` while in debug mode.
|
||||
To get your API key open a terminal on your server and run `cat /boot/config/plugins/dynamix.my.servers/myservers.cfg | grep apikey=\"unraid | cut -d '"' -f2`. Add that API key in the "HTTP headers" panel of the playground.
|
||||
|
||||
```json
|
||||
{
|
||||
"x-api-key":"__REPLACE_ME_WITH_API_KEY__"
|
||||
}
|
||||
```
|
||||
|
||||
Next add the query you want to run and hit the play icon.
|
||||
|
||||
```gql
|
||||
query welcome {
|
||||
welcome {
|
||||
message
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You should get something like this back.
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"welcome": {
|
||||
"message": "Welcome root to this Unraid 6.10.0 server"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Click the "Schema" and "Docs" button on the right side of the playground to learn more.
|
||||
|
||||
For exploring the schema visually I'd suggest using [Voyager](https://apis.guru/graphql-voyager/) (click Change Schema -> Introspection, then copy/paste the introspection query into the local Graph Playground, and copy/paste the results back into Voyager).
|
||||
|
||||
<br>
|
||||
<hr>
|
||||
<br>
|
||||
|
||||
## Running this locally
|
||||
|
||||
```bash
|
||||
MOTHERSHIP_RELAY_WS_LINK=ws://localhost:8000 \ # Switch to local copy of mothership
|
||||
PATHS_UNRAID_DATA=$(pwd)/dev/data \ # Where we store plugin data (e.g. permissions.json)
|
||||
PATHS_STATES=$(pwd)/dev/states \ # Where .ini files live (e.g. vars.ini)
|
||||
PATHS_DYNAMIX_BASE=$(pwd)/dev/dynamix \ # Dynamix's data directory
|
||||
PATHS_DYNAMIX_CONFIG=$(pwd)/dev/dynamix/dynamix.cfg \ # Dynamix's config file
|
||||
PATHS_MY_SERVERS_CONFIG=$(pwd)/dev/Unraid.net/myservers.cfg \ # My servers config file
|
||||
PORT=8500 \ # What port unraid-api should start on (e.g. /var/run/unraid-api.sock or 8000)
|
||||
node dist/cli.js --debug # Enable debug logging
|
||||
```
|
||||
|
||||
<br>
|
||||
<hr>
|
||||
<br>
|
||||
|
||||
## Create a new release
|
||||
|
||||
To create a new version run `npm run release` and then run **ONLY** the `git push` section of the commands it returns.
|
||||
To create a new prerelease run `npm run release -- --prerelease alpha`.
|
||||
|
||||
Pushing to this repo will cause an automatic "rolling" release to be built which can be accessed via the page for the associated Github action run.
|
||||
|
||||
<br>
|
||||
<hr>
|
||||
<br>
|
||||
|
||||
## Using a custom version (e.g. testing a new release)
|
||||
|
||||
1. Install the staging or production plugin (links in the Installation section at the top of this file)
|
||||
2. Download or build the api tgz file you want
|
||||
|
||||
* Download from [the releases page](https://github.com/unraid/api/releases)
|
||||
* Build it on your local machine (``docker compose run builder``) and copy from the `deploy/release` folder
|
||||
|
||||
3. Copy the file to `/boot/config/plugins/dynamix.my.servers/unraid-api.tgz`.
|
||||
4. Install the new api: `/etc/rc.d/rc.unraid-api (install / _install)`
|
||||
|
||||
* `_install` will no start the plugin for you after running, so you can make sure you launch in dev mode
|
||||
* `install` will start the plugin after install
|
||||
5. Start the api: `unraid-api start`
|
||||
6. Confirm the version: `unraid-api report`
|
||||
|
||||
## Cloning Secrets from AWS
|
||||
|
||||
1. Go here to create security credentials for your user [S3 Creds](https://us-east-1.console.aws.amazon.com/iam/home?region=us-east-1&skipRegion=true#/security_credentials)
|
||||
2. Export your AWS secrets OR run `aws configure` to setup your environment
|
||||
|
||||
```sh
|
||||
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
|
||||
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
|
||||
export AWS_DEFAULT_REGION=us-east-1
|
||||
|
||||
```
|
||||
|
||||
3. Set variables for staging and production to the ARN of the secret you would like to clone:
|
||||
|
||||
* `STAGING_SECRET_ID`
|
||||
* `PRODUCTION_SECRET_ID`
|
||||
|
||||
4. Run `scripts/copy-env-from-aws.sh` to pull down the secrets into their respective files
|
||||
4
api/docs/public/_category_.json
Normal file
4
api/docs/public/_category_.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"label": "Unraid API",
|
||||
"position": 4
|
||||
}
|
||||
162
api/docs/public/cli.md
Normal file
162
api/docs/public/cli.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# CLI Commands
|
||||
|
||||
### Start
|
||||
|
||||
```bash
|
||||
unraid-api start [--log-level <level>]
|
||||
```
|
||||
|
||||
Starts the Unraid API service.
|
||||
|
||||
Options:
|
||||
- `--log-level`: Set logging level (trace|debug|info|warn|error)
|
||||
|
||||
### Stop
|
||||
|
||||
```bash
|
||||
unraid-api stop [--delete]
|
||||
```
|
||||
|
||||
Stops the Unraid API service.
|
||||
|
||||
- `--delete`: Optional. Delete the PM2 home directory
|
||||
|
||||
### Restart
|
||||
|
||||
```bash
|
||||
unraid-api restart
|
||||
```
|
||||
|
||||
Restarts the Unraid API service.
|
||||
|
||||
### Logs
|
||||
|
||||
```bash
|
||||
unraid-api logs [-l <lines>]
|
||||
```
|
||||
|
||||
View the API logs.
|
||||
|
||||
- `-l, --lines`: Optional. Number of lines to tail (default: 100)
|
||||
|
||||
## Configuration Commands
|
||||
|
||||
### Config
|
||||
|
||||
```bash
|
||||
unraid-api config
|
||||
```
|
||||
|
||||
Displays current configuration values.
|
||||
|
||||
### Switch Environment
|
||||
|
||||
```bash
|
||||
unraid-api switch-env [-e <environment>]
|
||||
```
|
||||
|
||||
Switch between production and staging environments.
|
||||
|
||||
- `-e, --environment`: Optional. Target environment (production|staging)
|
||||
|
||||
### Developer Mode
|
||||
|
||||
```bash
|
||||
unraid-api developer
|
||||
```
|
||||
|
||||
Configure developer features for the API (e.g., GraphQL sandbox).
|
||||
|
||||
## API Key Management
|
||||
|
||||
### API Key Commands
|
||||
|
||||
```bash
|
||||
unraid-api apikey [options]
|
||||
```
|
||||
|
||||
Create and manage API keys.
|
||||
|
||||
Options:
|
||||
|
||||
- `--name <name>`: Name of the key
|
||||
- `--create`: Create a new key
|
||||
- `-r, --roles <roles>`: Comma-separated list of roles
|
||||
- `-p, --permissions <permissions>`: Comma-separated list of permissions
|
||||
- `-d, --description <description>`: Description for the key
|
||||
|
||||
## SSO (Single Sign-On) Management
|
||||
|
||||
### SSO Base Command
|
||||
|
||||
```bash
|
||||
unraid-api sso
|
||||
```
|
||||
|
||||
#### Add SSO User
|
||||
|
||||
```bash
|
||||
unraid-api sso add-user
|
||||
# or
|
||||
unraid-api sso add
|
||||
# or
|
||||
unraid-api sso a
|
||||
```
|
||||
|
||||
Add a new user for SSO authentication.
|
||||
|
||||
#### Remove SSO User
|
||||
|
||||
```bash
|
||||
unraid-api sso remove-user
|
||||
# or
|
||||
unraid-api sso remove
|
||||
# or
|
||||
unraid-api sso r
|
||||
```
|
||||
|
||||
Remove a user (or all users) from SSO.
|
||||
|
||||
#### List SSO Users
|
||||
|
||||
```bash
|
||||
unraid-api sso list-users
|
||||
# or
|
||||
unraid-api sso list
|
||||
# or
|
||||
unraid-api sso l
|
||||
```
|
||||
|
||||
List all configured SSO users.
|
||||
|
||||
#### Validate SSO Token
|
||||
|
||||
```bash
|
||||
unraid-api sso validate-token <token>
|
||||
# or
|
||||
unraid-api sso validate
|
||||
# or
|
||||
unraid-api sso v
|
||||
```
|
||||
|
||||
Validates an SSO token and returns its status.
|
||||
|
||||
## Report Generation
|
||||
|
||||
### Generate Report
|
||||
|
||||
```bash
|
||||
unraid-api report [-r] [-j]
|
||||
```
|
||||
|
||||
Generate a system report.
|
||||
|
||||
- `-r, --raw`: Display raw command output
|
||||
- `-j, --json`: Display output in JSON format
|
||||
|
||||
## Notes
|
||||
|
||||
1. Most commands require appropriate permissions to modify system state
|
||||
2. Some commands require the API to be running or stopped
|
||||
3. Store API keys securely as they provide system access
|
||||
4. SSO configuration changes may require a service restart
|
||||
202
api/docs/public/how-to-use-the-api.md
Normal file
202
api/docs/public/how-to-use-the-api.md
Normal file
@@ -0,0 +1,202 @@
|
||||
# Using the Unraid API
|
||||
|
||||
The Unraid API provides a GraphQL interface that allows you to interact with your Unraid server. This guide will help you get started with exploring and using the API.
|
||||
|
||||
## Enabling the GraphQL Sandbox
|
||||
|
||||
1. First, enable developer mode using the CLI:
|
||||
|
||||
```bash
|
||||
unraid-api developer
|
||||
```
|
||||
|
||||
2. Follow the prompts to enable the sandbox. This will allow you to access the Apollo Sandbox interface.
|
||||
|
||||
3. Access the GraphQL playground by navigating to:
|
||||
|
||||
```txt
|
||||
http://YOUR_SERVER_IP/graphql
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
Most queries and mutations require authentication. You can authenticate using either:
|
||||
|
||||
1. API Keys
|
||||
2. Cookies (default method when signed into the WebGUI)
|
||||
|
||||
### Creating an API Key
|
||||
|
||||
Use the CLI to create an API key:
|
||||
|
||||
```bash
|
||||
unraid-api apikey --create
|
||||
```
|
||||
|
||||
Follow the prompts to set:
|
||||
|
||||
- Name
|
||||
- Description
|
||||
- Roles
|
||||
- Permissions
|
||||
|
||||
The generated API key should be included in your GraphQL requests as a header:
|
||||
|
||||
```json
|
||||
{
|
||||
"x-api-key": "YOUR_API_KEY"
|
||||
}
|
||||
```
|
||||
|
||||
## Available Schemas
|
||||
|
||||
The API provides access to various aspects of your Unraid server:
|
||||
|
||||
### System Information
|
||||
|
||||
- Query system details including CPU, memory, and OS information
|
||||
- Monitor system status and health
|
||||
- Access baseboard and hardware information
|
||||
|
||||
### Array Management
|
||||
|
||||
- Query array status and configuration
|
||||
- Manage array operations (start/stop)
|
||||
- Monitor disk status and health
|
||||
- Perform parity checks
|
||||
|
||||
### Docker Management
|
||||
|
||||
- List and manage Docker containers
|
||||
- Monitor container status
|
||||
- Manage Docker networks
|
||||
|
||||
### Remote Access
|
||||
|
||||
- Configure and manage remote access settings
|
||||
- Handle SSO configuration
|
||||
- Manage allowed origins
|
||||
|
||||
### Example Queries
|
||||
|
||||
1. Check System Status:
|
||||
|
||||
```graphql
|
||||
query {
|
||||
info {
|
||||
os {
|
||||
platform
|
||||
distro
|
||||
release
|
||||
uptime
|
||||
}
|
||||
cpu {
|
||||
manufacturer
|
||||
brand
|
||||
cores
|
||||
threads
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Monitor Array Status:
|
||||
|
||||
```graphql
|
||||
query {
|
||||
array {
|
||||
state
|
||||
capacity {
|
||||
disks {
|
||||
free
|
||||
used
|
||||
total
|
||||
}
|
||||
}
|
||||
disks {
|
||||
name
|
||||
size
|
||||
status
|
||||
temp
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. List Docker Containers:
|
||||
|
||||
```graphql
|
||||
query {
|
||||
dockerContainers {
|
||||
id
|
||||
names
|
||||
state
|
||||
status
|
||||
autoStart
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Schema Types
|
||||
|
||||
The API includes several core types:
|
||||
|
||||
### Base Types
|
||||
|
||||
- `Node`: Interface for objects with unique IDs - please see [Object Identification](https://graphql.org/learn/global-object-identification/)
|
||||
- `JSON`: For complex JSON data
|
||||
- `DateTime`: For timestamp values
|
||||
- `Long`: For 64-bit integers
|
||||
|
||||
### Resource Types
|
||||
|
||||
- `Array`: Array and disk management
|
||||
- `Docker`: Container and network management
|
||||
- `Info`: System information
|
||||
- `Config`: Server configuration
|
||||
- `Connect`: Remote access settings
|
||||
|
||||
### Role-Based Access
|
||||
|
||||
Available roles:
|
||||
|
||||
- `admin`: Full access
|
||||
- `connect`: Remote access features
|
||||
- `guest`: Limited read access
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Use the Apollo Sandbox to explore the schema and test queries
|
||||
2. Start with small queries and gradually add fields as needed
|
||||
3. Monitor your query complexity to maintain performance
|
||||
4. Use appropriate roles and permissions for your API keys
|
||||
5. Keep your API keys secure and rotate them periodically
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
The API implements rate limiting to prevent abuse. Ensure your applications handle rate limit responses appropriately.
|
||||
|
||||
## Error Handling
|
||||
|
||||
The API returns standard GraphQL errors in the following format:
|
||||
|
||||
```json
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"message": "Error description",
|
||||
"locations": [...],
|
||||
"path": [...]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- Use the Apollo Sandbox's schema explorer to browse all available types and fields
|
||||
- Check the documentation tab in Apollo Sandbox for detailed field descriptions
|
||||
- Monitor the API's health using `unraid-api status`
|
||||
- Generate reports using `unraid-api report` for troubleshooting
|
||||
|
||||
For more information about specific commands and configuration options, refer to the CLI documentation or run `unraid-api --help`.
|
||||
37
api/docs/public/index.md
Normal file
37
api/docs/public/index.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Unraid API
|
||||
|
||||
The Unraid API provides a GraphQL interface for programmatic interaction with your Unraid server. It enables automation, monitoring, and integration capabilities.
|
||||
|
||||
## Current Availability
|
||||
|
||||
The API is available through the Unraid Connect Plugin:
|
||||
|
||||
1. Install Unraid Connect Plugin from Apps
|
||||
2. [Configure the plugin](./how-to-use-the-api.md#enabling-the-graphql-sandbox)
|
||||
3. Access API functionality through the [GraphQL Sandbox](./how-to-use-the-api.md#accessing-the-graphql-sandbox)
|
||||
|
||||
## Future Availability
|
||||
|
||||
The API will be integrated directly into the Unraid operating system in an upcoming OS release. This integration will:
|
||||
|
||||
- Make the API a core part of the Unraid system
|
||||
- Remove the need for separate plugin installation
|
||||
- Enable deeper system integration capabilities
|
||||
|
||||
## Documentation Sections
|
||||
|
||||
- [CLI Commands](./cli.md) - Reference for all available command-line interface commands
|
||||
- [Using the Unraid API](./how-to-use-the-api.md) - Comprehensive guide on using the GraphQL API
|
||||
- [Upcoming Features](./upcoming-features.md) - Roadmap of planned features and improvements
|
||||
|
||||
## Key Features
|
||||
|
||||
The API provides:
|
||||
|
||||
- GraphQL Interface: Modern, flexible API with strong typing
|
||||
- Authentication: Secure access via API keys or session cookies
|
||||
- Comprehensive Coverage: Access to system information, array management, and Docker operations
|
||||
- Developer Tools: Built-in GraphQL sandbox for testing
|
||||
- Role-Based Access: Granular permission control
|
||||
|
||||
For detailed usage instructions, see [CLI Commands](./cli.md).
|
||||
71
api/docs/public/upcoming-features.md
Normal file
71
api/docs/public/upcoming-features.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Upcoming Features
|
||||
|
||||
Note: This roadmap outlines planned features and improvements for the Unraid API. Features and timelines may change based on development priorities and community feedback.
|
||||
|
||||
## Core Infrastructure
|
||||
|
||||
| Feature | Status | Tag |
|
||||
|---------|--------|-----|
|
||||
| API Development Environment Improvements | Done | v4.0.0 |
|
||||
| Include API in Unraid OS | Planned (Q1 2025) | - |
|
||||
| Make API Open Source | Planned (Q1 2025) | - |
|
||||
| Separate API from Connect Plugin | Planned (Q2 2025) | - |
|
||||
| Developer Tools for Plugins | Planned (Q2 2025) | - |
|
||||
|
||||
## Security & Authentication
|
||||
|
||||
| Feature | Status | Tag |
|
||||
|---------|--------|-----|
|
||||
| Permissions System Rewrite | Done | v4.0.0 |
|
||||
| User Interface Component Library | In Progress | - |
|
||||
|
||||
## User Interface Improvements
|
||||
|
||||
| Feature | Status | Tag |
|
||||
|---------|--------|-----|
|
||||
| New Settings Pages | Planned (Q2 2025) | - |
|
||||
| Custom Theme Creator | Planned (Q2-Q3 2025) | - |
|
||||
| New Connect Settings Interface | Planned (Q1 2025) | - |
|
||||
|
||||
## Array Management
|
||||
|
||||
| Feature | Status | Tag |
|
||||
|---------|--------|-----|
|
||||
| Array Status Monitoring | Done | v4.0.0 |
|
||||
| Storage Pool Creation Interface | Planned (Q2 2025) | - |
|
||||
| Storage Pool Status Interface | Planned (Q2 2025) | - |
|
||||
|
||||
## Docker Integration
|
||||
|
||||
| Feature | Status | Tag |
|
||||
|---------|--------|-----|
|
||||
| Docker Container Status Monitoring | Done | v4.0.0 |
|
||||
| New Docker Status Interface Design | Planned (Q3 2025) | - |
|
||||
| New Docker Status Interface | Planned (Q3 2025) | - |
|
||||
| Docker Container Setup Interface | Planned (Q3 2025) | - |
|
||||
| Docker Compose Support | Planned | - |
|
||||
|
||||
## Share Management
|
||||
|
||||
| Feature | Status | Tag |
|
||||
|---------|--------|-----|
|
||||
| Array/Cache Share Status Monitoring | Done | v4.0.0 |
|
||||
| Storage Share Creation & Settings | Planned | - |
|
||||
| Storage Share Management Interface | Planned | - |
|
||||
|
||||
## Plugin System
|
||||
|
||||
| Feature | Status | Tag |
|
||||
|---------|--------|-----|
|
||||
| New Plugins Interface | Planned (Q3 2025) | - |
|
||||
| Plugin Management Interface | Planned | - |
|
||||
| Plugin Development Tools | Planned | - |
|
||||
|
||||
## Notifications
|
||||
|
||||
| Feature | Status | Tag |
|
||||
|---------|--------|-----|
|
||||
| Notifications System | Done | v4.0.0 |
|
||||
| Notifications Interface | Done | v4.0.0 |
|
||||
|
||||
Features marked as "Done" are available in current releases. The tag column shows the version where a feature was first introduced.
|
||||
19
api/ecosystem.config.json
Normal file
19
api/ecosystem.config.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/pm2-ecosystem",
|
||||
"apps": [
|
||||
{
|
||||
"name": "unraid-api",
|
||||
"script": "./dist/main.js",
|
||||
"cwd": "/usr/local/unraid-api",
|
||||
"exec_mode": "fork",
|
||||
"wait_ready": true,
|
||||
"listen_timeout": 15000,
|
||||
"max_restarts": 10,
|
||||
"min_uptime": 10000,
|
||||
"watch": false,
|
||||
"ignore_watch": ["node_modules", "src", ".env.*", "myservers.cfg"],
|
||||
"log_file": "/var/log/graphql-api.log",
|
||||
"kill_timeout": 10000
|
||||
}
|
||||
]
|
||||
}
|
||||
20
api/justfile
Normal file
20
api/justfile
Normal file
@@ -0,0 +1,20 @@
|
||||
set fallback
|
||||
|
||||
default:
|
||||
@just --list --justfile {{justfile()}} --list-heading $'\nAPI project recipes:\n'
|
||||
@just list-commands
|
||||
|
||||
setup:
|
||||
pnpm install
|
||||
pnpm run container:build
|
||||
|
||||
# builds js files that can run on an unraid server
|
||||
@build:
|
||||
pnpm run build
|
||||
|
||||
# deploys to an unraid server
|
||||
@deploy:
|
||||
./scripts/deploy-dev.sh
|
||||
|
||||
# build & deploy
|
||||
bd: build deploy
|
||||
32138
api/package-lock.json
generated
32138
api/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
409
api/package.json
409
api/package.json
@@ -1,218 +1,195 @@
|
||||
{
|
||||
"name": "@unraid/api",
|
||||
"version": "3.11.0",
|
||||
"main": "dist/index.js",
|
||||
"bin": "dist/unraid-api.cjs",
|
||||
"type": "module",
|
||||
"repository": "git@github.com:unraid/api.git",
|
||||
"author": "Alexis Tyler <xo@wvvw.me> (https://wvvw.me/)",
|
||||
"license": "UNLICENSED",
|
||||
"engines": {
|
||||
"node": ">=16.5.0"
|
||||
},
|
||||
"pkg": {
|
||||
"assets": [
|
||||
"dist/index.cjs",
|
||||
"node_modules/@vmngr/libvirt/build/Release",
|
||||
"node_modules/ts-invariant/",
|
||||
"src/**/*.graphql"
|
||||
],
|
||||
"targets": [
|
||||
"node18-linux-x64"
|
||||
],
|
||||
"outputPath": "dist"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "tsup --config ./tsup.config.ts",
|
||||
"bundle": "pkg . --public",
|
||||
"build": "npm run compile && npm run bundle",
|
||||
"build:docker": "./scripts/dc.sh run --rm builder",
|
||||
"build-pkg": "./scripts/build.mjs",
|
||||
"codegen": "MOTHERSHIP_GRAPHQL_LINK='https://staging.mothership.unraid.net/ws' graphql-codegen --config codegen.yml -r dotenv/config './.env.staging'",
|
||||
"codegen:watch": "DOTENV_CONFIG_PATH='./.env.staging' graphql-codegen --config codegen.yml --watch -r dotenv/config",
|
||||
"codegen:local": "NODE_TLS_REJECT_UNAUTHORIZED=0 MOTHERSHIP_GRAPHQL_LINK='https://mothership.localhost/ws' graphql-codegen-esm --config codegen.yml --watch",
|
||||
"tsc": "tsc --noEmit",
|
||||
"lint": "DEBUG=eslint:cli-engine eslint . --config .eslintrc.cjs",
|
||||
"lint:fix": "DEBUG=eslint:cli-engine eslint . --fix --config .eslintrc.cjs",
|
||||
"test:watch": "vitest --segfault-retry=3 --pool=forks",
|
||||
"test": "vitest run --segfault-retry=3 --pool=forks",
|
||||
"coverage": "vitest run --segfault-retry=3 --coverage",
|
||||
"patch:subscriptions-transport-ws": "node ./.scripts/patches/subscriptions-transport-ws.cjs",
|
||||
"release": "standard-version",
|
||||
"typesync": "typesync",
|
||||
"install:unraid": "./scripts/install-in-unraid.sh",
|
||||
"start:plugin": "INTROSPECTION=true LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty LOG_LEVEL=trace unraid-api start --debug",
|
||||
"start:plugin-verbose": "LOG_CONTEXT=true LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty LOG_LEVEL=trace unraid-api start --debug",
|
||||
"start:dev": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty NODE_ENV=development LOG_LEVEL=trace NODE_ENV=development tsup --config ./tsup.config.ts --watch --onSuccess 'DOTENV_CONFIG_PATH=./.env.development node -r dotenv/config dist/unraid-api.cjs start --debug'",
|
||||
"restart:dev": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty NODE_ENV=development LOG_LEVEL=trace NODE_ENV=development tsup --config ./tsup.config.ts --watch --onSuccess 'DOTENV_CONFIG_PATH=./.env.development node -r dotenv/config dist/unraid-api.cjs restart --debug'",
|
||||
"stop:dev": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty NODE_ENV=development LOG_LEVEL=trace NODE_ENV=development tsup --config ./tsup.config.ts --onSuccess 'DOTENV_CONFIG_PATH=./.env.development node -r dotenv/config dist/unraid-api.cjs stop --debug'",
|
||||
"start:report": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty NODE_ENV=development LOG_LEVEL=trace NODE_ENV=development LOG_CONTEXT=true tsup --config ./tsup.config.ts --watch --onSuccess 'DOTENV_CONFIG_PATH=./.env.development node -r dotenv/config dist/unraid-api.cjs report --debug'",
|
||||
"build:dev": "./scripts/dc.sh build dev",
|
||||
"start:local": "./scripts/dc.sh run --rm --service-ports local",
|
||||
"start:ddev": "./scripts/dc.sh run --rm --service-ports dev",
|
||||
"start:dtest": "./scripts/dc.sh run --rm builder npm run test",
|
||||
"enter:ddev": "./scripts/dc.sh exec dev /bin/sh"
|
||||
},
|
||||
"files": [
|
||||
".env.staging",
|
||||
".env.production",
|
||||
"dist",
|
||||
"unraid-api"
|
||||
],
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.10.4",
|
||||
"@apollo/server": "^4.10.4",
|
||||
"@as-integrations/fastify": "^2.1.1",
|
||||
"@graphql-codegen/client-preset": "^4.2.5",
|
||||
"@graphql-tools/load-files": "^7.0.0",
|
||||
"@graphql-tools/merge": "^9.0.4",
|
||||
"@graphql-tools/schema": "^10.0.3",
|
||||
"@graphql-tools/utils": "^10.2.0",
|
||||
"@nestjs/apollo": "^12.1.0",
|
||||
"@nestjs/core": "^10.3.8",
|
||||
"@nestjs/graphql": "^12.1.1",
|
||||
"@nestjs/passport": "^10.0.3",
|
||||
"@nestjs/platform-fastify": "^10.3.8",
|
||||
"@nestjs/schedule": "^4.0.2",
|
||||
"@reduxjs/toolkit": "^2.2.4",
|
||||
"@reflet/cron": "^1.3.1",
|
||||
"@runonflux/nat-upnp": "^1.0.2",
|
||||
"accesscontrol": "^2.2.1",
|
||||
"am": "github:unraid/am",
|
||||
"async-exit-hook": "^2.0.1",
|
||||
"btoa": "^1.2.1",
|
||||
"bycontract": "^2.0.11",
|
||||
"bytes": "^3.1.2",
|
||||
"cacheable-lookup": "^6.1.0",
|
||||
"catch-exit": "^1.2.2",
|
||||
"chokidar": "^3.6.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
"cli-table": "^0.3.11",
|
||||
"command-exists": "^1.2.9",
|
||||
"convert": "^4.14.1",
|
||||
"cors": "^2.8.5",
|
||||
"cross-fetch": "^4.0.0",
|
||||
"docker-event-emitter": "^0.3.0",
|
||||
"dockerode": "^3.3.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.19.2",
|
||||
"find-process": "^1.4.7",
|
||||
"global-agent": "^3.0.0",
|
||||
"graphql": "^16.8.1",
|
||||
"graphql-fields": "^2.0.3",
|
||||
"graphql-scalars": "^1.23.0",
|
||||
"graphql-subscriptions": "^2.0.0",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"graphql-type-json": "^0.3.2",
|
||||
"graphql-type-uuid": "^0.2.0",
|
||||
"graphql-ws": "^5.16.0",
|
||||
"htpasswd-js": "^1.0.2",
|
||||
"ini": "^4.1.2",
|
||||
"ip": "^2.0.1",
|
||||
"jose": "^5.3.0",
|
||||
"lodash": "^4.17.21",
|
||||
"multi-ini": "^2.2.0",
|
||||
"mustache": "^4.2.0",
|
||||
"nanobus": "^4.5.0",
|
||||
"nest-access-control": "^3.1.0",
|
||||
"nestjs-pino": "^4.0.0",
|
||||
"node-cache": "^5.1.2",
|
||||
"node-window-polyfill": "^1.0.2",
|
||||
"openid-client": "^5.6.5",
|
||||
"p-iteration": "^1.1.8",
|
||||
"p-retry": "^4.6.2",
|
||||
"passport-http-header-strategy": "^1.1.0",
|
||||
"pidusage": "^3.0.2",
|
||||
"pino": "^9.1.0",
|
||||
"pino-http": "^9.0.0",
|
||||
"pino-pretty": "^11.0.0",
|
||||
"reflect-metadata": "^0.1.14",
|
||||
"request": "^2.88.2",
|
||||
"semver": "^7.6.2",
|
||||
"stoppable": "^1.1.0",
|
||||
"systeminformation": "^5.22.9",
|
||||
"ts-command-line-args": "^2.5.1",
|
||||
"uuid": "^9.0.1",
|
||||
"ws": "^8.17.0",
|
||||
"wtfnode": "^0.9.2",
|
||||
"xhr2": "^0.2.1",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/runtime": "^7.24.5",
|
||||
"@graphql-codegen/add": "^5.0.2",
|
||||
"@graphql-codegen/cli": "^5.0.2",
|
||||
"@graphql-codegen/fragment-matcher": "^5.0.2",
|
||||
"@graphql-codegen/import-types-preset": "^3.0.0",
|
||||
"@graphql-codegen/typed-document-node": "^5.0.6",
|
||||
"@graphql-codegen/typescript": "^4.0.6",
|
||||
"@graphql-codegen/typescript-operations": "^4.2.0",
|
||||
"@graphql-codegen/typescript-resolvers": "4.0.6",
|
||||
"@graphql-typed-document-node/core": "^3.2.0",
|
||||
"@nestjs/testing": "^10.3.8",
|
||||
"@swc/core": "^1.5.7",
|
||||
"@types/async-exit-hook": "^2.0.2",
|
||||
"@types/btoa": "^1.2.5",
|
||||
"@types/bytes": "^3.1.4",
|
||||
"@types/cli-table": "^0.3.4",
|
||||
"@types/command-exists": "^1.2.3",
|
||||
"@types/dockerode": "^3.3.29",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/graphql-fields": "^1.3.9",
|
||||
"@types/graphql-type-uuid": "^0.2.6",
|
||||
"@types/ini": "^4.1.0",
|
||||
"@types/lodash": "^4.17.1",
|
||||
"@types/mustache": "^4.2.5",
|
||||
"@types/node": "^20.12.12",
|
||||
"@types/pidusage": "^2.0.5",
|
||||
"@types/pify": "^5.0.4",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@types/sendmail": "^1.4.7",
|
||||
"@types/stoppable": "^1.1.3",
|
||||
"@types/uuid": "^9.0.8",
|
||||
"@types/ws": "^8.5.10",
|
||||
"@types/wtfnode": "^0.7.3",
|
||||
"@typescript-eslint/eslint-plugin": "^7.9.0",
|
||||
"@typescript-eslint/parser": "^7.9.0",
|
||||
"@unraid/eslint-config": "github:unraid/eslint-config",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"@vitest/ui": "^1.6.0",
|
||||
"camelcase-keys": "^8.0.2",
|
||||
"cz-conventional-changelog": "3.3.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^53.0.0",
|
||||
"eslint-plugin-unused-imports": "^3.2.0",
|
||||
"execa": "^7.1.1",
|
||||
"filter-obj": "^5.1.0",
|
||||
"got": "^13",
|
||||
"graphql-codegen-typescript-validation-schema": "^0.14.1",
|
||||
"ip-regex": "^5.0.0",
|
||||
"json-difference": "^1.16.1",
|
||||
"map-obj": "^5.0.2",
|
||||
"p-props": "^5.0.0",
|
||||
"path-exists": "^5.0.0",
|
||||
"path-type": "^5.0.0",
|
||||
"pkg": "^5.8.1",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
"pretty-ms": "^8.0.0",
|
||||
"standard-version": "^9.5.0",
|
||||
"tsup": "^8.0.2",
|
||||
"typescript": "^5.4.5",
|
||||
"typesync": "^0.12.1",
|
||||
"vite-tsconfig-paths": "^4.3.2",
|
||||
"vitest": "^1.6.0",
|
||||
"zx": "^7.2.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@vmngr/libvirt": "github:unraid/libvirt"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "./node_modules/cz-conventional-changelog"
|
||||
}
|
||||
}
|
||||
"name": "@unraid/api",
|
||||
"version": "4.1.0",
|
||||
"main": "src/cli/index.ts",
|
||||
"type": "module",
|
||||
"corepack": {
|
||||
"enabled": true
|
||||
},
|
||||
"repository": "git@github.com:unraid/api.git",
|
||||
"author": "Lime Technology, Inc. <unraid.net>",
|
||||
"license": "UNLICENSED",
|
||||
"engines": {
|
||||
"pnpm": ">=8.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"// Main application commands": "",
|
||||
"start": "node dist/main.js",
|
||||
"dev": "vite",
|
||||
"command": "pnpm run build && clear && ./dist/cli.js",
|
||||
"// Build commands": "",
|
||||
"build": "vite build --mode=production",
|
||||
"postbuild": "chmod +x dist/main.js && chmod +x dist/cli.js",
|
||||
"build:docker": "./scripts/dc.sh run --rm builder",
|
||||
"build-and-pack": "tsx ./scripts/build.ts",
|
||||
"// Code generation commands": "",
|
||||
"codegen": "MOTHERSHIP_GRAPHQL_LINK='https://staging.mothership.unraid.net/ws' graphql-codegen --config codegen.ts -r dotenv/config './.env.staging'",
|
||||
"codegen:watch": "DOTENV_CONFIG_PATH='./.env.staging' graphql-codegen --config codegen.ts --watch -r dotenv/config",
|
||||
"codegen:local": "NODE_TLS_REJECT_UNAUTHORIZED=0 MOTHERSHIP_GRAPHQL_LINK='https://mothership.localhost/ws' graphql-codegen --config codegen.ts --watch",
|
||||
"// Development and quality tools": "",
|
||||
"tsc": "tsc --noEmit",
|
||||
"lint": "eslint --config .eslintrc.ts src/",
|
||||
"lint:fix": "eslint --fix --config .eslintrc.ts src/",
|
||||
"release": "standard-version",
|
||||
"// Testing commands": "",
|
||||
"test": "NODE_ENV=test vitest run",
|
||||
"test:watch": "NODE_ENV=test vitest --ui",
|
||||
"coverage": "NODE_ENV=test vitest run --coverage",
|
||||
"// Container management commands": "",
|
||||
"container:build": "./scripts/dc.sh build dev",
|
||||
"container:start": "pnpm run container:stop && ./scripts/dc.sh run --rm --service-ports dev",
|
||||
"container:stop": "./scripts/dc.sh stop dev",
|
||||
"container:test": "./scripts/dc.sh run --rm builder pnpm run test",
|
||||
"container:enter": "./scripts/dc.sh exec dev /bin/bash"
|
||||
},
|
||||
"bin": {
|
||||
"unraid-api": "dist/cli.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.11.8",
|
||||
"@apollo/server": "^4.11.2",
|
||||
"@as-integrations/fastify": "^2.1.1",
|
||||
"@fastify/cookie": "^9.4.0",
|
||||
"@graphql-codegen/client-preset": "^4.5.0",
|
||||
"@graphql-tools/load-files": "^7.0.0",
|
||||
"@graphql-tools/merge": "^9.0.8",
|
||||
"@graphql-tools/schema": "^10.0.7",
|
||||
"@graphql-tools/utils": "^10.5.5",
|
||||
"@nestjs/apollo": "^12.2.1",
|
||||
"@nestjs/common": "^10.4.7",
|
||||
"@nestjs/core": "^10.4.7",
|
||||
"@nestjs/graphql": "^12.2.1",
|
||||
"@nestjs/passport": "^10.0.3",
|
||||
"@nestjs/platform-fastify": "^10.4.7",
|
||||
"@nestjs/schedule": "^4.1.1",
|
||||
"@nestjs/throttler": "^6.2.1",
|
||||
"@reduxjs/toolkit": "^2.3.0",
|
||||
"@runonflux/nat-upnp": "^1.0.2",
|
||||
"@types/diff": "^7.0.1",
|
||||
"@unraid/libvirt": "^1.0.5",
|
||||
"accesscontrol": "^2.2.1",
|
||||
"bycontract": "^2.0.11",
|
||||
"bytes": "^3.1.2",
|
||||
"cacheable-lookup": "^7.0.0",
|
||||
"camelcase-keys": "^9.1.3",
|
||||
"casbin": "^5.32.0",
|
||||
"catch-exit": "^1.2.2",
|
||||
"chokidar": "^4.0.1",
|
||||
"cli-table": "^0.3.11",
|
||||
"command-exists": "^1.2.9",
|
||||
"convert": "^5.5.1",
|
||||
"cookie": "^1.0.2",
|
||||
"cron": "3.2.1",
|
||||
"cross-fetch": "^4.0.0",
|
||||
"diff": "^7.0.0",
|
||||
"docker-event-emitter": "^0.3.0",
|
||||
"dockerode": "^3.3.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"execa": "^9.5.1",
|
||||
"exit-hook": "^4.0.0",
|
||||
"filenamify": "^6.0.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
"glob": "^11.0.1",
|
||||
"global-agent": "^3.0.0",
|
||||
"got": "^14.4.4",
|
||||
"graphql": "^16.9.0",
|
||||
"graphql-fields": "^2.0.3",
|
||||
"graphql-scalars": "^1.23.0",
|
||||
"graphql-subscriptions": "^2.0.0",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"graphql-type-json": "^0.3.2",
|
||||
"graphql-type-uuid": "^0.2.0",
|
||||
"graphql-ws": "^5.16.0",
|
||||
"ini": "^4.1.2",
|
||||
"ip": "^2.0.1",
|
||||
"jose": "^5.9.6",
|
||||
"lodash-es": "^4.17.21",
|
||||
"multi-ini": "^2.3.2",
|
||||
"mustache": "^4.2.0",
|
||||
"nest-authz": "^2.11.0",
|
||||
"nest-commander": "^3.15.0",
|
||||
"nestjs-pino": "^4.1.0",
|
||||
"node-cache": "^5.1.2",
|
||||
"node-window-polyfill": "^1.0.2",
|
||||
"p-retry": "^6.2.0",
|
||||
"passport-custom": "^1.1.1",
|
||||
"passport-http-header-strategy": "^1.1.0",
|
||||
"path-type": "^6.0.0",
|
||||
"pino": "^9.5.0",
|
||||
"pino-http": "^10.3.0",
|
||||
"pino-pretty": "^11.3.0",
|
||||
"pm2": "^5.4.2",
|
||||
"reflect-metadata": "^0.1.14",
|
||||
"request": "^2.88.2",
|
||||
"semver": "^7.6.3",
|
||||
"strftime": "^0.10.3",
|
||||
"systeminformation": "^5.25.11",
|
||||
"uuid": "^11.0.2",
|
||||
"ws": "^8.18.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/add": "^5.0.3",
|
||||
"@graphql-codegen/cli": "^5.0.3",
|
||||
"@graphql-codegen/fragment-matcher": "^5.0.2",
|
||||
"@graphql-codegen/import-types-preset": "^3.0.0",
|
||||
"@graphql-codegen/typed-document-node": "^5.0.11",
|
||||
"@graphql-codegen/typescript": "^4.1.1",
|
||||
"@graphql-codegen/typescript-operations": "^4.3.1",
|
||||
"@graphql-codegen/typescript-resolvers": "4.4.2",
|
||||
"@graphql-typed-document-node/core": "^3.2.0",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.4.0",
|
||||
"@nestjs/testing": "^10.4.7",
|
||||
"@originjs/vite-plugin-commonjs": "^1.0.3",
|
||||
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||
"@swc/core": "^1.10.1",
|
||||
"@types/async-exit-hook": "^2.0.2",
|
||||
"@types/bytes": "^3.1.4",
|
||||
"@types/cli-table": "^0.3.4",
|
||||
"@types/command-exists": "^1.2.3",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/dockerode": "^3.3.31",
|
||||
"@types/graphql-fields": "^1.3.9",
|
||||
"@types/graphql-type-uuid": "^0.2.6",
|
||||
"@types/ini": "^4.1.1",
|
||||
"@types/ip": "^1.1.3",
|
||||
"@types/lodash": "^4.17.13",
|
||||
"@types/mustache": "^4.2.5",
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/pify": "^5.0.4",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@types/sendmail": "^1.4.7",
|
||||
"@types/stoppable": "^1.1.3",
|
||||
"@types/strftime": "^0.9.8",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"@types/ws": "^8.5.13",
|
||||
"@types/wtfnode": "^0.7.3",
|
||||
"@vitest/coverage-v8": "^3.0.5",
|
||||
"@vitest/ui": "^3.0.5",
|
||||
"cz-conventional-changelog": "3.3.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-plugin-no-relative-import-paths": "^1.6.1",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"graphql-codegen-typescript-validation-schema": "^0.17.0",
|
||||
"jiti": "^2.4.0",
|
||||
"nodemon": "^3.1.7",
|
||||
"rollup-plugin-node-externals": "^7.1.3",
|
||||
"standard-version": "^9.5.0",
|
||||
"tsx": "^4.19.2",
|
||||
"typescript": "^5.6.3",
|
||||
"typescript-eslint": "^8.13.0",
|
||||
"unplugin-swc": "^1.5.1",
|
||||
"vite": "^5.4.14",
|
||||
"vite-plugin-node": "^4.0.0",
|
||||
"vite-tsconfig-paths": "^5.1.0",
|
||||
"vitest": "^3.0.5",
|
||||
"zx": "^8.3.2"
|
||||
},
|
||||
"overrides": {
|
||||
"eslint": {
|
||||
"jiti": "2"
|
||||
}
|
||||
},
|
||||
"packageManager": "pnpm@8.15.4+sha512.0bd3a9be9eb0e9a692676deec00a303ba218ba279d99241475616b398dbaeedd11146f92c2843458f557b1d127e09d4c171e105bdcd6b61002b39685a8016b9e",
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
#!/usr/bin/env zx
|
||||
import { exit } from 'process';
|
||||
import { cd, $ } from 'zx';
|
||||
|
||||
import getTags from './get-tags.mjs'
|
||||
|
||||
try {
|
||||
// Enable colours in output
|
||||
process.env.FORCE_COLOR = '1';
|
||||
|
||||
// Ensure we have the correct working directory
|
||||
process.env.WORKDIR = process.env.WORKDIR ?? process.env.PWD;
|
||||
cd(process.env.WORKDIR);
|
||||
|
||||
// Clean up last deploy
|
||||
await $`rm -rf ./deploy/release`;
|
||||
await $`rm -rf ./deploy/pre-pack`;
|
||||
await $`mkdir -p ./deploy/release/`;
|
||||
await $`mkdir -p ./deploy/pre-pack/`;
|
||||
|
||||
// Ensure all deps are installed
|
||||
await $`npm i`;
|
||||
|
||||
// Build Generated Types
|
||||
await $`npm run codegen`;
|
||||
// Build binary
|
||||
await $`npm run build`;
|
||||
|
||||
// Copy binary + extra files to deployment directory
|
||||
await $`cp ./dist/api ./deploy/pre-pack/unraid-api`;
|
||||
await $`cp ./.env.production ./deploy/pre-pack/.env.production`;
|
||||
await $`cp ./.env.staging ./deploy/pre-pack/.env.staging`;
|
||||
|
||||
// Get package details
|
||||
const { name, version } = await import('../package.json', {
|
||||
assert: { type: 'json' },
|
||||
}).then(pkg => pkg.default);
|
||||
|
||||
const tags = getTags(process.env);
|
||||
|
||||
// Decide whether to use full version or just tag
|
||||
const isTaggedRelease = tags.isTagged;
|
||||
const gitShaShort = tags.shortSha;
|
||||
|
||||
const deploymentVersion = isTaggedRelease ? version : `${version}+${gitShaShort}`;
|
||||
|
||||
// Create deployment package.json
|
||||
await $`echo ${JSON.stringify({ name, version: deploymentVersion })} > ./deploy/pre-pack/package.json`;
|
||||
|
||||
// # Create final tgz
|
||||
await $`cp ./README.md ./deploy/pre-pack/`;
|
||||
cd('./deploy/pre-pack');
|
||||
await $`npm pack`;
|
||||
|
||||
// Move unraid-api.tgz to release directory
|
||||
await $`mv unraid-api-${deploymentVersion}.tgz ../release`;
|
||||
|
||||
// Set API_VERSION output based on this command
|
||||
await $`echo "::set-output name=API_VERSION::${deploymentVersion}"`;
|
||||
} catch (error) {
|
||||
// Error with a command
|
||||
if (Object.keys(error).includes('stderr')) {
|
||||
console.log(`Failed building package. Exit code: ${error.exitCode}`);
|
||||
console.log(`Error: ${error.stderr}`);
|
||||
} else {
|
||||
// Normal js error
|
||||
console.log('Failed building package.');
|
||||
console.log(`Error: ${error.message}`);
|
||||
}
|
||||
|
||||
exit(error.exitCode);
|
||||
}
|
||||
67
api/scripts/build.ts
Executable file
67
api/scripts/build.ts
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env zx
|
||||
import { mkdir, readFile, rm, writeFile } from 'fs/promises';
|
||||
import { exit } from 'process';
|
||||
|
||||
import { $, cd } from 'zx';
|
||||
|
||||
import { getDeploymentVersion } from './get-deployment-version.js';
|
||||
|
||||
try {
|
||||
// Create release and pack directories
|
||||
// Clean existing deploy folder
|
||||
await rm('./deploy', { recursive: true }).catch(() => {});
|
||||
await mkdir('./deploy/release', { recursive: true });
|
||||
await mkdir('./deploy/pack', { recursive: true });
|
||||
|
||||
// Build Generated Types
|
||||
await $`pnpm run codegen`;
|
||||
|
||||
await $`pnpm run build`;
|
||||
// Copy app files to plugin directory
|
||||
|
||||
// Get package details
|
||||
const packageJson = await readFile('./package.json', 'utf-8');
|
||||
const parsedPackageJson = JSON.parse(packageJson);
|
||||
|
||||
const deploymentVersion = await getDeploymentVersion(process.env, parsedPackageJson.version);
|
||||
|
||||
// Update the package.json version to the deployment version
|
||||
parsedPackageJson.version = deploymentVersion;
|
||||
|
||||
// Create a temporary directory for packaging
|
||||
await mkdir('./deploy/pack/', { recursive: true });
|
||||
|
||||
await writeFile('./deploy/pack/package.json', JSON.stringify(parsedPackageJson, null, 4));
|
||||
// Copy necessary files to the pack directory
|
||||
await $`cp -r dist README.md .env.* ecosystem.config.json ./deploy/pack/`;
|
||||
|
||||
// Change to the pack directory and install dependencies
|
||||
cd('./deploy/pack');
|
||||
|
||||
console.log('Installing production dependencies...');
|
||||
$.verbose = true;
|
||||
await $`pnpm install --prod --ignore-workspace --node-linker hoisted`;
|
||||
|
||||
// chmod the cli
|
||||
await $`chmod +x ./dist/cli.js`;
|
||||
await $`chmod +x ./dist/main.js`;
|
||||
|
||||
// Create the tarball
|
||||
await $`tar -czf ../release/unraid-api.tgz ./`;
|
||||
|
||||
// Clean up
|
||||
cd('..');
|
||||
|
||||
} catch (error) {
|
||||
// Error with a command
|
||||
if (Object.keys(error).includes('stderr')) {
|
||||
console.log(`Failed building package. Exit code: ${error.exitCode}`);
|
||||
console.log(`Error: ${error.stderr}`);
|
||||
} else {
|
||||
// Normal js error
|
||||
console.log('Failed building package.');
|
||||
console.log(`Error: ${error.message}`);
|
||||
}
|
||||
|
||||
exit(error.exitCode);
|
||||
}
|
||||
33
api/scripts/create-session.sh
Executable file
33
api/scripts/create-session.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
# This script creates a mock session on a server.
|
||||
# During local dev/testing, you should run it in the api container,
|
||||
# so the nest.js api can authenticate cookies against it.
|
||||
#
|
||||
# You should also set a cookie named 'unraid_...' whose value matches
|
||||
# the name of the session you created (where name is sess_<name>).
|
||||
# By default, this is my-session
|
||||
|
||||
sessions_dir=/var/lib/php
|
||||
default_session_name=mock-user-session
|
||||
|
||||
if [ "$1" = "--help" ]; then
|
||||
echo "This script creates a mock session on a server."
|
||||
echo ""
|
||||
echo "Usage: $0 [options]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " [name] Name of the session to create (default: mock-user-session)"
|
||||
echo " --help Display this help message and exit"
|
||||
echo ""
|
||||
echo "Example: $0 a-session-name"
|
||||
echo ""
|
||||
echo "Current list of sessions:"
|
||||
ls $sessions_dir
|
||||
exit 0
|
||||
fi
|
||||
|
||||
session_name="${1:-$default_session_name}"
|
||||
|
||||
mkdir -p $sessions_dir
|
||||
touch "$sessions_dir/sess_$session_name"
|
||||
|
||||
ls $sessions_dir
|
||||
68
api/scripts/deploy-dev.sh
Executable file
68
api/scripts/deploy-dev.sh
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Path to store the last used server name
|
||||
state_file="$HOME/.deploy_state"
|
||||
|
||||
# Read the last used server name from the state file
|
||||
if [[ -f "$state_file" ]]; then
|
||||
last_server_name=$(cat "$state_file")
|
||||
else
|
||||
last_server_name=""
|
||||
fi
|
||||
|
||||
# Read the server name from the command-line argument or use the last used server name as the default
|
||||
server_name="${1:-$last_server_name}"
|
||||
|
||||
# Check if the server name is provided
|
||||
if [[ -z "$server_name" ]]; then
|
||||
echo "Please provide the SSH server name."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Save the current server name to the state file
|
||||
echo "$server_name" > "$state_file"
|
||||
|
||||
# Source directory path
|
||||
source_directory="./dist"
|
||||
|
||||
if [ ! -d "$source_directory" ]; then
|
||||
echo "The dist directory does not exist. Attempting build..."
|
||||
npm run build
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Build failed!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Change ownership on copy
|
||||
# Replace the value inside the rsync command with the user's input
|
||||
rsync_command="rsync -avz -e ssh $source_directory root@${server_name}:/usr/local/unraid-api"
|
||||
|
||||
echo "Executing the following command:"
|
||||
echo "$rsync_command"
|
||||
|
||||
# Execute the rsync command and capture the exit code
|
||||
eval "$rsync_command"
|
||||
exit_code=$?
|
||||
|
||||
# Chown the directory
|
||||
ssh root@"${server_name}" "chown -R root:root /usr/local/unraid-api"
|
||||
|
||||
# Run unraid-api restart on remote host
|
||||
ssh root@"${server_name}" "INTROSPECTION=true LOG_LEVEL=trace unraid-api restart"
|
||||
|
||||
# Play built-in sound based on the operating system
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
# macOS
|
||||
afplay /System/Library/Sounds/Glass.aiff
|
||||
elif [[ "$OSTYPE" == "linux-gnu" ]]; then
|
||||
# Linux
|
||||
paplay /usr/share/sounds/freedesktop/stereo/complete.oga
|
||||
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
|
||||
# Windows
|
||||
powershell.exe -c "(New-Object Media.SoundPlayer 'C:\Windows\Media\Windows Default.wav').PlaySync()"
|
||||
fi
|
||||
|
||||
# Exit with the rsync command's exit code
|
||||
exit $exit_code
|
||||
|
||||
32
api/scripts/get-deployment-version.ts
Normal file
32
api/scripts/get-deployment-version.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { execa } from 'execa';
|
||||
|
||||
const runCommand = async (command: string, args: string[]) => {
|
||||
try {
|
||||
const { stdout } = await execa(command, args);
|
||||
return stdout.trim();
|
||||
} catch (error) {
|
||||
console.log('Failed to execute command:', command, args.join(' '), error.message);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export const getDeploymentVersion = async (env = process.env, packageVersion: string) => {
|
||||
if (env.API_VERSION) {
|
||||
console.log(`Using env var for version: ${env.API_VERSION}`);
|
||||
return env.API_VERSION;
|
||||
} else if (env.GIT_SHA && env.IS_TAGGED) {
|
||||
console.log(`Using env vars for git tags: ${env.GIT_SHA} ${env.IS_TAGGED}`);
|
||||
return env.IS_TAGGED ? packageVersion : `${packageVersion}+${env.GIT_SHA}`;
|
||||
} else {
|
||||
const gitShortSHA = await runCommand('git', ['rev-parse', '--short', 'HEAD']);
|
||||
const isCommitTagged = await runCommand('git', ['describe', '--tags', '--abbrev=0', '--exact-match']) !== undefined;
|
||||
|
||||
console.log('gitShortSHA', gitShortSHA, 'isCommitTagged', isCommitTagged);
|
||||
|
||||
if (!gitShortSHA) {
|
||||
console.error('Failed to get git short SHA');
|
||||
process.exit(1);
|
||||
}
|
||||
return isCommitTagged ? packageVersion : `${packageVersion}+${gitShortSHA}`;
|
||||
}
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
const runCommand = (command) => {
|
||||
try {
|
||||
return execSync(command, { stdio: 'pipe' }).toString().trim();
|
||||
} catch(error) {
|
||||
console.log('Failed to get value from tag command: ', command, error.message);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const getTags = (env = process.env) => {
|
||||
|
||||
if (env.GIT_SHA) {
|
||||
console.log(`Using env vars for git tags: ${env.GIT_SHA} ${env.IS_TAGGED}`)
|
||||
return {
|
||||
shortSha: env.GIT_SHA,
|
||||
isTagged: Boolean(env.IS_TAGGED)
|
||||
}
|
||||
} else {
|
||||
const gitShortSHA = runCommand('git rev-parse --short HEAD');
|
||||
const isCommitTagged = runCommand('git describe --tags --abbrev=0 --exact-match') !== undefined;
|
||||
console.log('gitShortSHA', gitShortSHA, 'isCommitTagged', isCommitTagged);
|
||||
if (!gitShortSHA) {
|
||||
throw new Error('Failing build due to missing SHA');
|
||||
}
|
||||
return {
|
||||
shortSha: gitShortSHA,
|
||||
isTagged: isCommitTagged
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default getTags;
|
||||
@@ -1,31 +0,0 @@
|
||||
import { beforeEach, expect, test, vi } from 'vitest';
|
||||
|
||||
// Preloading imports for faster tests
|
||||
import '@app/cli/commands/restart';
|
||||
import '@app/cli/commands/start';
|
||||
import '@app/cli/commands/stop';
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
test('calls stop and then start', async () => {
|
||||
vi.mock('@app/cli/commands/start');
|
||||
vi.mock('@app/cli/commands/stop');
|
||||
// Call restart
|
||||
const { restart } = await import('@app/cli/commands/restart');
|
||||
const { start } = await import('@app/cli/commands/start');
|
||||
const { stop } = await import('@app/cli/commands/stop');
|
||||
await restart();
|
||||
|
||||
// Check stop was called
|
||||
expect(vi.mocked(stop).mock.calls.length).toBe(1);
|
||||
|
||||
// Check start was called
|
||||
expect(vi.mocked(start).mock.calls.length).toBe(1);
|
||||
|
||||
// Check stop was called first
|
||||
expect(vi.mocked(stop).mock.invocationCallOrder[0]).toBeLessThan(
|
||||
vi.mocked(start).mock.invocationCallOrder[0]
|
||||
);
|
||||
});
|
||||
@@ -1,48 +1,44 @@
|
||||
import { getAllowedOrigins } from '@app/common/allowed-origins';
|
||||
import { store } from '@app/store/index';
|
||||
import { loadConfigFile } from '@app/store/modules/config';
|
||||
import { loadStateFiles } from '@app/store/modules/emhttp';
|
||||
|
||||
import 'reflect-metadata';
|
||||
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
// Preloading imports for faster tests
|
||||
import '@app/common/allowed-origins';
|
||||
import '@app/store/modules/emhttp';
|
||||
import '@app/store';
|
||||
|
||||
test('Returns allowed origins', async () => {
|
||||
const { store } = await import('@app/store');
|
||||
const { loadStateFiles } = await import('@app/store/modules/emhttp');
|
||||
const { getAllowedOrigins } = await import('@app/common/allowed-origins');
|
||||
const { loadConfigFile } = await import('@app/store/modules/config');
|
||||
|
||||
// Load state files into store
|
||||
await store.dispatch(loadStateFiles());
|
||||
await store.dispatch(loadConfigFile());
|
||||
|
||||
// Get allowed origins
|
||||
expect(getAllowedOrigins()).toMatchInlineSnapshot(`
|
||||
[
|
||||
"/var/run/unraid-notifications.sock",
|
||||
"/var/run/unraid-php.sock",
|
||||
"/var/run/unraid-cli.sock",
|
||||
"http://localhost:8080",
|
||||
"https://localhost:4443",
|
||||
"https://tower.local:4443",
|
||||
"https://192.168.1.150:4443",
|
||||
"https://tower:4443",
|
||||
"https://192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net:4443",
|
||||
"https://85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net:8443",
|
||||
"https://10-252-0-1.hash.myunraid.net:4443",
|
||||
"https://10-252-1-1.hash.myunraid.net:4443",
|
||||
"https://10-253-3-1.hash.myunraid.net:4443",
|
||||
"https://10-253-4-1.hash.myunraid.net:4443",
|
||||
"https://10-253-5-1.hash.myunraid.net:4443",
|
||||
"https://10-100-0-1.hash.myunraid.net:4443",
|
||||
"https://10-100-0-2.hash.myunraid.net:4443",
|
||||
"https://10-123-1-2.hash.myunraid.net:4443",
|
||||
"https://221-123-121-112.hash.myunraid.net:4443",
|
||||
"https://google.com",
|
||||
"https://test.com",
|
||||
"https://connect.myunraid.net",
|
||||
"https://connect-staging.myunraid.net",
|
||||
"https://dev-my.myunraid.net:4000",
|
||||
]
|
||||
`);
|
||||
[
|
||||
"/var/run/unraid-notifications.sock",
|
||||
"/var/run/unraid-php.sock",
|
||||
"/var/run/unraid-cli.sock",
|
||||
"http://localhost:8080",
|
||||
"https://localhost:4443",
|
||||
"https://tower.local:4443",
|
||||
"https://192.168.1.150:4443",
|
||||
"https://tower:4443",
|
||||
"https://192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net:4443",
|
||||
"https://85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net:8443",
|
||||
"https://10-252-0-1.hash.myunraid.net:4443",
|
||||
"https://10-252-1-1.hash.myunraid.net:4443",
|
||||
"https://10-253-3-1.hash.myunraid.net:4443",
|
||||
"https://10-253-4-1.hash.myunraid.net:4443",
|
||||
"https://10-253-5-1.hash.myunraid.net:4443",
|
||||
"https://10-100-0-1.hash.myunraid.net:4443",
|
||||
"https://10-100-0-2.hash.myunraid.net:4443",
|
||||
"https://10-123-1-2.hash.myunraid.net:4443",
|
||||
"https://221-123-121-112.hash.myunraid.net:4443",
|
||||
"https://google.com",
|
||||
"https://test.com",
|
||||
"https://connect.myunraid.net",
|
||||
"https://connect-staging.myunraid.net",
|
||||
"https://dev-my.myunraid.net:4000",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
@@ -1,446 +0,0 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`Returns default permissions 1`] = `
|
||||
RolesBuilder {
|
||||
"_grants": {
|
||||
"admin": {
|
||||
"$extend": [
|
||||
"guest",
|
||||
],
|
||||
"apikey": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"array": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"cloud": {
|
||||
"read:own": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"config": {
|
||||
"update:own": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"connect": {
|
||||
"read:own": [
|
||||
"*",
|
||||
],
|
||||
"update:own": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"cpu": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"crash-reporting-enabled": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"customizations": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"device": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"device/unassigned": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"disk": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"disk/settings": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"display": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"docker/container": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"docker/network": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"flash": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"info": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"license-key": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"logs": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"machine-id": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"memory": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"notifications": {
|
||||
"create:any": [
|
||||
"*",
|
||||
],
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"online": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"os": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"owner": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"parity-history": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"permission": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"registration": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"servers": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"service": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"service/emhttpd": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"service/unraid-api": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"services": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"share": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"software-versions": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"unraid-version": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"uptime": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"user": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"vars": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"vms": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"vms/domain": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"vms/network": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
},
|
||||
"guest": {
|
||||
"me": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"welcome": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
},
|
||||
"my_servers": {
|
||||
"$extend": [
|
||||
"guest",
|
||||
],
|
||||
"array": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"config": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"connect": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"connect/dynamic-remote-access": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
"update:own": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"customizations": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"dashboard": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"display": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"docker": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"docker/container": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"info": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"logs": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"network": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"notifications": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"services": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"unraid-version": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"vars": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"vms": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"vms/domain": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
},
|
||||
"notifier": {
|
||||
"$extend": [
|
||||
"guest",
|
||||
],
|
||||
"notifications": {
|
||||
"create:own": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
},
|
||||
"upc": {
|
||||
"$extend": [
|
||||
"guest",
|
||||
],
|
||||
"apikey": {
|
||||
"read:own": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"cloud": {
|
||||
"read:own": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"config": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
"update:own": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"connect": {
|
||||
"read:own": [
|
||||
"*",
|
||||
],
|
||||
"update:own": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"crash-reporting-enabled": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"customizations": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"disk": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"display": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"flash": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"info": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"logs": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"os": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"owner": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"permission": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"registration": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"servers": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
"vars": {
|
||||
"read:any": [
|
||||
"*",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"_isLocked": false,
|
||||
}
|
||||
`;
|
||||
@@ -1,212 +1,209 @@
|
||||
import { test, expect, vi } from 'vitest';
|
||||
import { expect, test, vi } from 'vitest';
|
||||
|
||||
import { getArrayData } from '@app/core/modules/array/get-array-data';
|
||||
import { store } from '@app/store';
|
||||
import { loadConfigFile } from '@app/store/modules/config';
|
||||
import { loadStateFiles } from '@app/store/modules/emhttp';
|
||||
|
||||
vi.mock('@app/core/pubsub', () => ({
|
||||
pubsub: { publish: vi.fn() },
|
||||
}));
|
||||
|
||||
test('Creates an array event', async () => {
|
||||
const { getArrayData } = await import(
|
||||
'@app/core/modules/array/get-array-data'
|
||||
);
|
||||
const { store } = await import('@app/store');
|
||||
const { loadStateFiles } = await import('@app/store/modules/emhttp');
|
||||
const { loadConfigFile } = await import('@app/store/modules/config');
|
||||
// Load state files into store
|
||||
await store.dispatch(loadStateFiles());
|
||||
|
||||
await store.dispatch(loadConfigFile());
|
||||
|
||||
const arrayEvent = getArrayData(store.getState);
|
||||
expect(arrayEvent).toMatchInlineSnapshot(`
|
||||
{
|
||||
"boot": {
|
||||
"comment": "Unraid OS boot device",
|
||||
"critical": null,
|
||||
"device": "sda",
|
||||
"exportable": true,
|
||||
"format": "unknown",
|
||||
"fsFree": 3191407,
|
||||
"fsSize": 4042732,
|
||||
"fsType": "vfat",
|
||||
"fsUsed": 851325,
|
||||
"id": "Cruzer",
|
||||
"idx": 32,
|
||||
"name": "flash",
|
||||
"numErrors": 0,
|
||||
"numReads": 0,
|
||||
"numWrites": 0,
|
||||
"rotational": true,
|
||||
"size": 3956700,
|
||||
"status": "DISK_OK",
|
||||
"temp": null,
|
||||
"transport": "usb",
|
||||
"type": "Flash",
|
||||
"warning": null,
|
||||
expect(arrayEvent).toMatchObject({
|
||||
boot: {
|
||||
comment: 'Unraid OS boot device',
|
||||
critical: null,
|
||||
device: 'sda',
|
||||
exportable: true,
|
||||
format: 'unknown',
|
||||
fsFree: 3191407,
|
||||
fsSize: 4042732,
|
||||
fsType: 'vfat',
|
||||
fsUsed: 851325,
|
||||
id: 'Cruzer',
|
||||
idx: 32,
|
||||
name: 'flash',
|
||||
numErrors: 0,
|
||||
numReads: 0,
|
||||
numWrites: 0,
|
||||
rotational: true,
|
||||
size: 3956700,
|
||||
status: 'DISK_OK',
|
||||
temp: null,
|
||||
transport: 'usb',
|
||||
type: 'Flash',
|
||||
warning: null,
|
||||
},
|
||||
"caches": [
|
||||
{
|
||||
"comment": "",
|
||||
"critical": null,
|
||||
"device": "sdi",
|
||||
"exportable": false,
|
||||
"format": "MBR: 4KiB-aligned",
|
||||
"fsFree": 111810683,
|
||||
"fsSize": 250059317,
|
||||
"fsType": "btrfs",
|
||||
"fsUsed": 137273827,
|
||||
"id": "Samsung_SSD_850_EVO_250GB_S2R5NX0H643734Z",
|
||||
"idx": 30,
|
||||
"name": "cache",
|
||||
"numErrors": 0,
|
||||
"numReads": 0,
|
||||
"numWrites": 0,
|
||||
"rotational": false,
|
||||
"size": 244198552,
|
||||
"status": "DISK_OK",
|
||||
"temp": 22,
|
||||
"transport": "ata",
|
||||
"type": "Cache",
|
||||
"warning": null,
|
||||
},
|
||||
{
|
||||
"comment": null,
|
||||
"critical": null,
|
||||
"device": "nvme0n1",
|
||||
"exportable": false,
|
||||
"format": "MBR: 4KiB-aligned",
|
||||
"fsFree": null,
|
||||
"fsSize": null,
|
||||
"fsType": null,
|
||||
"fsUsed": null,
|
||||
"id": "KINGSTON_SA2000M8250G_50026B7282669D9E",
|
||||
"idx": 31,
|
||||
"name": "cache2",
|
||||
"numErrors": 0,
|
||||
"numReads": 0,
|
||||
"numWrites": 0,
|
||||
"rotational": false,
|
||||
"size": 244198552,
|
||||
"status": "DISK_OK",
|
||||
"temp": 27,
|
||||
"transport": "nvme",
|
||||
"type": "Cache",
|
||||
"warning": null,
|
||||
},
|
||||
caches: [
|
||||
{
|
||||
comment: '',
|
||||
critical: null,
|
||||
device: 'sdi',
|
||||
exportable: false,
|
||||
format: 'MBR: 4KiB-aligned',
|
||||
fsFree: 111810683,
|
||||
fsSize: 250059317,
|
||||
fsType: 'btrfs',
|
||||
fsUsed: 137273827,
|
||||
id: 'Samsung_SSD_850_EVO_250GB_S2R5NX0H643734Z',
|
||||
idx: 30,
|
||||
name: 'cache',
|
||||
numErrors: 0,
|
||||
numReads: 0,
|
||||
numWrites: 0,
|
||||
rotational: false,
|
||||
size: 244198552,
|
||||
status: 'DISK_OK',
|
||||
temp: 22,
|
||||
transport: 'ata',
|
||||
type: 'Cache',
|
||||
warning: null,
|
||||
},
|
||||
{
|
||||
comment: null,
|
||||
critical: null,
|
||||
device: 'nvme0n1',
|
||||
exportable: false,
|
||||
format: 'MBR: 4KiB-aligned',
|
||||
fsFree: null,
|
||||
fsSize: null,
|
||||
fsType: null,
|
||||
fsUsed: null,
|
||||
id: 'KINGSTON_SA2000M8250G_50026B7282669D9E',
|
||||
idx: 31,
|
||||
name: 'cache2',
|
||||
numErrors: 0,
|
||||
numReads: 0,
|
||||
numWrites: 0,
|
||||
rotational: false,
|
||||
size: 244198552,
|
||||
status: 'DISK_OK',
|
||||
temp: 27,
|
||||
transport: 'nvme',
|
||||
type: 'Cache',
|
||||
warning: null,
|
||||
},
|
||||
],
|
||||
"capacity": {
|
||||
"disks": {
|
||||
"free": "27",
|
||||
"total": "30",
|
||||
"used": "3",
|
||||
},
|
||||
"kilobytes": {
|
||||
"free": "19495825571",
|
||||
"total": "41994745901",
|
||||
"used": "22498920330",
|
||||
},
|
||||
capacity: {
|
||||
disks: {
|
||||
free: '27',
|
||||
total: '30',
|
||||
used: '3',
|
||||
},
|
||||
kilobytes: {
|
||||
free: '19495825571',
|
||||
total: '41994745901',
|
||||
used: '22498920330',
|
||||
},
|
||||
},
|
||||
"disks": [
|
||||
{
|
||||
"comment": "Seagate Exos",
|
||||
"critical": 75,
|
||||
"device": "sdf",
|
||||
"exportable": false,
|
||||
"format": "GPT: 4KiB-aligned",
|
||||
"fsFree": 13882739732,
|
||||
"fsSize": 17998742753,
|
||||
"fsType": "xfs",
|
||||
"fsUsed": 4116003021,
|
||||
"id": "ST18000NM000J-2TV103_ZR5B1W9X",
|
||||
"idx": 1,
|
||||
"name": "disk1",
|
||||
"numErrors": 0,
|
||||
"numReads": 0,
|
||||
"numWrites": 0,
|
||||
"rotational": true,
|
||||
"size": 17578328012,
|
||||
"status": "DISK_OK",
|
||||
"temp": 30,
|
||||
"transport": "ata",
|
||||
"type": "Data",
|
||||
"warning": 50,
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"critical": null,
|
||||
"device": "sdj",
|
||||
"exportable": false,
|
||||
"format": "GPT: 4KiB-aligned",
|
||||
"fsFree": 93140746,
|
||||
"fsSize": 11998001574,
|
||||
"fsType": "xfs",
|
||||
"fsUsed": 11904860828,
|
||||
"id": "WDC_WD120EDAZ-11F3RA0_5PJRD45C",
|
||||
"idx": 2,
|
||||
"name": "disk2",
|
||||
"numErrors": 0,
|
||||
"numReads": 0,
|
||||
"numWrites": 0,
|
||||
"rotational": true,
|
||||
"size": 11718885324,
|
||||
"status": "DISK_OK",
|
||||
"temp": 30,
|
||||
"transport": "ata",
|
||||
"type": "Data",
|
||||
"warning": null,
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"critical": null,
|
||||
"device": "sde",
|
||||
"exportable": false,
|
||||
"format": "GPT: 4KiB-aligned",
|
||||
"fsFree": 5519945093,
|
||||
"fsSize": 11998001574,
|
||||
"fsType": "xfs",
|
||||
"fsUsed": 6478056481,
|
||||
"id": "WDC_WD120EMAZ-11BLFA0_5PH8BTYD",
|
||||
"idx": 3,
|
||||
"name": "disk3",
|
||||
"numErrors": 0,
|
||||
"numReads": 0,
|
||||
"numWrites": 0,
|
||||
"rotational": true,
|
||||
"size": 11718885324,
|
||||
"status": "DISK_OK",
|
||||
"temp": 30,
|
||||
"transport": "ata",
|
||||
"type": "Data",
|
||||
"warning": null,
|
||||
},
|
||||
disks: [
|
||||
{
|
||||
comment: 'Seagate Exos',
|
||||
critical: 75,
|
||||
device: 'sdf',
|
||||
exportable: false,
|
||||
format: 'GPT: 4KiB-aligned',
|
||||
fsFree: 13882739732,
|
||||
fsSize: 17998742753,
|
||||
fsType: 'xfs',
|
||||
fsUsed: 4116003021,
|
||||
id: 'ST18000NM000J-2TV103_ZR5B1W9X',
|
||||
idx: 1,
|
||||
name: 'disk1',
|
||||
numErrors: 0,
|
||||
numReads: 0,
|
||||
numWrites: 0,
|
||||
rotational: true,
|
||||
size: 17578328012,
|
||||
status: 'DISK_OK',
|
||||
temp: 30,
|
||||
transport: 'ata',
|
||||
type: 'Data',
|
||||
warning: 50,
|
||||
},
|
||||
{
|
||||
comment: '',
|
||||
critical: null,
|
||||
device: 'sdj',
|
||||
exportable: false,
|
||||
format: 'GPT: 4KiB-aligned',
|
||||
fsFree: 93140746,
|
||||
fsSize: 11998001574,
|
||||
fsType: 'xfs',
|
||||
fsUsed: 11904860828,
|
||||
id: 'WDC_WD120EDAZ-11F3RA0_5PJRD45C',
|
||||
idx: 2,
|
||||
name: 'disk2',
|
||||
numErrors: 0,
|
||||
numReads: 0,
|
||||
numWrites: 0,
|
||||
rotational: true,
|
||||
size: 11718885324,
|
||||
status: 'DISK_OK',
|
||||
temp: 30,
|
||||
transport: 'ata',
|
||||
type: 'Data',
|
||||
warning: null,
|
||||
},
|
||||
{
|
||||
comment: '',
|
||||
critical: null,
|
||||
device: 'sde',
|
||||
exportable: false,
|
||||
format: 'GPT: 4KiB-aligned',
|
||||
fsFree: 5519945093,
|
||||
fsSize: 11998001574,
|
||||
fsType: 'xfs',
|
||||
fsUsed: 6478056481,
|
||||
id: 'WDC_WD120EMAZ-11BLFA0_5PH8BTYD',
|
||||
idx: 3,
|
||||
name: 'disk3',
|
||||
numErrors: 0,
|
||||
numReads: 0,
|
||||
numWrites: 0,
|
||||
rotational: true,
|
||||
size: 11718885324,
|
||||
status: 'DISK_OK',
|
||||
temp: 30,
|
||||
transport: 'ata',
|
||||
type: 'Data',
|
||||
warning: null,
|
||||
},
|
||||
],
|
||||
"id": "97bbe87602982688216c367801f7aa24ea57350b44b7523160d01a9d48d6fcb9",
|
||||
"parities": [
|
||||
{
|
||||
"comment": null,
|
||||
"critical": null,
|
||||
"device": "sdh",
|
||||
"exportable": false,
|
||||
"format": "GPT: 4KiB-aligned",
|
||||
"fsFree": null,
|
||||
"fsSize": null,
|
||||
"fsType": null,
|
||||
"fsUsed": null,
|
||||
"id": "ST18000NM000J-2TV103_ZR585CPY",
|
||||
"idx": 0,
|
||||
"name": "parity",
|
||||
"numErrors": 0,
|
||||
"numReads": 0,
|
||||
"numWrites": 0,
|
||||
"rotational": true,
|
||||
"size": 17578328012,
|
||||
"status": "DISK_OK",
|
||||
"temp": 25,
|
||||
"transport": "ata",
|
||||
"type": "Parity",
|
||||
"warning": null,
|
||||
},
|
||||
id: expect.any(String),
|
||||
parities: [
|
||||
{
|
||||
comment: null,
|
||||
critical: null,
|
||||
device: 'sdh',
|
||||
exportable: false,
|
||||
format: 'GPT: 4KiB-aligned',
|
||||
fsFree: null,
|
||||
fsSize: null,
|
||||
fsType: null,
|
||||
fsUsed: null,
|
||||
id: 'ST18000NM000J-2TV103_ZR585CPY',
|
||||
idx: 0,
|
||||
name: 'parity',
|
||||
numErrors: 0,
|
||||
numReads: 0,
|
||||
numWrites: 0,
|
||||
rotational: true,
|
||||
size: 17578328012,
|
||||
status: 'DISK_OK',
|
||||
temp: 25,
|
||||
transport: 'ata',
|
||||
type: 'Parity',
|
||||
warning: null,
|
||||
},
|
||||
],
|
||||
"state": "STOPPED",
|
||||
}
|
||||
`);
|
||||
state: 'STOPPED',
|
||||
});
|
||||
});
|
||||
|
||||
22
api/src/__test__/core/notifiers/console.test.ts
Normal file
22
api/src/__test__/core/notifiers/console.test.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { expect, test, vi } from 'vitest';
|
||||
|
||||
import { ConsoleNotifier } from '@app/core/notifiers/console';
|
||||
|
||||
vi.mock('@app/core/log', () => ({
|
||||
logger: {
|
||||
info: vi.fn(),
|
||||
error: vi.fn(),
|
||||
debug: vi.fn(),
|
||||
},
|
||||
graphqlLogger: {
|
||||
info: vi.fn(),
|
||||
error: vi.fn(),
|
||||
debug: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
test('Creates a console notifier', () => {
|
||||
const notifier = new ConsoleNotifier();
|
||||
expect(notifier.level).toBe('info');
|
||||
expect(notifier.template).toBe('{{{ data }}}');
|
||||
});
|
||||
24
api/src/__test__/core/notifiers/unraid-local.test.ts
Normal file
24
api/src/__test__/core/notifiers/unraid-local.test.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { expect, test, vi } from 'vitest';
|
||||
|
||||
import { UnraidLocalNotifier } from '@app/core/notifiers/unraid-local';
|
||||
|
||||
vi.mock('@app/core/log', () => ({
|
||||
logger: {
|
||||
info: vi.fn(),
|
||||
error: vi.fn(),
|
||||
debug: vi.fn(),
|
||||
},
|
||||
graphqlLogger: {
|
||||
info: vi.fn(),
|
||||
error: vi.fn(),
|
||||
debug: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
test('Creates an email notifier', () => {
|
||||
const notifier = new UnraidLocalNotifier({ level: 'info' });
|
||||
expect(notifier.level).toBe('normal');
|
||||
expect(notifier.template).toBe('{{ message }}');
|
||||
const rendered = notifier.render({ message: 'Remote access started' });
|
||||
expect(rendered).toEqual('Remote access started');
|
||||
});
|
||||
@@ -1,8 +0,0 @@
|
||||
import 'reflect-metadata';
|
||||
|
||||
import { expect, test } from 'vitest';
|
||||
import { setupPermissions } from '@app/core/permissions';
|
||||
|
||||
test('Returns default permissions', () => {
|
||||
expect(setupPermissions()).toMatchSnapshot();
|
||||
});
|
||||
23
api/src/__test__/core/utils/array/array-is-running.test.ts
Normal file
23
api/src/__test__/core/utils/array/array-is-running.test.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { expect, test, vi } from 'vitest';
|
||||
|
||||
import type { SliceState } from '@app/store/modules/emhttp';
|
||||
import { getters } from '@app/store';
|
||||
|
||||
test('Returns true if the array is started', async () => {
|
||||
vi.spyOn(getters, 'emhttp').mockImplementation(
|
||||
() => ({ var: { mdState: 'STARTED' } }) as unknown as SliceState
|
||||
);
|
||||
|
||||
const { arrayIsRunning } = await import('@app/core/utils/array/array-is-running');
|
||||
expect(arrayIsRunning()).toBe(true);
|
||||
vi.spyOn(getters, 'emhttp').mockReset();
|
||||
});
|
||||
|
||||
test('Returns false if the array is stopped', async () => {
|
||||
vi.spyOn(getters, 'emhttp').mockImplementation(
|
||||
() => ({ var: { mdState: 'Stopped' } }) as unknown as SliceState
|
||||
);
|
||||
const { arrayIsRunning } = await import('@app/core/utils/array/array-is-running');
|
||||
expect(arrayIsRunning()).toBe(false);
|
||||
vi.spyOn(getters, 'emhttp').mockReset();
|
||||
});
|
||||
@@ -1,126 +1,123 @@
|
||||
import 'reflect-metadata';
|
||||
|
||||
import { test, expect } from 'vitest';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { getWriteableConfig } from '@app/core/utils/files/config-file-normalizer';
|
||||
import { initialState } from '@app/store/modules/config';
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
test('it creates a FLASH config with NO OPTIONAL values', () => {
|
||||
const basicConfig = initialState;
|
||||
const config = getWriteableConfig(basicConfig, 'flash');
|
||||
expect(config).toMatchInlineSnapshot(`
|
||||
{
|
||||
"api": {
|
||||
"extraOrigins": "",
|
||||
"version": "",
|
||||
},
|
||||
"local": {},
|
||||
"notifier": {
|
||||
"apikey": "",
|
||||
},
|
||||
"remote": {
|
||||
"accesstoken": "",
|
||||
"apikey": "",
|
||||
"avatar": "",
|
||||
"dynamicRemoteAccessType": "DISABLED",
|
||||
"email": "",
|
||||
"idtoken": "",
|
||||
"refreshtoken": "",
|
||||
"regWizTime": "",
|
||||
"username": "",
|
||||
"wanaccess": "",
|
||||
"wanport": "",
|
||||
},
|
||||
"upc": {
|
||||
"apikey": "",
|
||||
},
|
||||
}
|
||||
`);
|
||||
{
|
||||
"api": {
|
||||
"extraOrigins": "",
|
||||
"version": "",
|
||||
},
|
||||
"local": {
|
||||
"sandbox": "no",
|
||||
},
|
||||
"remote": {
|
||||
"accesstoken": "",
|
||||
"apikey": "",
|
||||
"avatar": "",
|
||||
"dynamicRemoteAccessType": "DISABLED",
|
||||
"email": "",
|
||||
"idtoken": "",
|
||||
"localApiKey": "",
|
||||
"refreshtoken": "",
|
||||
"regWizTime": "",
|
||||
"ssoSubIds": "",
|
||||
"upnpEnabled": "",
|
||||
"username": "",
|
||||
"wanaccess": "",
|
||||
"wanport": "",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('it creates a MEMORY config with NO OPTIONAL values', () => {
|
||||
const basicConfig = initialState;
|
||||
const config = getWriteableConfig(basicConfig, 'memory');
|
||||
expect(config).toMatchInlineSnapshot(`
|
||||
{
|
||||
"api": {
|
||||
"extraOrigins": "",
|
||||
"version": "",
|
||||
},
|
||||
"connectionStatus": {
|
||||
"minigraph": "PRE_INIT",
|
||||
},
|
||||
"local": {},
|
||||
"notifier": {
|
||||
"apikey": "",
|
||||
},
|
||||
"remote": {
|
||||
"accesstoken": "",
|
||||
"allowedOrigins": "/var/run/unraid-notifications.sock, /var/run/unraid-php.sock, /var/run/unraid-cli.sock, https://connect.myunraid.net, https://connect-staging.myunraid.net, https://dev-my.myunraid.net:4000",
|
||||
"apikey": "",
|
||||
"avatar": "",
|
||||
"dynamicRemoteAccessType": "DISABLED",
|
||||
"email": "",
|
||||
"idtoken": "",
|
||||
"refreshtoken": "",
|
||||
"regWizTime": "",
|
||||
"username": "",
|
||||
"wanaccess": "",
|
||||
"wanport": "",
|
||||
},
|
||||
"upc": {
|
||||
"apikey": "",
|
||||
},
|
||||
}
|
||||
`);
|
||||
{
|
||||
"api": {
|
||||
"extraOrigins": "",
|
||||
"version": "",
|
||||
},
|
||||
"connectionStatus": {
|
||||
"minigraph": "PRE_INIT",
|
||||
"upnpStatus": "",
|
||||
},
|
||||
"local": {
|
||||
"sandbox": "no",
|
||||
},
|
||||
"remote": {
|
||||
"accesstoken": "",
|
||||
"allowedOrigins": "/var/run/unraid-notifications.sock, /var/run/unraid-php.sock, /var/run/unraid-cli.sock, https://connect.myunraid.net, https://connect-staging.myunraid.net, https://dev-my.myunraid.net:4000",
|
||||
"apikey": "",
|
||||
"avatar": "",
|
||||
"dynamicRemoteAccessType": "DISABLED",
|
||||
"email": "",
|
||||
"idtoken": "",
|
||||
"localApiKey": "",
|
||||
"refreshtoken": "",
|
||||
"regWizTime": "",
|
||||
"ssoSubIds": "",
|
||||
"upnpEnabled": "",
|
||||
"username": "",
|
||||
"wanaccess": "",
|
||||
"wanport": "",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('it creates a FLASH config with OPTIONAL values', () => {
|
||||
const basicConfig = cloneDeep(initialState);
|
||||
// 2fa & t2fa should be ignored
|
||||
basicConfig.remote['2Fa'] = 'yes';
|
||||
basicConfig.local['2Fa'] = 'yes';
|
||||
basicConfig.local.showT2Fa = 'yes';
|
||||
|
||||
basicConfig.api.extraOrigins = 'myextra.origins';
|
||||
basicConfig.remote.upnpEnabled = 'yes';
|
||||
basicConfig.connectionStatus.upnpStatus = 'Turned On';
|
||||
const config = getWriteableConfig(basicConfig, 'flash');
|
||||
expect(config).toMatchInlineSnapshot(`
|
||||
{
|
||||
"api": {
|
||||
"extraOrigins": "myextra.origins",
|
||||
"version": "",
|
||||
},
|
||||
"local": {
|
||||
"2Fa": "yes",
|
||||
"showT2Fa": "yes",
|
||||
},
|
||||
"notifier": {
|
||||
"apikey": "",
|
||||
},
|
||||
"remote": {
|
||||
"2Fa": "yes",
|
||||
"accesstoken": "",
|
||||
"apikey": "",
|
||||
"avatar": "",
|
||||
"dynamicRemoteAccessType": "DISABLED",
|
||||
"email": "",
|
||||
"idtoken": "",
|
||||
"refreshtoken": "",
|
||||
"regWizTime": "",
|
||||
"upnpEnabled": "yes",
|
||||
"username": "",
|
||||
"wanaccess": "",
|
||||
"wanport": "",
|
||||
},
|
||||
"upc": {
|
||||
"apikey": "",
|
||||
},
|
||||
}
|
||||
`);
|
||||
{
|
||||
"api": {
|
||||
"extraOrigins": "myextra.origins",
|
||||
"version": "",
|
||||
},
|
||||
"local": {
|
||||
"sandbox": "no",
|
||||
},
|
||||
"remote": {
|
||||
"accesstoken": "",
|
||||
"apikey": "",
|
||||
"avatar": "",
|
||||
"dynamicRemoteAccessType": "DISABLED",
|
||||
"email": "",
|
||||
"idtoken": "",
|
||||
"localApiKey": "",
|
||||
"refreshtoken": "",
|
||||
"regWizTime": "",
|
||||
"ssoSubIds": "",
|
||||
"upnpEnabled": "yes",
|
||||
"username": "",
|
||||
"wanaccess": "",
|
||||
"wanport": "",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('it creates a MEMORY config with OPTIONAL values', () => {
|
||||
const basicConfig = cloneDeep(initialState);
|
||||
// 2fa & t2fa should be ignored
|
||||
basicConfig.remote['2Fa'] = 'yes';
|
||||
basicConfig.local['2Fa'] = 'yes';
|
||||
basicConfig.local.showT2Fa = 'yes';
|
||||
@@ -129,41 +126,35 @@ test('it creates a MEMORY config with OPTIONAL values', () => {
|
||||
basicConfig.connectionStatus.upnpStatus = 'Turned On';
|
||||
const config = getWriteableConfig(basicConfig, 'memory');
|
||||
expect(config).toMatchInlineSnapshot(`
|
||||
{
|
||||
"api": {
|
||||
"extraOrigins": "myextra.origins",
|
||||
"version": "",
|
||||
},
|
||||
"connectionStatus": {
|
||||
"minigraph": "PRE_INIT",
|
||||
"upnpStatus": "Turned On",
|
||||
},
|
||||
"local": {
|
||||
"2Fa": "yes",
|
||||
"showT2Fa": "yes",
|
||||
},
|
||||
"notifier": {
|
||||
"apikey": "",
|
||||
},
|
||||
"remote": {
|
||||
"2Fa": "yes",
|
||||
"accesstoken": "",
|
||||
"allowedOrigins": "/var/run/unraid-notifications.sock, /var/run/unraid-php.sock, /var/run/unraid-cli.sock, https://connect.myunraid.net, https://connect-staging.myunraid.net, https://dev-my.myunraid.net:4000",
|
||||
"apikey": "",
|
||||
"avatar": "",
|
||||
"dynamicRemoteAccessType": "DISABLED",
|
||||
"email": "",
|
||||
"idtoken": "",
|
||||
"refreshtoken": "",
|
||||
"regWizTime": "",
|
||||
"upnpEnabled": "yes",
|
||||
"username": "",
|
||||
"wanaccess": "",
|
||||
"wanport": "",
|
||||
},
|
||||
"upc": {
|
||||
"apikey": "",
|
||||
},
|
||||
}
|
||||
`);
|
||||
{
|
||||
"api": {
|
||||
"extraOrigins": "myextra.origins",
|
||||
"version": "",
|
||||
},
|
||||
"connectionStatus": {
|
||||
"minigraph": "PRE_INIT",
|
||||
"upnpStatus": "Turned On",
|
||||
},
|
||||
"local": {
|
||||
"sandbox": "no",
|
||||
},
|
||||
"remote": {
|
||||
"accesstoken": "",
|
||||
"allowedOrigins": "/var/run/unraid-notifications.sock, /var/run/unraid-php.sock, /var/run/unraid-cli.sock, https://connect.myunraid.net, https://connect-staging.myunraid.net, https://dev-my.myunraid.net:4000",
|
||||
"apikey": "",
|
||||
"avatar": "",
|
||||
"dynamicRemoteAccessType": "DISABLED",
|
||||
"email": "",
|
||||
"idtoken": "",
|
||||
"localApiKey": "",
|
||||
"refreshtoken": "",
|
||||
"regWizTime": "",
|
||||
"ssoSubIds": "",
|
||||
"upnpEnabled": "yes",
|
||||
"username": "",
|
||||
"wanaccess": "",
|
||||
"wanport": "",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
import { test, expect } from 'vitest';
|
||||
import { parse } from 'ini';
|
||||
import { safelySerializeObjectToIni } from '@app/core/utils/files/safe-ini-serializer';
|
||||
import { Serializer } from 'multi-ini';
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { safelySerializeObjectToIni } from '@app/core/utils/files/safe-ini-serializer';
|
||||
|
||||
test('MultiIni breaks when serializing an object with a boolean inside', async () => {
|
||||
const objectToSerialize = {
|
||||
root: {
|
||||
anonMode: false,
|
||||
},
|
||||
};
|
||||
const serializer = new Serializer({ keep_quotes: false });
|
||||
expect(serializer.serialize(objectToSerialize)).toMatchInlineSnapshot(`
|
||||
const objectToSerialize = {
|
||||
root: {
|
||||
anonMode: false,
|
||||
},
|
||||
};
|
||||
const serializer = new Serializer({ keep_quotes: false });
|
||||
expect(serializer.serialize(objectToSerialize)).toMatchInlineSnapshot(`
|
||||
"[root]
|
||||
anonMode=false
|
||||
"
|
||||
`)
|
||||
`);
|
||||
});
|
||||
|
||||
test('MultiIni can safely serialize an object with a boolean inside', async () => {
|
||||
const objectToSerialize = {
|
||||
root: {
|
||||
anonMode: false,
|
||||
},
|
||||
};
|
||||
expect(safelySerializeObjectToIni(objectToSerialize)).toMatchInlineSnapshot(`
|
||||
const objectToSerialize = {
|
||||
root: {
|
||||
anonMode: false,
|
||||
},
|
||||
};
|
||||
expect(safelySerializeObjectToIni(objectToSerialize)).toMatchInlineSnapshot(`
|
||||
"[root]
|
||||
anonMode="false"
|
||||
"
|
||||
`);
|
||||
const result = safelySerializeObjectToIni(objectToSerialize);
|
||||
expect(parse(result)).toMatchInlineSnapshot(`
|
||||
const result = safelySerializeObjectToIni(objectToSerialize);
|
||||
expect(parse(result)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"root": {
|
||||
"anonMode": false,
|
||||
@@ -37,3 +38,33 @@ test('MultiIni can safely serialize an object with a boolean inside', async () =
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test.skip('Can serialize top-level fields', async () => {
|
||||
const objectToSerialize = {
|
||||
id: 'an-id',
|
||||
message: 'hello-world',
|
||||
number: 1,
|
||||
float: 1.1,
|
||||
flag: true,
|
||||
flag2: false,
|
||||
item: undefined,
|
||||
missing: null,
|
||||
empty: {},
|
||||
};
|
||||
|
||||
const expected = `
|
||||
"id=an-id
|
||||
message=hello-world
|
||||
number=1
|
||||
float=1.1
|
||||
flag="true"
|
||||
flag2="false"
|
||||
[empty]
|
||||
"
|
||||
`
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.join('\n');
|
||||
|
||||
expect(safelySerializeObjectToIni(objectToSerialize)).toMatchInlineSnapshot(expected);
|
||||
});
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import { getBannerPathIfPresent, getCasePathIfPresent } from "@app/core/utils/images/image-file-helpers";
|
||||
import { loadDynamixConfigFile } from "@app/store/actions/load-dynamix-config-file";
|
||||
import { store } from "@app/store/index";
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { expect, test } from "vitest";
|
||||
import { getBannerPathIfPresent, getCasePathIfPresent } from '@app/core/utils/images/image-file-helpers';
|
||||
import { loadDynamixConfigFile } from '@app/store/actions/load-dynamix-config-file';
|
||||
import { store } from '@app/store/index';
|
||||
|
||||
test('get case path returns expected result', () => {
|
||||
expect(getCasePathIfPresent()).resolves.toContain('/dev/dynamix/case-model.png')
|
||||
})
|
||||
test('get case path returns expected result', async () => {
|
||||
await expect(getCasePathIfPresent()).resolves.toContain('/dev/dynamix/case-model.png');
|
||||
});
|
||||
|
||||
test('get banner path returns null (state unloaded)', () => {
|
||||
expect(getBannerPathIfPresent()).resolves.toMatchInlineSnapshot('null')
|
||||
})
|
||||
test('get banner path returns null (state unloaded)', async () => {
|
||||
await expect(getBannerPathIfPresent()).resolves.toMatchInlineSnapshot('null');
|
||||
});
|
||||
|
||||
test('get banner path returns the banner (state loaded)', async() => {
|
||||
await store.dispatch(loadDynamixConfigFile()).unwrap();
|
||||
expect(getBannerPathIfPresent()).resolves.toContain('/dev/dynamix/banner.png');
|
||||
})
|
||||
test('get banner path returns the banner (state loaded)', async () => {
|
||||
await store.dispatch(loadDynamixConfigFile()).unwrap();
|
||||
await expect(getBannerPathIfPresent()).resolves.toContain('/dev/dynamix/banner.png');
|
||||
});
|
||||
|
||||
test('get banner path returns null when no banner (state loaded)', async () => {
|
||||
await store.dispatch(loadDynamixConfigFile()).unwrap();
|
||||
expect(getBannerPathIfPresent('notabanner.png')).resolves.toMatchInlineSnapshot('null');
|
||||
});
|
||||
await expect(getBannerPathIfPresent('notabanner.png')).resolves.toMatchInlineSnapshot('null');
|
||||
});
|
||||
|
||||
8
api/src/__test__/core/utils/misc/clean-stdout.test.ts
Normal file
8
api/src/__test__/core/utils/misc/clean-stdout.test.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { cleanStdout } from '@app/core/utils/misc/clean-stdout';
|
||||
|
||||
test('Returns trimmed stdout from execa command', () => {
|
||||
expect(cleanStdout({ stdout: 'test' })).toBe('test');
|
||||
expect(cleanStdout({ stdout: 'test ' })).toBe('test');
|
||||
});
|
||||
64
api/src/__test__/core/utils/misc/get-key-file.test.ts
Normal file
64
api/src/__test__/core/utils/misc/get-key-file.test.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { store } from '@app/store';
|
||||
import { FileLoadStatus, StateFileKey } from '@app/store/types';
|
||||
|
||||
import '@app/core/utils/misc/get-key-file';
|
||||
import '@app/store/modules/emhttp';
|
||||
|
||||
test('Before loading key returns null', async () => {
|
||||
const { getKeyFile } = await import('@app/core/utils/misc/get-key-file');
|
||||
const { status } = store.getState().registration;
|
||||
|
||||
expect(status).toBe(FileLoadStatus.UNLOADED);
|
||||
await expect(getKeyFile()).resolves.toBe(null);
|
||||
});
|
||||
|
||||
test('Requires emhttp to be loaded to find key file', async () => {
|
||||
const { getKeyFile } = await import('@app/core/utils/misc/get-key-file');
|
||||
const { loadRegistrationKey } = await import('@app/store/modules/registration');
|
||||
|
||||
// Load registration key into store
|
||||
await store.dispatch(loadRegistrationKey());
|
||||
|
||||
// Check if store has state files loaded
|
||||
const { status } = store.getState().registration;
|
||||
expect(status).toBe(FileLoadStatus.LOADED);
|
||||
await expect(getKeyFile()).resolves.toBe(null);
|
||||
});
|
||||
|
||||
test('Returns empty key if key location is empty', async () => {
|
||||
const { getKeyFile } = await import('@app/core/utils/misc/get-key-file');
|
||||
const { updateEmhttpState } = await import('@app/store/modules/emhttp');
|
||||
|
||||
// Set key file location as empty
|
||||
// This should only happen if the user doesn't have a key file
|
||||
store.dispatch(
|
||||
updateEmhttpState({
|
||||
field: StateFileKey.var,
|
||||
state: {
|
||||
regFile: '',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// Check if store has state files loaded
|
||||
const { status } = store.getState().registration;
|
||||
expect(status).toBe(FileLoadStatus.LOADED);
|
||||
await expect(getKeyFile()).resolves.toBe('');
|
||||
});
|
||||
|
||||
test('Returns decoded key file if key location exists', async () => {
|
||||
const { getKeyFile } = await import('@app/core/utils/misc/get-key-file');
|
||||
const { loadStateFiles } = await import('@app/store/modules/emhttp');
|
||||
|
||||
// Load state files into store
|
||||
await store.dispatch(loadStateFiles());
|
||||
|
||||
// Check if store has state files loaded
|
||||
const { status } = store.getState().registration;
|
||||
expect(status).toBe(FileLoadStatus.LOADED);
|
||||
await expect(getKeyFile()).resolves.toMatchInlineSnapshot(
|
||||
'"hVs1tLjvC9FiiQsIwIQ7G1KszAcexf0IneThhnmf22SB0dGs5WzRkqMiSMmt2DtR5HOXFUD32YyxuzGeUXmky3zKpSu6xhZNKVg5atGM1OfvkzHBMldI3SeBLuUFSgejLbpNUMdTrbk64JJdbzle4O8wiQgkIpAMIGxeYLwLBD4zHBcfyzq40QnxG--HcX6j25eE0xqa2zWj-j0b0rCAXahJV2a3ySCbPzr1MvfPRTVb0rr7KJ-25R592hYrz4H7Sc1B3p0lr6QUxHE6o7bcYrWKDRtIVoZ8SMPpd1_0gzYIcl5GsDFzFumTXUh8NEnl0Q8hwW1YE-tRc6Y_rrvd7w"'
|
||||
);
|
||||
});
|
||||
@@ -1,9 +1,11 @@
|
||||
import { test, expect } from 'vitest';
|
||||
import { parseConfig } from '@app/core/utils/misc/parse-config';
|
||||
import { Parser as MultiIniParser } from 'multi-ini';
|
||||
import { readFile, writeFile } from 'fs/promises';
|
||||
|
||||
import { parse } from 'ini';
|
||||
import { Parser as MultiIniParser } from 'multi-ini';
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { safelySerializeObjectToIni } from '@app/core/utils/files/safe-ini-serializer';
|
||||
import { parseConfig } from '@app/core/utils/misc/parse-config';
|
||||
|
||||
const iniTestData = `["root"]
|
||||
idx="0"
|
||||
@@ -22,11 +24,11 @@ desc=""
|
||||
passwd="no"`;
|
||||
|
||||
test('it loads a config from a passed in ini file successfully', () => {
|
||||
const res = parseConfig<any>({
|
||||
file: iniTestData,
|
||||
type: 'ini',
|
||||
});
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
const res = parseConfig<any>({
|
||||
file: iniTestData,
|
||||
type: 'ini',
|
||||
});
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
{
|
||||
"root": {
|
||||
"desc": "Console and webGui login account",
|
||||
@@ -48,26 +50,26 @@ test('it loads a config from a passed in ini file successfully', () => {
|
||||
},
|
||||
}
|
||||
`);
|
||||
expect(res?.root.desc).toEqual('Console and webGui login account');
|
||||
expect(res?.root.desc).toEqual('Console and webGui login account');
|
||||
});
|
||||
|
||||
test('it loads a config from disk properly', () => {
|
||||
const path = './dev/states/var.ini';
|
||||
const res = parseConfig<any>({ filePath: path, type: 'ini' });
|
||||
expect(res.DOMAIN_SHORT).toEqual(undefined);
|
||||
expect(res.domainShort).toEqual('');
|
||||
expect(res.shareCount).toEqual('0');
|
||||
const path = './dev/states/var.ini';
|
||||
const res = parseConfig<any>({ filePath: path, type: 'ini' });
|
||||
expect(res.DOMAIN_SHORT).toEqual(undefined);
|
||||
expect(res.domainShort).toEqual('');
|
||||
expect(res.shareCount).toEqual('0');
|
||||
});
|
||||
|
||||
test('Confirm Multi-Ini Parser Still Broken', () => {
|
||||
const parser = new MultiIniParser();
|
||||
const res = parser.parse(iniTestData);
|
||||
expect(res).toMatchInlineSnapshot('{}');
|
||||
const parser = new MultiIniParser();
|
||||
const res = parser.parse(iniTestData);
|
||||
expect(res).toMatchInlineSnapshot('{}');
|
||||
});
|
||||
|
||||
test('Combine Ini and Multi-Ini to read and then write a file with quotes', async () => {
|
||||
const parsedFile = parse(iniTestData);
|
||||
expect(parsedFile).toMatchInlineSnapshot(`
|
||||
const parsedFile = parse(iniTestData);
|
||||
expect(parsedFile).toMatchInlineSnapshot(`
|
||||
{
|
||||
"root": {
|
||||
"desc": "Console and webGui login account",
|
||||
@@ -90,10 +92,10 @@ test('Combine Ini and Multi-Ini to read and then write a file with quotes', asyn
|
||||
}
|
||||
`);
|
||||
|
||||
const ini = safelySerializeObjectToIni(parsedFile);
|
||||
await writeFile('/tmp/test.ini', ini);
|
||||
const file = await readFile('/tmp/test.ini', 'utf-8');
|
||||
expect(file).toMatchInlineSnapshot(`
|
||||
const ini = safelySerializeObjectToIni(parsedFile);
|
||||
await writeFile('/tmp/test.ini', ini);
|
||||
const file = await readFile('/tmp/test.ini', 'utf-8');
|
||||
expect(file).toMatchInlineSnapshot(`
|
||||
"[root]
|
||||
idx="0"
|
||||
name="root"
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { getShares } from '@app/core/utils/shares/get-shares';
|
||||
import { store } from '@app/store';
|
||||
import { loadStateFiles } from '@app/store/modules/emhttp';
|
||||
|
||||
test('Returns both disk and user shares', async () => {
|
||||
await store.dispatch(loadStateFiles());
|
||||
await store.dispatch(loadStateFiles());
|
||||
|
||||
expect(getShares()).toMatchInlineSnapshot(`
|
||||
expect(getShares()).toMatchInlineSnapshot(`
|
||||
{
|
||||
"disks": [],
|
||||
"users": [
|
||||
@@ -96,8 +97,8 @@ test('Returns both disk and user shares', async () => {
|
||||
});
|
||||
|
||||
test('Returns shares by type', async () => {
|
||||
await store.dispatch(loadStateFiles());
|
||||
expect(getShares('user')).toMatchInlineSnapshot(`
|
||||
await store.dispatch(loadStateFiles());
|
||||
expect(getShares('user')).toMatchInlineSnapshot(`
|
||||
{
|
||||
"allocator": "highwater",
|
||||
"cachePool": "cache",
|
||||
@@ -119,7 +120,7 @@ test('Returns shares by type', async () => {
|
||||
"used": 33619300,
|
||||
}
|
||||
`);
|
||||
expect(getShares('users')).toMatchInlineSnapshot(`
|
||||
expect(getShares('users')).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"allocator": "highwater",
|
||||
@@ -203,12 +204,12 @@ test('Returns shares by type', async () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(getShares('disk')).toMatchInlineSnapshot('null');
|
||||
expect(getShares('disks')).toMatchInlineSnapshot('[]');
|
||||
expect(getShares('disk')).toMatchInlineSnapshot('null');
|
||||
expect(getShares('disks')).toMatchInlineSnapshot('[]');
|
||||
});
|
||||
|
||||
test('Returns shares by name', async () => {
|
||||
expect(getShares('user', { name: 'domains' })).toMatchInlineSnapshot(`
|
||||
expect(getShares('user', { name: 'domains' })).toMatchInlineSnapshot(`
|
||||
{
|
||||
"allocator": "highwater",
|
||||
"cachePool": "cache",
|
||||
@@ -230,8 +231,8 @@ test('Returns shares by name', async () => {
|
||||
"used": 33619300,
|
||||
}
|
||||
`);
|
||||
expect(getShares('user', { name: 'non-existent-user-share' })).toMatchInlineSnapshot('null');
|
||||
// @TODO: disk shares need to be added to the dev ini files
|
||||
expect(getShares('disk', { name: 'disk1' })).toMatchInlineSnapshot('null');
|
||||
expect(getShares('disk', { name: 'non-existent-disk-share' })).toMatchInlineSnapshot('null');
|
||||
expect(getShares('user', { name: 'non-existent-user-share' })).toMatchInlineSnapshot('null');
|
||||
// @TODO: disk shares need to be added to the dev ini files
|
||||
expect(getShares('disk', { name: 'disk1' })).toMatchInlineSnapshot('null');
|
||||
expect(getShares('disk', { name: 'non-existent-disk-share' })).toMatchInlineSnapshot('null');
|
||||
});
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { afterEach, expect, test, vi } from 'vitest';
|
||||
|
||||
import { checkDNS } from '@app/graphql/resolvers/query/cloud/check-dns';
|
||||
import { store } from '@app/store';
|
||||
import { clearKey } from '@app/store/modules/cache';
|
||||
import { CacheKeys } from '@app/store/types';
|
||||
|
||||
afterEach(() => {
|
||||
store.dispatch(clearKey(CacheKeys.checkDns));
|
||||
});
|
||||
|
||||
test('it resolves dns successfully', async () => {
|
||||
// @TODO
|
||||
const dns = await checkDNS('example.com');
|
||||
expect(dns.cloudIp).not.toBeNull();
|
||||
}, 25_000);
|
||||
|
||||
test('testing twice results in a cache hit', async () => {
|
||||
// Hit mothership
|
||||
const getters = await import('@app/store/getters');
|
||||
const dnsSpy = vi.spyOn(getters, 'getDnsCache');
|
||||
const dns = await checkDNS();
|
||||
expect(dns.cloudIp).toBeTypeOf('string');
|
||||
expect(dnsSpy.mock.results[0]).toMatchInlineSnapshot(`
|
||||
{
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
}
|
||||
`);
|
||||
const dnslookup2 = await checkDNS();
|
||||
expect(dnslookup2.cloudIp).toEqual(dns.cloudIp);
|
||||
expect(dnsSpy.mock.results[1].value.cloudIp).toEqual(dns.cloudIp);
|
||||
expect(store.getState().cache.nodeCache.getTtl(CacheKeys.checkDns)).toBeGreaterThan(500);
|
||||
});
|
||||
@@ -1,10 +1,26 @@
|
||||
import 'reflect-metadata';
|
||||
import { checkMothershipAuthentication } from "@app/graphql/resolvers/query/cloud/check-mothership-authentication";
|
||||
import { expect, test } from "vitest";
|
||||
import packageJson from '@app/../package.json'
|
||||
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import packageJson from '@app/../package.json';
|
||||
import { checkMothershipAuthentication } from '@app/graphql/resolvers/query/cloud/check-mothership-authentication';
|
||||
|
||||
test('It fails to authenticate with mothership with no credentials', async () => {
|
||||
await expect(checkMothershipAuthentication('BAD', 'BAD')).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Failed to connect to https://mothership.unraid.net/ws with a "426" HTTP error.]`);
|
||||
expect(packageJson.version).not.toBeNull();
|
||||
await expect(checkMothershipAuthentication(packageJson.version, 'BAD_API_KEY')).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Invalid credentials]`);
|
||||
}, 15_000)
|
||||
try {
|
||||
await expect(
|
||||
checkMothershipAuthentication('BAD', 'BAD')
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`[Error: Failed to connect to https://mothership.unraid.net/ws with a "426" HTTP error.]`
|
||||
);
|
||||
expect(packageJson.version).not.toBeNull();
|
||||
await expect(
|
||||
checkMothershipAuthentication(packageJson.version, 'BAD_API_KEY')
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Invalid credentials]`);
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.message.includes('Timeout')) {
|
||||
// Test succeeds on timeout
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,124 +1,197 @@
|
||||
import { expect, test } from 'vitest';
|
||||
import { type Nginx } from '../../../../core/types/states/nginx';
|
||||
import { getUrlForField, getUrlForServer, getServerIps, type NginxUrlFields } from '@app/graphql/resolvers/subscription/network';
|
||||
|
||||
import type { NginxUrlFields } from '@app/graphql/resolvers/subscription/network';
|
||||
import { type Nginx } from '@app/core/types/states/nginx';
|
||||
import {
|
||||
getServerIps,
|
||||
getUrlForField,
|
||||
getUrlForServer,
|
||||
} from '@app/graphql/resolvers/subscription/network';
|
||||
import { store } from '@app/store';
|
||||
import { loadStateFiles } from '@app/store/modules/emhttp';
|
||||
import { loadConfigFile } from '@app/store/modules/config';
|
||||
import { loadStateFiles } from '@app/store/modules/emhttp';
|
||||
|
||||
test.each([
|
||||
[{ httpPort: 80, httpsPort: 443, url: 'my-default-url.com' }],
|
||||
[{ httpPort: 123, httpsPort: 443, url: 'my-default-url.com' }],
|
||||
[{ httpPort: 80, httpsPort: 12_345, url: 'my-default-url.com' }],
|
||||
[{ httpPort: 212, httpsPort: 3_233, url: 'my-default-url.com' }],
|
||||
[{ httpPort: 80, httpsPort: 443, url: 'https://BROKEN_URL' }],
|
||||
|
||||
[{ httpPort: 80, httpsPort: 443, url: 'my-default-url.com' }],
|
||||
[{ httpPort: 123, httpsPort: 443, url: 'my-default-url.com' }],
|
||||
[{ httpPort: 80, httpsPort: 12_345, url: 'my-default-url.com' }],
|
||||
[{ httpPort: 212, httpsPort: 3_233, url: 'my-default-url.com' }],
|
||||
[{ httpPort: 80, httpsPort: 443, url: 'https://BROKEN_URL' }],
|
||||
])('getUrlForField', ({ httpPort, httpsPort, url }) => {
|
||||
const responseInsecure = getUrlForField({
|
||||
port: httpPort,
|
||||
url,
|
||||
});
|
||||
const responseInsecure = getUrlForField({
|
||||
port: httpPort,
|
||||
url,
|
||||
});
|
||||
|
||||
const responseSecure = getUrlForField({
|
||||
portSsl: httpsPort,
|
||||
url,
|
||||
});
|
||||
if (httpPort === 80) {
|
||||
expect(responseInsecure.port).toBe('');
|
||||
} else {
|
||||
expect(responseInsecure.port).toBe(httpPort.toString());
|
||||
}
|
||||
const responseSecure = getUrlForField({
|
||||
portSsl: httpsPort,
|
||||
url,
|
||||
});
|
||||
if (httpPort === 80) {
|
||||
expect(responseInsecure.port).toBe('');
|
||||
} else {
|
||||
expect(responseInsecure.port).toBe(httpPort.toString());
|
||||
}
|
||||
|
||||
if (httpsPort === 443) {
|
||||
expect(responseSecure.port).toBe('');
|
||||
} else {
|
||||
expect(responseSecure.port).toBe(httpsPort.toString());
|
||||
}
|
||||
if (httpsPort === 443) {
|
||||
expect(responseSecure.port).toBe('');
|
||||
} else {
|
||||
expect(responseSecure.port).toBe(httpsPort.toString());
|
||||
}
|
||||
});
|
||||
|
||||
test('getUrlForServer - field exists, ssl disabled', () => {
|
||||
const result = getUrlForServer({ nginx: { lanIp: '192.168.1.1', sslEnabled: false, httpPort: 123, httpsPort: 445 } as const as Nginx,
|
||||
field: 'lanIp',
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot('"http://192.168.1.1:123/"');
|
||||
const result = getUrlForServer({
|
||||
nginx: {
|
||||
lanIp: '192.168.1.1',
|
||||
sslEnabled: false,
|
||||
httpPort: 123,
|
||||
httpsPort: 445,
|
||||
} as const as Nginx,
|
||||
field: 'lanIp',
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot('"http://192.168.1.1:123/"');
|
||||
});
|
||||
|
||||
test('getUrlForServer - field exists, ssl yes', () => {
|
||||
const result = getUrlForServer({
|
||||
nginx: { lanIp: '192.168.1.1', sslEnabled: true, sslMode: 'yes', httpPort: 123, httpsPort: 445 } as const as Nginx,
|
||||
field: 'lanIp',
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot('"https://192.168.1.1:445/"');
|
||||
const result = getUrlForServer({
|
||||
nginx: {
|
||||
lanIp: '192.168.1.1',
|
||||
sslEnabled: true,
|
||||
sslMode: 'yes',
|
||||
httpPort: 123,
|
||||
httpsPort: 445,
|
||||
} as const as Nginx,
|
||||
field: 'lanIp',
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot('"https://192.168.1.1:445/"');
|
||||
});
|
||||
|
||||
test('getUrlForServer - field exists, ssl yes, port empty', () => {
|
||||
const result = getUrlForServer(
|
||||
{ nginx: { lanIp: '192.168.1.1', sslEnabled: true, sslMode: 'yes', httpPort: 80, httpsPort: 443 } as const as Nginx,
|
||||
field: 'lanIp',
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot('"https://192.168.1.1/"');
|
||||
const result = getUrlForServer({
|
||||
nginx: {
|
||||
lanIp: '192.168.1.1',
|
||||
sslEnabled: true,
|
||||
sslMode: 'yes',
|
||||
httpPort: 80,
|
||||
httpsPort: 443,
|
||||
} as const as Nginx,
|
||||
field: 'lanIp',
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot('"https://192.168.1.1/"');
|
||||
});
|
||||
|
||||
test('getUrlForServer - field exists, ssl auto', () => {
|
||||
const getResult = async () => getUrlForServer({
|
||||
nginx: { lanIp: '192.168.1.1', sslEnabled: true, sslMode: 'auto', httpPort: 123, httpsPort: 445 } as const as Nginx,
|
||||
field: 'lanIp',
|
||||
});
|
||||
void expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Cannot get IP Based URL for field: "lanIp" SSL mode auto]`);
|
||||
test('getUrlForServer - field exists, ssl auto', async () => {
|
||||
const getResult = async () =>
|
||||
getUrlForServer({
|
||||
nginx: {
|
||||
lanIp: '192.168.1.1',
|
||||
sslEnabled: true,
|
||||
sslMode: 'auto',
|
||||
httpPort: 123,
|
||||
httpsPort: 445,
|
||||
} as const as Nginx,
|
||||
field: 'lanIp',
|
||||
});
|
||||
await expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`[Error: Cannot get IP Based URL for field: "lanIp" SSL mode auto]`
|
||||
);
|
||||
});
|
||||
|
||||
test('getUrlForServer - field does not exist, ssl disabled', () => {
|
||||
const getResult = async () => getUrlForServer(
|
||||
{
|
||||
nginx: { lanIp: '192.168.1.1', sslEnabled: false, sslMode: 'no' } as const as Nginx,
|
||||
ports: {
|
||||
port: ':123', portSsl: ':445', defaultUrl: new URL('https://my-default-url.unraid.net'),
|
||||
},
|
||||
// @ts-expect-error Field doesn't exist
|
||||
field: 'idontexist',
|
||||
});
|
||||
void expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: IP URL Resolver: Could not resolve any access URL for field: "idontexist", is FQDN?: false]`);
|
||||
test('getUrlForServer - field does not exist, ssl disabled', async () => {
|
||||
const getResult = async () =>
|
||||
getUrlForServer({
|
||||
nginx: { lanIp: '192.168.1.1', sslEnabled: false, sslMode: 'no' } as const as Nginx,
|
||||
ports: {
|
||||
port: ':123',
|
||||
portSsl: ':445',
|
||||
defaultUrl: new URL('https://my-default-url.unraid.net'),
|
||||
},
|
||||
// @ts-expect-error Field doesn't exist
|
||||
field: 'idontexist',
|
||||
});
|
||||
await expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`[Error: IP URL Resolver: Could not resolve any access URL for field: "idontexist", is FQDN?: false]`
|
||||
);
|
||||
});
|
||||
|
||||
test('getUrlForServer - FQDN - field exists, port non-empty', () => {
|
||||
const result = getUrlForServer({
|
||||
nginx: { lanFqdn: 'my-fqdn.unraid.net', httpsPort: 445 } as const as Nginx,
|
||||
field: 'lanFqdn',
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot('"https://my-fqdn.unraid.net:445/"');
|
||||
const result = getUrlForServer({
|
||||
nginx: { lanFqdn: 'my-fqdn.unraid.net', httpsPort: 445 } as const as Nginx,
|
||||
field: 'lanFqdn',
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot('"https://my-fqdn.unraid.net:445/"');
|
||||
});
|
||||
|
||||
test('getUrlForServer - FQDN - field exists, port empty', () => {
|
||||
const result = getUrlForServer({ nginx: { lanFqdn: 'my-fqdn.unraid.net', httpPort: 80, httpsPort: 443 } as const as Nginx,
|
||||
field: 'lanFqdn',
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot('"https://my-fqdn.unraid.net/"');
|
||||
const result = getUrlForServer({
|
||||
nginx: { lanFqdn: 'my-fqdn.unraid.net', httpPort: 80, httpsPort: 443 } as const as Nginx,
|
||||
field: 'lanFqdn',
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot('"https://my-fqdn.unraid.net/"');
|
||||
});
|
||||
|
||||
test.each([
|
||||
[{ nginx: { lanFqdn: 'my-fqdn.unraid.net', sslEnabled: false, sslMode: 'no', httpPort: 80, httpsPort: 443 } as const as Nginx, field: 'lanFqdn' as NginxUrlFields }],
|
||||
[{ nginx: { wanFqdn: 'my-fqdn.unraid.net', sslEnabled: true, sslMode: 'yes', httpPort: 80, httpsPort: 443 } as const as Nginx, field: 'wanFqdn' as NginxUrlFields }],
|
||||
[{ nginx: { wanFqdn6: 'my-fqdn.unraid.net', sslEnabled: true, sslMode: 'auto', httpPort: 80, httpsPort: 443 } as const as Nginx, field: 'wanFqdn6' as NginxUrlFields }],
|
||||
|
||||
[
|
||||
{
|
||||
nginx: {
|
||||
lanFqdn: 'my-fqdn.unraid.net',
|
||||
sslEnabled: false,
|
||||
sslMode: 'no',
|
||||
httpPort: 80,
|
||||
httpsPort: 443,
|
||||
} as const as Nginx,
|
||||
field: 'lanFqdn' as NginxUrlFields,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
nginx: {
|
||||
wanFqdn: 'my-fqdn.unraid.net',
|
||||
sslEnabled: true,
|
||||
sslMode: 'yes',
|
||||
httpPort: 80,
|
||||
httpsPort: 443,
|
||||
} as const as Nginx,
|
||||
field: 'wanFqdn' as NginxUrlFields,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
nginx: {
|
||||
wanFqdn6: 'my-fqdn.unraid.net',
|
||||
sslEnabled: true,
|
||||
sslMode: 'auto',
|
||||
httpPort: 80,
|
||||
httpsPort: 443,
|
||||
} as const as Nginx,
|
||||
field: 'wanFqdn6' as NginxUrlFields,
|
||||
},
|
||||
],
|
||||
])('getUrlForServer - FQDN', ({ nginx, field }) => {
|
||||
const result = getUrlForServer({ nginx, field });
|
||||
expect(result.toString()).toBe('https://my-fqdn.unraid.net/');
|
||||
const result = getUrlForServer({ nginx, field });
|
||||
expect(result.toString()).toBe('https://my-fqdn.unraid.net/');
|
||||
});
|
||||
|
||||
test('getUrlForServer - field does not exist, ssl disabled', () => {
|
||||
const getResult = async () => getUrlForServer({ nginx:
|
||||
{ lanFqdn: 'my-fqdn.unraid.net' } as const as Nginx,
|
||||
ports: { portSsl: '', port: '', defaultUrl: new URL('https://my-default-url.unraid.net') },
|
||||
// @ts-expect-error Field doesn't exist
|
||||
field: 'idontexist' });
|
||||
void expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: IP URL Resolver: Could not resolve any access URL for field: "idontexist", is FQDN?: false]`);
|
||||
test('getUrlForServer - field does not exist, ssl disabled', async () => {
|
||||
const getResult = async () =>
|
||||
getUrlForServer({
|
||||
nginx: { lanFqdn: 'my-fqdn.unraid.net' } as const as Nginx,
|
||||
ports: { portSsl: '', port: '', defaultUrl: new URL('https://my-default-url.unraid.net') },
|
||||
// @ts-expect-error Field doesn't exist
|
||||
field: 'idontexist',
|
||||
});
|
||||
await expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
`[Error: IP URL Resolver: Could not resolve any access URL for field: "idontexist", is FQDN?: false]`
|
||||
);
|
||||
});
|
||||
|
||||
test('integration test, loading nginx ini and generating all URLs', async () => {
|
||||
await store.dispatch(loadStateFiles());
|
||||
await store.dispatch(loadConfigFile());
|
||||
await store.dispatch(loadStateFiles());
|
||||
await store.dispatch(loadConfigFile());
|
||||
|
||||
const urls = getServerIps();
|
||||
expect(urls.urls).toMatchInlineSnapshot(`
|
||||
const urls = getServerIps();
|
||||
expect(urls.urls).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"ipv4": "https://tower.local:4443/",
|
||||
@@ -198,7 +271,7 @@ test('integration test, loading nginx ini and generating all URLs', async () =>
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(urls.errors).toMatchInlineSnapshot(`
|
||||
expect(urls.errors).toMatchInlineSnapshot(`
|
||||
[
|
||||
[Error: IP URL Resolver: Could not resolve any access URL for field: "lanIp6", is FQDN?: false],
|
||||
]
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
import { API_KEY_STATUS } from '@app/mothership/api-key/api-key-types';
|
||||
import * as apiKeyCheckJobs from '@app/mothership/jobs/api-key-check-jobs';
|
||||
import * as apiKeyValidator from '@app/mothership/api-key/validate-api-key-with-keyserver';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { type RecursivePartial } from '@app/types/index';
|
||||
import { type RootState } from '@app/store/index';
|
||||
import { logoutUser } from '@app/store/modules/config';
|
||||
|
||||
describe('apiKeyCheckJob Tests', () => {
|
||||
it('API Check Job (with success)', async () => {
|
||||
const getState = vi.fn<[], RecursivePartial<RootState>>().mockReturnValue({
|
||||
apiKey: { status: API_KEY_STATUS.PENDING_VALIDATION },
|
||||
config: { remote: { apikey: '_______________________BIG_API_KEY_HERE_________________________' } },
|
||||
emhttp: { var: { flashGuid: 'my-flash-guid', version: '6.11.5' } },
|
||||
});
|
||||
|
||||
const dispatch = vi.fn();
|
||||
|
||||
const validationSpy = vi.spyOn(apiKeyValidator, 'validateApiKeyWithKeyServer').mockResolvedValue(API_KEY_STATUS.API_KEY_VALID);
|
||||
|
||||
await expect(apiKeyCheckJobs.apiKeyCheckJob(getState, dispatch)).resolves.toBe(true);
|
||||
|
||||
expect(validationSpy).toHaveBeenCalledOnce();
|
||||
|
||||
expect(dispatch).toHaveBeenLastCalledWith({
|
||||
payload: API_KEY_STATUS.API_KEY_VALID,
|
||||
type: 'apiKey/setApiKeyState',
|
||||
});
|
||||
});
|
||||
|
||||
it('API Check Job (with invalid length key)', async () => {
|
||||
// Setup state
|
||||
const getState = vi.fn<[], RecursivePartial<RootState>>().mockReturnValue({
|
||||
apiKey: { status: API_KEY_STATUS.PENDING_VALIDATION },
|
||||
config: { remote: { apikey: 'too-short-key' } },
|
||||
emhttp: { var: { flashGuid: 'my-flash-guid', version: '6.11.5' } },
|
||||
});
|
||||
|
||||
const dispatch = vi.fn();
|
||||
|
||||
const validationSpy = vi.spyOn(apiKeyValidator, 'validateApiKeyWithKeyServer').mockResolvedValue(API_KEY_STATUS.API_KEY_VALID);
|
||||
|
||||
await expect(apiKeyCheckJobs.apiKeyCheckJob(getState, dispatch)).resolves.toBe(false);
|
||||
expect(dispatch).toHaveBeenCalledWith(expect.any(Function));
|
||||
|
||||
expect(validationSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('API Check Job (with a failure that throws an error - NETWORK_ERROR)', async () => {
|
||||
const getState = vi.fn<[], RecursivePartial<RootState>>().mockReturnValue({
|
||||
apiKey: { status: API_KEY_STATUS.PENDING_VALIDATION },
|
||||
config: { remote: { apikey: '_______________________BIG_API_KEY_HERE_________________________' } },
|
||||
emhttp: { var: { flashGuid: 'my-flash-guid', version: '6.11.5' } },
|
||||
});
|
||||
|
||||
const dispatch = vi.fn();
|
||||
|
||||
const validationSpy = vi.spyOn(apiKeyValidator, 'validateApiKeyWithKeyServer')
|
||||
.mockResolvedValueOnce(API_KEY_STATUS.NETWORK_ERROR);
|
||||
|
||||
await expect(apiKeyCheckJobs.apiKeyCheckJob(getState, dispatch)).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Keyserver Failure, must retry]`);
|
||||
|
||||
expect(validationSpy).toHaveBeenCalledOnce();
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith({
|
||||
payload: API_KEY_STATUS.NETWORK_ERROR,
|
||||
type: 'apiKey/setApiKeyState',
|
||||
});
|
||||
});
|
||||
|
||||
it('API Check Job (with a failure that throws an error - INVALID_RESPONSE)', async () => {
|
||||
const getState = vi.fn<[], RecursivePartial<RootState>>().mockReturnValue({
|
||||
apiKey: { status: API_KEY_STATUS.PENDING_VALIDATION },
|
||||
config: { remote: { apikey: '_______________________BIG_API_KEY_HERE_________________________' } },
|
||||
emhttp: { var: { flashGuid: 'my-flash-guid', version: '6.11.5' } },
|
||||
});
|
||||
|
||||
const dispatch = vi.fn();
|
||||
|
||||
const validationSpy = vi.spyOn(apiKeyValidator, 'validateApiKeyWithKeyServer')
|
||||
.mockResolvedValueOnce(API_KEY_STATUS.INVALID_KEYSERVER_RESPONSE);
|
||||
|
||||
await expect(apiKeyCheckJobs.apiKeyCheckJob(getState, dispatch)).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Keyserver Failure, must retry]`);
|
||||
|
||||
expect(validationSpy).toHaveBeenCalledOnce();
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith({
|
||||
payload: API_KEY_STATUS.INVALID_KEYSERVER_RESPONSE,
|
||||
type: 'apiKey/setApiKeyState',
|
||||
});
|
||||
}, 10_000);
|
||||
|
||||
it('API Check Job (with failure that results in a log out)', async () => {
|
||||
const getState = vi.fn<[], RecursivePartial<RootState>>().mockReturnValue({
|
||||
apiKey: { status: API_KEY_STATUS.PENDING_VALIDATION },
|
||||
config: { remote: { apikey: '_______________________BIG_API_KEY_HERE_________________________' } },
|
||||
emhttp: { var: { flashGuid: 'my-flash-guid', version: '6.11.5' } },
|
||||
});
|
||||
|
||||
const dispatch = vi.fn();
|
||||
|
||||
const validationSpy = vi.spyOn(apiKeyValidator, 'validateApiKeyWithKeyServer')
|
||||
.mockResolvedValue(API_KEY_STATUS.API_KEY_INVALID);
|
||||
|
||||
await expect(apiKeyCheckJobs.apiKeyCheckJob(getState, dispatch)).resolves.toBe(false);
|
||||
|
||||
expect(validationSpy).toHaveBeenCalledOnce();
|
||||
expect(dispatch).toHaveBeenCalledTimes(1);
|
||||
expect(dispatch).toHaveBeenCalledWith(expect.any(Function));
|
||||
}, 10_000);
|
||||
});
|
||||
@@ -4,45 +4,45 @@ import { beforeEach, expect, test, vi } from 'vitest';
|
||||
import '@app/mothership/utils/convert-to-fuzzy-time';
|
||||
|
||||
vi.mock('fs', () => ({
|
||||
default: {
|
||||
readFileSync: vi.fn().mockReturnValue('my-file'),
|
||||
writeFileSync: vi.fn(),
|
||||
existsSync: vi.fn(),
|
||||
},
|
||||
readFileSync: vi.fn().mockReturnValue('my-file'),
|
||||
existsSync: vi.fn(),
|
||||
default: {
|
||||
readFileSync: vi.fn().mockReturnValue('my-file'),
|
||||
writeFileSync: vi.fn(),
|
||||
existsSync: vi.fn(),
|
||||
},
|
||||
readFileSync: vi.fn().mockReturnValue('my-file'),
|
||||
existsSync: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@graphql-tools/schema', () => ({
|
||||
makeExecutableSchema: vi.fn(),
|
||||
makeExecutableSchema: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@app/core/log', () => ({
|
||||
default: { relayLogger: { trace: vi.fn() } },
|
||||
relayLogger: { trace: vi.fn() },
|
||||
logger: { trace: vi.fn() },
|
||||
default: { relayLogger: { trace: vi.fn() } },
|
||||
relayLogger: { trace: vi.fn() },
|
||||
logger: { trace: vi.fn() },
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
vi.clearAllMocks();
|
||||
vi.resetModules();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
const generateTestCases = () => {
|
||||
const cases: Array<{ min: number; max: number }> = [];
|
||||
for (let i = 0; i < 15; i += 1) {
|
||||
const min = Math.round(Math.random() * 100);
|
||||
const max = min + (Math.round(Math.random() * 20));
|
||||
cases.push({ min, max });
|
||||
}
|
||||
const cases: Array<{ min: number; max: number }> = [];
|
||||
for (let i = 0; i < 15; i += 1) {
|
||||
const min = Math.round(Math.random() * 100);
|
||||
const max = min + Math.round(Math.random() * 20);
|
||||
cases.push({ min, max });
|
||||
}
|
||||
|
||||
return cases;
|
||||
return cases;
|
||||
};
|
||||
|
||||
test.each(generateTestCases())('Successfully converts to fuzzy time %o', async ({ min, max }) => {
|
||||
const { convertToFuzzyTime } = await import('@app/mothership/utils/convert-to-fuzzy-time');
|
||||
const { convertToFuzzyTime } = await import('@app/mothership/utils/convert-to-fuzzy-time');
|
||||
|
||||
const res = convertToFuzzyTime(min, max);
|
||||
expect(res).toBeGreaterThanOrEqual(min);
|
||||
expect(res).toBeLessThanOrEqual(max);
|
||||
const res = convertToFuzzyTime(min, max);
|
||||
expect(res).toBeGreaterThanOrEqual(min);
|
||||
expect(res).toBeLessThanOrEqual(max);
|
||||
});
|
||||
|
||||
6
api/src/__test__/setup/child-process-easy-to-kill.js
Executable file
6
api/src/__test__/setup/child-process-easy-to-kill.js
Executable file
@@ -0,0 +1,6 @@
|
||||
/* eslint-disable */
|
||||
process.title = 'unraid-api';
|
||||
|
||||
setInterval(() => {
|
||||
console.log('I NEED TO DIE');
|
||||
}, 5_000);
|
||||
10
api/src/__test__/setup/child-process-hard-to-kill.js
Normal file
10
api/src/__test__/setup/child-process-hard-to-kill.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/* eslint-disable */
|
||||
process.title = 'unraid-api';
|
||||
setInterval(() => {
|
||||
console.log('I NEED TO DIE (but i am very hard to kill)');
|
||||
}, 5_000);
|
||||
|
||||
process.on('SIGTERM', () => {
|
||||
// Do nothing
|
||||
console.log('you cant kill me haha');
|
||||
});
|
||||
7
api/src/__test__/setup/env-setup.ts
Normal file
7
api/src/__test__/setup/env-setup.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { config } from 'dotenv';
|
||||
|
||||
config({
|
||||
path: './.env.test',
|
||||
debug: false,
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
6
api/src/__test__/setup/keyserver-mock.ts
Normal file
6
api/src/__test__/setup/keyserver-mock.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { vi } from 'vitest';
|
||||
|
||||
vi.mock('@app/core/utils/misc/send-form-to-keyserver', () => {
|
||||
const sendFormToKeyServer = vi.fn().mockResolvedValue({ body: JSON.stringify({ valid: true }) });
|
||||
return { sendFormToKeyServer };
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`Before init returns default values for all fields 1`] = `
|
||||
{
|
||||
"api": {
|
||||
"extraOrigins": "",
|
||||
"version": "",
|
||||
},
|
||||
"connectionStatus": {
|
||||
"minigraph": "PRE_INIT",
|
||||
"upnpStatus": "",
|
||||
},
|
||||
"local": {
|
||||
"sandbox": "no",
|
||||
},
|
||||
"nodeEnv": "test",
|
||||
"remote": {
|
||||
"accesstoken": "",
|
||||
"allowedOrigins": "",
|
||||
"apikey": "",
|
||||
"avatar": "",
|
||||
"dynamicRemoteAccessType": "DISABLED",
|
||||
"email": "",
|
||||
"idtoken": "",
|
||||
"localApiKey": "",
|
||||
"refreshtoken": "",
|
||||
"regWizTime": "",
|
||||
"ssoSubIds": "",
|
||||
"upnpEnabled": "",
|
||||
"username": "",
|
||||
"wanaccess": "",
|
||||
"wanport": "",
|
||||
},
|
||||
"status": "UNLOADED",
|
||||
}
|
||||
`;
|
||||
@@ -6,7 +6,7 @@ exports[`loads notifications properly 1`] = `
|
||||
"description": "Canceled",
|
||||
"id": "/app/dev/notifications/unread/Unraid_Parity_check_1683971161.notify",
|
||||
"importance": "WARNING",
|
||||
"link": undefined,
|
||||
"link": "/",
|
||||
"subject": "Notice [UNRAID] - Parity check finished (0 errors)",
|
||||
"timestamp": "2023-05-13T09:46:01.000Z",
|
||||
"title": "Unraid Parity check",
|
||||
|
||||
@@ -1,48 +1,11 @@
|
||||
import { test, expect } from 'vitest';
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { store } from '@app/store';
|
||||
import { MyServersConfigMemory } from '@app/types/my-servers-config';
|
||||
|
||||
test('Before init returns default values for all fields', async () => {
|
||||
const state = store.getState().config;
|
||||
expect(state).toMatchInlineSnapshot(`
|
||||
{
|
||||
"api": {
|
||||
"extraOrigins": "",
|
||||
"version": "",
|
||||
},
|
||||
"connectionStatus": {
|
||||
"minigraph": "PRE_INIT",
|
||||
"upnpStatus": "",
|
||||
},
|
||||
"local": {
|
||||
"2Fa": "",
|
||||
"showT2Fa": "",
|
||||
},
|
||||
"nodeEnv": "test",
|
||||
"notifier": {
|
||||
"apikey": "",
|
||||
},
|
||||
"remote": {
|
||||
"2Fa": "",
|
||||
"accesstoken": "",
|
||||
"allowedOrigins": "",
|
||||
"apikey": "",
|
||||
"avatar": "",
|
||||
"dynamicRemoteAccessType": "DISABLED",
|
||||
"email": "",
|
||||
"idtoken": "",
|
||||
"refreshtoken": "",
|
||||
"regWizTime": "",
|
||||
"upnpEnabled": "",
|
||||
"username": "",
|
||||
"wanaccess": "",
|
||||
"wanport": "",
|
||||
},
|
||||
"status": "UNLOADED",
|
||||
"upc": {
|
||||
"apikey": "",
|
||||
},
|
||||
}
|
||||
`);
|
||||
expect(state).toMatchSnapshot();
|
||||
}, 10_000);
|
||||
|
||||
test('After init returns values from cfg file for all fields', async () => {
|
||||
@@ -64,15 +27,10 @@ test('After init returns values from cfg file for all fields', async () => {
|
||||
upnpStatus: '',
|
||||
},
|
||||
local: {
|
||||
'2Fa': '',
|
||||
showT2Fa: '',
|
||||
sandbox: expect.any(String),
|
||||
},
|
||||
nodeEnv: 'test',
|
||||
notifier: {
|
||||
apikey: 'unnotify_30994bfaccf839c65bae75f7fa12dd5ee16e69389f754c3b98ed7d5',
|
||||
},
|
||||
remote: {
|
||||
'2Fa': '',
|
||||
accesstoken: '',
|
||||
allowedOrigins: '',
|
||||
apikey: '_______________________BIG_API_KEY_HERE_________________________',
|
||||
@@ -80,25 +38,22 @@ test('After init returns values from cfg file for all fields', async () => {
|
||||
dynamicRemoteAccessType: 'DISABLED',
|
||||
email: 'test@example.com',
|
||||
idtoken: '',
|
||||
localApiKey: '_______________________LOCAL_API_KEY_HERE_________________________',
|
||||
refreshtoken: '',
|
||||
regWizTime: '1611175408732_0951-1653-3509-FBA155FA23C0',
|
||||
ssoSubIds: '',
|
||||
upnpEnabled: 'no',
|
||||
username: 'zspearmint',
|
||||
wanaccess: 'yes',
|
||||
wanport: '8443',
|
||||
},
|
||||
status: 'LOADED',
|
||||
upc: {
|
||||
apikey: 'unupc_fab6ff6ffe51040595c6d9ffb63a353ba16cc2ad7d93f813a2e80a5810',
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test('updateUserConfig merges in changes to current state', async () => {
|
||||
const { loadConfigFile, updateUserConfig } = await import(
|
||||
'@app/store/modules/config'
|
||||
);
|
||||
const { loadConfigFile, updateUserConfig } = await import('@app/store/modules/config');
|
||||
|
||||
// Load cfg into store
|
||||
await store.dispatch(loadConfigFile());
|
||||
@@ -122,15 +77,10 @@ test('updateUserConfig merges in changes to current state', async () => {
|
||||
upnpStatus: '',
|
||||
},
|
||||
local: {
|
||||
'2Fa': '',
|
||||
showT2Fa: '',
|
||||
sandbox: expect.any(String),
|
||||
},
|
||||
nodeEnv: 'test',
|
||||
notifier: {
|
||||
apikey: 'unnotify_30994bfaccf839c65bae75f7fa12dd5ee16e69389f754c3b98ed7d5',
|
||||
},
|
||||
remote: {
|
||||
'2Fa': '',
|
||||
accesstoken: '',
|
||||
allowedOrigins: '',
|
||||
apikey: '_______________________BIG_API_KEY_HERE_________________________',
|
||||
@@ -138,17 +88,16 @@ test('updateUserConfig merges in changes to current state', async () => {
|
||||
dynamicRemoteAccessType: 'DISABLED',
|
||||
email: 'test@example.com',
|
||||
idtoken: '',
|
||||
localApiKey: '_______________________LOCAL_API_KEY_HERE_________________________',
|
||||
refreshtoken: '',
|
||||
regWizTime: '1611175408732_0951-1653-3509-FBA155FA23C0',
|
||||
ssoSubIds: '',
|
||||
upnpEnabled: 'no',
|
||||
username: 'zspearmint',
|
||||
wanaccess: 'yes',
|
||||
wanport: '8443',
|
||||
},
|
||||
status: 'LOADED',
|
||||
upc: {
|
||||
apikey: 'unupc_fab6ff6ffe51040595c6d9ffb63a353ba16cc2ad7d93f813a2e80a5810',
|
||||
},
|
||||
})
|
||||
} as MyServersConfigMemory)
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { test, expect } from 'vitest';
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { store } from '@app/store';
|
||||
import { FileLoadStatus } from '@app/store/types';
|
||||
|
||||
@@ -6,9 +7,9 @@ import { FileLoadStatus } from '@app/store/types';
|
||||
import '@app/store/modules/emhttp';
|
||||
|
||||
test('Before init returns default values for all fields', async () => {
|
||||
const { status, ...state } = store.getState().emhttp;
|
||||
expect(status).toBe(FileLoadStatus.UNLOADED);
|
||||
expect(state).toMatchInlineSnapshot(`
|
||||
const { status, ...state } = store.getState().emhttp;
|
||||
expect(status).toBe(FileLoadStatus.UNLOADED);
|
||||
expect(state).toMatchInlineSnapshot(`
|
||||
{
|
||||
"devices": [],
|
||||
"disks": [],
|
||||
@@ -24,16 +25,27 @@ test('Before init returns default values for all fields', async () => {
|
||||
});
|
||||
|
||||
test('After init returns values from cfg file for all fields', async () => {
|
||||
const { loadStateFiles } = await import('@app/store/modules/emhttp');
|
||||
const { loadStateFiles } = await import('@app/store/modules/emhttp');
|
||||
|
||||
// Load state files into store
|
||||
await store.dispatch(loadStateFiles());
|
||||
// Load state files into store
|
||||
await store.dispatch(loadStateFiles());
|
||||
|
||||
// Check if store has state files loaded
|
||||
const { devices, networks, nfsShares, nginx, shares, disks, smbShares, status, users, var: varState } = store.getState().emhttp;
|
||||
expect(status).toBe(FileLoadStatus.LOADED);
|
||||
expect(devices).toMatchInlineSnapshot('[]');
|
||||
expect(networks).toMatchInlineSnapshot(`
|
||||
// Check if store has state files loaded
|
||||
const {
|
||||
devices,
|
||||
networks,
|
||||
nfsShares,
|
||||
nginx,
|
||||
shares,
|
||||
disks,
|
||||
smbShares,
|
||||
status,
|
||||
users,
|
||||
var: varState,
|
||||
} = store.getState().emhttp;
|
||||
expect(status).toBe(FileLoadStatus.LOADED);
|
||||
expect(devices).toMatchInlineSnapshot('[]');
|
||||
expect(networks).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"bonding": true,
|
||||
@@ -99,7 +111,7 @@ test('After init returns values from cfg file for all fields', async () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(nginx).toMatchInlineSnapshot(`
|
||||
expect(nginx).toMatchInlineSnapshot(`
|
||||
{
|
||||
"certificateName": "*.thisisfourtyrandomcharacters012345678900.myunraid.net",
|
||||
"certificatePath": "/boot/config/ssl/certs/certificate_bundle.pem",
|
||||
@@ -184,7 +196,7 @@ test('After init returns values from cfg file for all fields', async () => {
|
||||
"wanIp": "",
|
||||
}
|
||||
`);
|
||||
expect(disks).toMatchInlineSnapshot(`
|
||||
expect(disks).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"comment": null,
|
||||
@@ -356,7 +368,7 @@ test('After init returns values from cfg file for all fields', async () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(shares).toMatchInlineSnapshot(`
|
||||
expect(shares).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"allocator": "highwater",
|
||||
@@ -432,7 +444,7 @@ test('After init returns values from cfg file for all fields', async () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(nfsShares).toMatchInlineSnapshot(`
|
||||
expect(nfsShares).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"enabled": false,
|
||||
@@ -620,7 +632,7 @@ test('After init returns values from cfg file for all fields', async () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(smbShares).toMatchInlineSnapshot(`
|
||||
expect(smbShares).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
@@ -911,7 +923,7 @@ test('After init returns values from cfg file for all fields', async () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(users).toMatchInlineSnapshot(`
|
||||
expect(users).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"description": "Console and webGui login account",
|
||||
@@ -936,7 +948,7 @@ test('After init returns values from cfg file for all fields', async () => {
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(varState).toMatchInlineSnapshot(`
|
||||
expect(varState).toMatchInlineSnapshot(`
|
||||
{
|
||||
"bindMgt": false,
|
||||
"cacheNumDevices": NaN,
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { setupNotificationWatch } from '@app/core/modules/notifications/setup-notification-watch';
|
||||
import { sleep } from '@app/core/utils/misc/sleep';
|
||||
import { loadDynamixConfigFile } from '@app/store/actions/load-dynamix-config-file';
|
||||
import { store } from '@app/store/index';
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
test('loads notifications properly', async () => {
|
||||
await store.dispatch(loadDynamixConfigFile()).unwrap();
|
||||
const watch = await setupNotificationWatch();
|
||||
expect(watch).not.toBeNull();
|
||||
await sleep(400);
|
||||
expect(store.getState().notifications.notifications).toMatchSnapshot();
|
||||
await watch?.close();
|
||||
});
|
||||
@@ -1,9 +1,10 @@
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { store } from '@app/store';
|
||||
|
||||
test('Returns paths', async () => {
|
||||
const { paths } = store.getState();
|
||||
expect(Object.keys(paths)).toMatchInlineSnapshot(`
|
||||
const { paths } = store.getState();
|
||||
expect(Object.keys(paths)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"core",
|
||||
"unraid-api-base",
|
||||
@@ -25,6 +26,8 @@ test('Returns paths', async () => {
|
||||
"machine-id",
|
||||
"log-base",
|
||||
"var-run",
|
||||
"auth-sessions",
|
||||
"auth-keys",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
66
api/src/__test__/store/modules/registration.test.ts
Normal file
66
api/src/__test__/store/modules/registration.test.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { store } from '@app/store';
|
||||
import { loadRegistrationKey } from '@app/store/modules/registration';
|
||||
import { FileLoadStatus, StateFileKey } from '@app/store/types';
|
||||
|
||||
// Preloading imports for faster tests
|
||||
|
||||
test('Before loading key returns null', async () => {
|
||||
const { status, keyFile } = store.getState().registration;
|
||||
expect(status).toBe(FileLoadStatus.UNLOADED);
|
||||
expect(keyFile).toBe(null);
|
||||
});
|
||||
|
||||
test('Requires emhttp to be loaded to find key file', async () => {
|
||||
// Load registration key into store
|
||||
await store.dispatch(loadRegistrationKey());
|
||||
|
||||
// Check if store has state files loaded
|
||||
const { status, keyFile } = store.getState().registration;
|
||||
|
||||
expect(status).toBe(FileLoadStatus.LOADED);
|
||||
expect(keyFile).toBe(null);
|
||||
});
|
||||
|
||||
test('Returns empty key if key location is empty', async () => {
|
||||
const { updateEmhttpState } = await import('@app/store/modules/emhttp');
|
||||
const { loadRegistrationKey } = await import('@app/store/modules/registration');
|
||||
|
||||
// Set key file location as empty
|
||||
// This should only happen if the user doesn't have a key file
|
||||
store.dispatch(
|
||||
updateEmhttpState({
|
||||
field: StateFileKey.var,
|
||||
state: {
|
||||
regFile: '',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// Load registration key into store
|
||||
await store.dispatch(loadRegistrationKey());
|
||||
|
||||
// Check if store has state files loaded
|
||||
const { status, keyFile } = store.getState().registration;
|
||||
expect(status).toBe(FileLoadStatus.LOADED);
|
||||
expect(keyFile).toBe('');
|
||||
});
|
||||
|
||||
test('Returns decoded key file if key location exists', async () => {
|
||||
const { loadRegistrationKey } = await import('@app/store/modules/registration');
|
||||
const { loadStateFiles } = await import('@app/store/modules/emhttp');
|
||||
|
||||
// Load state files into store
|
||||
await store.dispatch(loadStateFiles());
|
||||
|
||||
// Load registration key into store
|
||||
await store.dispatch(loadRegistrationKey());
|
||||
|
||||
// Check if store has state files loaded
|
||||
const { status, keyFile } = store.getState().registration;
|
||||
expect(status).toBe(FileLoadStatus.LOADED);
|
||||
expect(keyFile).toMatchInlineSnapshot(
|
||||
'"hVs1tLjvC9FiiQsIwIQ7G1KszAcexf0IneThhnmf22SB0dGs5WzRkqMiSMmt2DtR5HOXFUD32YyxuzGeUXmky3zKpSu6xhZNKVg5atGM1OfvkzHBMldI3SeBLuUFSgejLbpNUMdTrbk64JJdbzle4O8wiQgkIpAMIGxeYLwLBD4zHBcfyzq40QnxG--HcX6j25eE0xqa2zWj-j0b0rCAXahJV2a3ySCbPzr1MvfPRTVb0rr7KJ-25R592hYrz4H7Sc1B3p0lr6QUxHE6o7bcYrWKDRtIVoZ8SMPpd1_0gzYIcl5GsDFzFumTXUh8NEnl0Q8hwW1YE-tRc6Y_rrvd7w"'
|
||||
);
|
||||
});
|
||||
18
api/src/__test__/store/state-parsers/devices.test.ts
Normal file
18
api/src/__test__/store/state-parsers/devices.test.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { join } from 'path';
|
||||
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import type { DevicesIni } from '@app/store/state-parsers/devices';
|
||||
import { store } from '@app/store';
|
||||
|
||||
test('Returns parsed state file', async () => {
|
||||
const { parse } = await import('@app/store/state-parsers/devices');
|
||||
const { parseConfig } = await import('@app/core/utils/misc/parse-config');
|
||||
const { paths } = store.getState();
|
||||
const filePath = join(paths.states, 'devs.ini');
|
||||
const stateFile = parseConfig<DevicesIni>({
|
||||
filePath,
|
||||
type: 'ini',
|
||||
});
|
||||
expect(parse(stateFile)).toMatchInlineSnapshot('[]');
|
||||
});
|
||||
83
api/src/__test__/store/state-parsers/network.test.ts
Normal file
83
api/src/__test__/store/state-parsers/network.test.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { join } from 'path';
|
||||
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import type { NetworkIni } from '@app/store/state-parsers/network';
|
||||
import { store } from '@app/store';
|
||||
|
||||
test('Returns parsed state file', async () => {
|
||||
const { parse } = await import('@app/store/state-parsers/network');
|
||||
const { parseConfig } = await import('@app/core/utils/misc/parse-config');
|
||||
const { paths } = store.getState();
|
||||
const filePath = join(paths.states, 'network.ini');
|
||||
const stateFile = parseConfig<NetworkIni>({
|
||||
filePath,
|
||||
type: 'ini',
|
||||
});
|
||||
expect(parse(stateFile)).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"bonding": true,
|
||||
"bondingMiimon": "100",
|
||||
"bondingMode": "1",
|
||||
"bondname": "",
|
||||
"bondnics": [
|
||||
"eth0",
|
||||
"eth1",
|
||||
"eth2",
|
||||
"eth3",
|
||||
],
|
||||
"brfd": "0",
|
||||
"bridging": true,
|
||||
"brname": "",
|
||||
"brnics": "bond0",
|
||||
"brstp": "0",
|
||||
"description": [
|
||||
"",
|
||||
],
|
||||
"dhcp6Keepresolv": false,
|
||||
"dhcpKeepresolv": false,
|
||||
"dnsServer1": "1.1.1.1",
|
||||
"dnsServer2": "8.8.8.8",
|
||||
"gateway": [
|
||||
"192.168.1.1",
|
||||
],
|
||||
"gateway6": [
|
||||
"",
|
||||
],
|
||||
"ipaddr": [
|
||||
"192.168.1.150",
|
||||
],
|
||||
"ipaddr6": [
|
||||
"",
|
||||
],
|
||||
"metric": [
|
||||
"",
|
||||
],
|
||||
"metric6": [
|
||||
"",
|
||||
],
|
||||
"mtu": "",
|
||||
"netmask": [
|
||||
"255.255.255.0",
|
||||
],
|
||||
"netmask6": [
|
||||
"",
|
||||
],
|
||||
"privacy6": [
|
||||
"",
|
||||
],
|
||||
"protocol": [
|
||||
"",
|
||||
],
|
||||
"type": "access",
|
||||
"useDhcp": [
|
||||
true,
|
||||
],
|
||||
"useDhcp6": [
|
||||
false,
|
||||
],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
205
api/src/__test__/store/state-parsers/nfs.test.ts
Normal file
205
api/src/__test__/store/state-parsers/nfs.test.ts
Normal file
@@ -0,0 +1,205 @@
|
||||
import { join } from 'path';
|
||||
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import type { NfsSharesIni } from '@app/store/state-parsers/nfs';
|
||||
import { store } from '@app/store';
|
||||
|
||||
test('Returns parsed state file', async () => {
|
||||
const { parse } = await import('@app/store/state-parsers/nfs');
|
||||
const { parseConfig } = await import('@app/core/utils/misc/parse-config');
|
||||
const { paths } = store.getState();
|
||||
const filePath = join(paths.states, 'sec_nfs.ini');
|
||||
const stateFile = parseConfig<NfsSharesIni>({
|
||||
filePath,
|
||||
type: 'ini',
|
||||
});
|
||||
expect(parse(stateFile)).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk1",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk2",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk3",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk4",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk5",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk6",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk7",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk8",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk9",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk10",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk11",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk12",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk13",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk14",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk15",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk16",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk17",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk18",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk19",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk20",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk21",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "disk22",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"hostList": "",
|
||||
"name": "abc",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"writeList": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
@@ -1,16 +1,18 @@
|
||||
import { join } from 'path';
|
||||
|
||||
import { expect, test } from 'vitest';
|
||||
import { store } from '@app/store';
|
||||
|
||||
import type { NginxIni } from '@app/store/state-parsers/nginx';
|
||||
import { store } from '@app/store';
|
||||
|
||||
test('Returns parsed state file', async () => {
|
||||
const { parse } = await import('@app/store/state-parsers/nginx');
|
||||
const { parseConfig } = await import('@app/core/utils/misc/parse-config');
|
||||
const { paths } = store.getState();
|
||||
const filePath = join(paths.states, 'nginx.ini');
|
||||
const stateFile = parseConfig<NginxIni>({
|
||||
filePath,
|
||||
type: 'ini',
|
||||
});
|
||||
expect(parse(stateFile)).toMatchSnapshot();
|
||||
});
|
||||
const { parse } = await import('@app/store/state-parsers/nginx');
|
||||
const { parseConfig } = await import('@app/core/utils/misc/parse-config');
|
||||
const { paths } = store.getState();
|
||||
const filePath = join(paths.states, 'nginx.ini');
|
||||
const stateFile = parseConfig<NginxIni>({
|
||||
filePath,
|
||||
type: 'ini',
|
||||
});
|
||||
expect(parse(stateFile)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import { join } from 'path';
|
||||
|
||||
import { expect, test } from 'vitest';
|
||||
import { store } from '@app/store';
|
||||
|
||||
import type { SharesIni } from '@app/store/state-parsers/shares';
|
||||
import { store } from '@app/store';
|
||||
|
||||
test('Returns parsed state file', async () => {
|
||||
const { parse } = await import('@app/store/state-parsers/shares');
|
||||
const { parseConfig } = await import('@app/core/utils/misc/parse-config');
|
||||
const { paths } = store.getState();
|
||||
const filePath = join(paths.states, 'shares.ini');
|
||||
const stateFile = parseConfig<SharesIni>({
|
||||
filePath,
|
||||
type: 'ini',
|
||||
});
|
||||
expect(parse(stateFile)).toMatchInlineSnapshot(`
|
||||
const { parse } = await import('@app/store/state-parsers/shares');
|
||||
const { parseConfig } = await import('@app/core/utils/misc/parse-config');
|
||||
const { paths } = store.getState();
|
||||
const filePath = join(paths.states, 'shares.ini');
|
||||
const stateFile = parseConfig<SharesIni>({
|
||||
filePath,
|
||||
type: 'ini',
|
||||
});
|
||||
expect(parse(stateFile)).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"allocator": "highwater",
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import { join } from 'path';
|
||||
|
||||
import { expect, test } from 'vitest';
|
||||
import { store } from '@app/store';
|
||||
|
||||
import type { SlotsIni } from '@app/store/state-parsers/slots';
|
||||
import { store } from '@app/store';
|
||||
|
||||
test('Returns parsed state file', async () => {
|
||||
const { parse } = await import('@app/store/state-parsers/slots');
|
||||
const { parseConfig } = await import('@app/core/utils/misc/parse-config');
|
||||
const { paths } = store.getState();
|
||||
const filePath = join(paths.states, 'disks.ini');
|
||||
const stateFile = parseConfig<SlotsIni>({
|
||||
filePath,
|
||||
type: 'ini',
|
||||
});
|
||||
expect(parse(stateFile)).toMatchInlineSnapshot(`
|
||||
const { parse } = await import('@app/store/state-parsers/slots');
|
||||
const { parseConfig } = await import('@app/core/utils/misc/parse-config');
|
||||
const { paths } = store.getState();
|
||||
const filePath = join(paths.states, 'disks.ini');
|
||||
const stateFile = parseConfig<SlotsIni>({
|
||||
filePath,
|
||||
type: 'ini',
|
||||
});
|
||||
expect(parse(stateFile)).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"comment": null,
|
||||
|
||||
308
api/src/__test__/store/state-parsers/smb.test.ts
Normal file
308
api/src/__test__/store/state-parsers/smb.test.ts
Normal file
@@ -0,0 +1,308 @@
|
||||
import { join } from 'path';
|
||||
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import type { SmbIni } from '@app/store/state-parsers/smb';
|
||||
import { store } from '@app/store';
|
||||
|
||||
test('Returns parsed state file', async () => {
|
||||
const { parse } = await import('@app/store/state-parsers/smb');
|
||||
const { parseConfig } = await import('@app/core/utils/misc/parse-config');
|
||||
const { paths } = store.getState();
|
||||
const filePath = join(paths.states, 'sec.ini');
|
||||
const stateFile = parseConfig<SmbIni>({
|
||||
filePath,
|
||||
type: 'ini',
|
||||
});
|
||||
expect(parse(stateFile)).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk1",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk2",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk3",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk4",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk5",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk6",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk7",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk8",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk9",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk10",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk11",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk12",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk13",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk14",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk15",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk16",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk17",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk18",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk19",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk20",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk21",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "disk22",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"caseSensitive": "auto",
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "abc",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
{
|
||||
"enabled": true,
|
||||
"fruit": "no",
|
||||
"name": "flash",
|
||||
"readList": [],
|
||||
"security": "public",
|
||||
"timemachine": {
|
||||
"volsizelimit": NaN,
|
||||
},
|
||||
"writeList": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user