Compare commits
1823 Commits
rcnginx_sa
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
95c6913c62 | ||
|
b783d4b207 | ||
|
a866de833a | ||
|
ee31e35849 | ||
|
50e7389c8a | ||
|
d536ef285b | ||
|
2dc82b61de | ||
|
57ec7909e5 | ||
|
01c6f64b52 | ||
|
80d567dfde | ||
|
99d60fa08a | ||
|
8bbf176b8b | ||
|
ca51a3799b | ||
|
e4bb758b05 | ||
|
3c007fa1d0 | ||
|
c062e4dd9c | ||
|
06b1c9a20f | ||
|
bf6d5982be | ||
|
d9bd5b56c8 | ||
|
bc7c66fec9 | ||
|
dc50e7d2c2 | ||
|
0061c66dfe | ||
|
91caf869f5 | ||
|
97c3a4621b | ||
|
1ffb22bddf | ||
|
1d9e14f07c | ||
6f7b97e37a | |||
|
ed7219d9c7 | ||
|
082d7d842b | ||
|
9a502776a1 | ||
|
03346f4709 | ||
|
1cc84832ee | ||
|
959df7e46c | ||
|
3fb6c2147b | ||
|
3db6fa9a1d | ||
|
0c5987fab0 | ||
|
fcbc8f700e | ||
|
6fd88575b2 | ||
|
bff0238f88 | ||
|
ee7f1f4a5b | ||
|
c3dd62f1d5 | ||
|
7c0fb18e3c | ||
|
fe2e2ff897 | ||
|
74530129ae | ||
|
968e3b1d72 | ||
|
6bdcb38c47 | ||
|
8c7cdca4aa | ||
|
08024a0464 | ||
|
828cd7b747 | ||
|
0ce3960de6 | ||
|
8b91d22796 | ||
b716920800 | |||
6d749a8b1a | |||
69b95ae27d | |||
|
20e29ab5af | ||
a75bc3d4d7 | |||
|
e8e5ccdf18 | ||
020ed9a07f | |||
|
8f656e87b1 | ||
|
54b1e81b38 | ||
|
4c6be23467 | ||
|
4a4983f7c5 | ||
|
dcfaa1afa0 | ||
|
e52813b626 | ||
|
760aac71df | ||
|
20ef176665 | ||
|
66d7193dab | ||
|
9c9c79b1b3 | ||
|
8aac4ee119 | ||
|
8120959c2f | ||
|
72abe50721 | ||
|
18e37ed045 | ||
|
6845c007a7 | ||
|
b844f941d0 | ||
|
5883e767aa | ||
|
efc4fa2673 | ||
|
0810fc5bd8 | ||
|
897365a5de | ||
|
8d628aad4f | ||
e3c4ff280d | |||
19de7c1979 | |||
5ec695921a | |||
171a77feec | |||
3e29f0b8b8 | |||
b62c8f5a12 | |||
e9faee0d27 | |||
|
16823d07b1 | ||
|
73705b71fa | ||
|
6b31532688 | ||
|
039c798b43 | ||
1e43abc785 | |||
|
9b1081d2e1 | ||
|
c27e018fdb | ||
|
ef5067584b | ||
|
4ea425411a | ||
|
24bdc5169d | ||
|
753d87c690 | ||
07d02f579f | |||
|
ceb97ab392 | ||
|
6a15afa2a8 | ||
|
175d24afd2 | ||
|
12828eec63 | ||
|
156599031a | ||
|
15f4138c87 | ||
|
fd6e4f1ba1 | ||
|
72a47035ef | ||
|
d57bf205fa | ||
|
16a8e7092d | ||
|
00b1f77742 | ||
|
506270e413 | ||
|
303c76d7da | ||
|
73ea1bb7b3 | ||
|
9d4ca6a2c9 | ||
49b82d0eb8 | |||
|
106f155ecc | ||
|
53704b58aa | ||
|
da9add3637 | ||
|
db77c13552 | ||
|
be22c0e1f8 | ||
|
cd9d20eaf3 | ||
|
c4afbba9bc | ||
|
16089cd927 | ||
|
1ede8e621b | ||
|
64ead9a127 | ||
|
ff80906d11 | ||
|
8981e8bb15 | ||
|
83675005d2 | ||
|
4b7f2bfcee | ||
|
72ff3c52c0 | ||
|
69e11713e5 | ||
|
67cf2db493 | ||
|
631479d27d | ||
|
28b3d2ae71 | ||
|
ec1689dc68 | ||
|
3615992dc4 | ||
d9f83cc76b | |||
|
7e6ad9512d | ||
|
d7b4dfd44b | ||
|
c62ef28fc3 | ||
|
07fa790411 | ||
|
fb19a99ad4 | ||
d0dcf6c314 | |||
0d925a2471 | |||
|
2b4eb1abad | ||
|
251881d850 | ||
|
24fce7582c | ||
|
b56f3e529c | ||
|
130e3fcd44 | ||
|
c1b2bb7435 | ||
|
840e19d322 | ||
|
2ae85fdd31 | ||
|
0db0032648 | ||
|
8d9e2a04c0 | ||
|
31f81349a8 | ||
|
3de8e05432 | ||
|
1c019c8f08 | ||
|
8d76d6f1cc | ||
|
3e17f35e19 | ||
|
6f51589547 | ||
|
b18e734381 | ||
|
b5a8223ffe | ||
|
936adea879 | ||
|
1572378824 | ||
|
0cf3585a0d | ||
|
3f103f2089 | ||
|
ed308c3a69 | ||
|
985d077af5 | ||
|
86b8b170d1 | ||
|
d351e51f58 | ||
|
53c1788580 | ||
|
0870461731 | ||
|
043d2baaf7 | ||
|
32bb9bb6d9 | ||
|
2ff8b77c9d | ||
|
654db74167 | ||
fb2b66b5b0 | |||
663665a61b | |||
|
c9333ea955 | ||
|
bad23e7647 | ||
17909f889e | |||
8cabad6f0d | |||
|
566113f86c | ||
|
21e640184e | ||
|
202196f7d3 | ||
9c2aa45751 | |||
|
33a73b2fb5 | ||
|
06735f7a3e | ||
|
e7f7ef43c0 | ||
|
c5b692e805 | ||
|
6a91f270e3 | ||
|
6d3a7a3298 | ||
f81118ffe3 | |||
f9107ebe11 | |||
76f58d2995 | |||
b4722f57aa | |||
3314860d31 | |||
9a6b62ae98 | |||
e0b1612633 | |||
1e41ac637d | |||
858a3aa999 | |||
79c484e2e5 | |||
49793ff602 | |||
342619a567 | |||
|
27047c8832 | ||
|
b850940f19 | ||
|
de3334b0d2 | ||
|
373bb9f2ee | ||
|
833194705c | ||
|
392cc77a20 | ||
|
d272bf78ac | ||
|
9430366eaf | ||
|
71dc414592 | ||
|
2b41f9a8d2 | ||
|
70c01ec454 | ||
|
7840ae6d3c | ||
|
5b009dfb39 | ||
|
5565c02f74 | ||
|
793289bc7f | ||
|
7d92761860 | ||
|
1021adc33b | ||
|
c9374f7911 | ||
|
73a17a0306 | ||
|
0729386af9 | ||
|
4b8ec6e5a3 | ||
|
ea2fa8a8db | ||
|
d7e474257c | ||
|
4b3e8f2d46 | ||
|
54a6e3dd13 | ||
|
e20f37d936 | ||
|
4c1c566e78 | ||
|
a6c50b208a | ||
|
9a23761dc8 | ||
|
359334b85a | ||
|
f5ed6964dd | ||
|
882ee7f911 | ||
|
234a749b7f | ||
|
a9891f557e | ||
|
04640a5708 | ||
|
fac92be4d4 | ||
|
817ed5c1c1 | ||
|
a4abe0fa55 | ||
|
6920542d6c | ||
|
36f9e7402c | ||
|
cfa547972e | ||
|
84b5baf402 | ||
|
1b162e2c21 | ||
|
75f0c2e4f6 | ||
|
67369622fa | ||
|
17fdfb6f50 | ||
|
9e80fb13c7 | ||
|
1d6c3f4375 | ||
58c31f4ef6 | |||
|
84b767ddcd | ||
|
32d3f88b44 | ||
|
6156a2582f | ||
|
8a55228b8e | ||
|
fe7ab1fc43 | ||
30492ed2f2 | |||
da1ef5c0e0 | |||
93054c2091 | |||
|
f2abfaf292 | ||
|
5a42314c60 | ||
|
bbed6047e3 | ||
|
a7f6ac7389 | ||
|
f7748f7619 | ||
|
d4968e1b19 | ||
|
fb680469ac | ||
|
eaabbec7e0 | ||
|
693a0260af | ||
|
130c9c6373 | ||
73c264e9fe | |||
667741129a | |||
|
42fe45595f | ||
|
ed9b8322d4 | ||
|
cfb2daa531 | ||
|
694d35b412 | ||
|
4011d942ce | ||
|
5b95526e84 | ||
|
667418e656 | ||
|
c0d4e1de1b | ||
|
ec7ec769f4 | ||
|
1524f2d69a | ||
|
c9109d61bf | ||
|
a9a2b73849 | ||
|
b1b76d8ffa | ||
|
891ee6beff | ||
|
bd4eb4189b | ||
|
24fd56fff3 | ||
|
45d71932a1 | ||
|
f8ad3105c7 | ||
|
a8adba6728 | ||
|
6ab9f0a017 | ||
|
4904a5021c | ||
|
859e697413 | ||
|
c60cbb5c6e | ||
|
4a3a1f526d | ||
|
38758462f7 | ||
|
7e8b8e0a0a | ||
|
2f2f50d178 | ||
|
69d2996c31 | ||
|
f4a8bf0d81 | ||
|
9d63b5ecf8 | ||
|
95353c143a | ||
|
925fff60a9 | ||
|
8965860224 | ||
|
9d15302bf0 | ||
|
6bb27eec3a | ||
|
84ad25fe18 | ||
|
9f9429424f | ||
|
04e0fac01c | ||
|
27973b8e34 | ||
|
d6f8206275 | ||
|
cd1b4031df | ||
|
44dfe5a7b1 | ||
|
1ae58dc360 | ||
|
e0c0440d69 | ||
|
282cfc41ca | ||
|
26f261e93b | ||
|
65e67856bb | ||
|
b73327d4b7 | ||
|
3fdcbf125d | ||
|
941778d288 | ||
|
90cbff0058 | ||
|
30b76de196 | ||
|
7f681fe2fa | ||
|
72651576f4 | ||
|
2ea62cca3d | ||
|
20f34bc0b9 | ||
|
c2a4e68196 | ||
|
b75c420ce0 | ||
|
da18a7e213 | ||
|
f6ae173275 | ||
|
dd9474ef55 | ||
|
7512161e1a | ||
|
68fe9a9399 | ||
|
78826be39d | ||
|
c4eff321f2 | ||
|
6d2de179a0 | ||
|
1da8308b81 | ||
|
243b838d80 | ||
|
f93095d552 | ||
|
eed5a94d03 | ||
|
5c33796801 | ||
|
3e1e33094c | ||
|
63d4bab0d1 | ||
|
dbd1c9f7b1 | ||
|
446111b0b1 | ||
|
be0dcff031 | ||
|
cdce8e048a | ||
|
2494d1735e | ||
|
8328461cf5 | ||
|
1cb3134217 | ||
|
18872afdd0 | ||
|
fa5b932c13 | ||
|
aa489bb92d | ||
|
22124123a9 | ||
|
419b9a77e6 | ||
|
191f68642c | ||
|
cfa1ec4860 | ||
|
955ba7f0a6 | ||
|
8354a5c6ac | ||
|
392811005c | ||
|
b2916424be | ||
|
b35ce11344 | ||
|
91bc84a97a | ||
|
e61132fe69 | ||
|
15af3fb6eb | ||
|
c1493a61d7 | ||
|
a823ecf79c | ||
|
50a27242ab | ||
|
7656c9a55c | ||
|
15913a6c64 | ||
|
f8ce0a6e80 | ||
|
470e02ed55 | ||
|
40ac4fe6fe | ||
|
ef795438cc | ||
|
7a968eac84 | ||
|
3ce94f664b | ||
|
5daacf1e97 | ||
|
e621ccebb1 | ||
|
e28d4a32fb | ||
|
f6427a3361 | ||
|
91e14b22db | ||
|
095b931dad | ||
|
5303b18462 | ||
|
7bdb5eeb03 | ||
|
e6ff7a5d7f | ||
|
4fcf899c5a | ||
|
d9325649bb | ||
|
0f22fe77e6 | ||
|
45c1cab4b5 | ||
|
e29de3c3e5 | ||
|
a757fe0fe6 | ||
|
55c79439f3 | ||
|
32c769e6bd | ||
|
a6c0369444 | ||
|
74ee77521e | ||
|
290d4da90a | ||
|
efd598c8f8 | ||
|
19be69461e | ||
|
cf6f3acb3a | ||
|
b14922734a | ||
|
9aa50b1b1d | ||
|
24d5ed5f1b | ||
|
a2d35294d3 | ||
|
73b3829d61 | ||
|
7b568c2aa1 | ||
|
f76337c97f | ||
|
44e74e15d3 | ||
|
3ec2a92b41 | ||
|
e256fa8313 | ||
|
ad2e98ea46 | ||
|
ed1ee47ce4 | ||
|
cce6b7ea92 | ||
|
1d5ff688ba | ||
|
81e48a2291 | ||
|
3deacb643d | ||
|
a4f6b7dcad | ||
|
fecd6505af | ||
|
6938fbb992 | ||
|
8d1478a06e | ||
|
964d083551 | ||
|
70a24418b1 | ||
|
db094cdf89 | ||
|
05f6afd1a2 | ||
|
3e37b4a27d | ||
|
bdc9ef9782 | ||
|
215d16af41 | ||
|
dcb1e43d21 | ||
|
a5cab82c29 | ||
|
280e7a52cd | ||
|
f0d4c00389 | ||
|
3301357979 | ||
|
7701f10ef4 | ||
|
ab41b013e2 | ||
|
04ef869aba | ||
|
1be0380f36 | ||
|
8d4c007226 | ||
|
f5e5ae2d28 | ||
|
41363509e2 | ||
|
59835e14eb | ||
|
d6eb51f502 | ||
|
cebe945e81 | ||
|
7532448241 | ||
|
f184a79e85 | ||
|
45308bc7cb | ||
|
e988ef55fc | ||
|
4cf3e39add | ||
|
d85d68de2e | ||
|
6790400629 | ||
|
7f77338b3d | ||
|
70d3d5a656 | ||
|
69bd331d2d | ||
|
c44beb2eb7 | ||
|
2d136461fd | ||
|
414dddb008 | ||
|
894bc28aaa | ||
|
8bf3cae742 | ||
|
86a014f82e | ||
|
91edca4576 | ||
|
1c4f5983af | ||
|
f933c288e9 | ||
|
dd0cf7f2fa | ||
|
939a30774a | ||
|
6234c5edc0 | ||
|
b34fe9838a | ||
|
f65780a67e | ||
|
80e5481de9 | ||
|
40c25d9d18 | ||
|
5542b65e45 | ||
|
70760a302c | ||
|
0431343070 | ||
|
32f1c8c3ec | ||
|
8f8da76bf3 | ||
|
58f5fb269b | ||
|
9a76f69f5d | ||
|
dac9d237ee | ||
|
f492ee8f7f | ||
|
3cc0bf7e90 | ||
|
bf92bdb1af | ||
|
7fdb5cb5be | ||
|
c45dd68e08 | ||
|
8b5eb3f66d | ||
|
43ae4c785d | ||
|
8da53df357 | ||
|
b4a3a90a46 | ||
|
072e3512e0 | ||
|
ae8feb2dbc | ||
|
f901cc9d4e | ||
|
a8f0e3ec19 | ||
|
2db31b2012 | ||
|
85d1a2f6f5 | ||
|
9296e6297c | ||
|
245e6413cb | ||
|
4f82b16fdd | ||
|
a90d083cb0 | ||
|
efe372d1d9 | ||
|
995a95f053 | ||
|
0c32fe5d4d | ||
f8ff2333bb | |||
|
ba9bef985c | ||
|
45cfa13e14 | ||
|
424b5cb121 | ||
|
d1e5f3bb10 | ||
|
e6441a8345 | ||
|
43c71ec2da | ||
|
33b27f0a71 | ||
|
90eb25f114 | ||
|
71f99155b8 | ||
|
cb48e16845 | ||
|
ff2328ddca | ||
|
b0680ee1e1 | ||
|
c8b9f1c9cc | ||
|
863afd348d | ||
|
ae285176a9 | ||
|
d9588b7c83 | ||
|
f79f907923 | ||
|
a5b7247d88 | ||
|
2a6c09f9c9 | ||
|
b8400d4395 | ||
|
191c067465 | ||
|
511a8e47ac | ||
|
2bec253098 | ||
|
b21437cf5c | ||
|
da7749725f | ||
|
7cce87baa2 | ||
|
c3d232efc0 | ||
|
1b35b145f8 | ||
|
7e0f91cb53 | ||
|
b7f69da252 | ||
|
8f99ba2346 | ||
|
e87a15d439 | ||
|
1640e6d2a0 | ||
|
a76a68d4e2 | ||
|
f9398d01c6 | ||
|
56990109f5 | ||
|
d2e20c4d45 | ||
|
21dcf49ad1 | ||
|
e7648ba08c | ||
|
fcb58b1908 | ||
|
003d4b86a8 | ||
|
28e16fc500 | ||
|
a5be34d6b9 | ||
|
92a9d2e4c3 | ||
|
22c3ac6061 | ||
|
562a1ace79 | ||
|
cdedaa9476 | ||
|
1d35b06539 | ||
|
80b200950f | ||
|
62ea5702ce | ||
|
e9c973baad | ||
|
7d85097bce | ||
|
37b41950bb | ||
|
9d583f63f0 | ||
|
a88d5608af | ||
|
1a79fb8cd8 | ||
|
bc931a5483 | ||
|
e6e74004a3 | ||
|
dc3f03b952 | ||
|
bf36603023 | ||
|
c8967594c7 | ||
|
e0ea112af7 | ||
|
ffabb996fc | ||
|
4a4444229e | ||
|
5867f6719d | ||
|
cf69edb57d | ||
|
1d47440008 | ||
|
890671f106 | ||
|
a1d486f112 | ||
|
bce62bb5e9 | ||
|
7c318c11f1 | ||
|
1447bea75b | ||
|
fd21e9d6f5 | ||
|
a2a598d28d | ||
|
cc2d969181 | ||
|
3790217cec | ||
|
cde1e4582a | ||
|
689f0bb697 | ||
|
845fb47335 | ||
|
641226a49f | ||
|
ba0eabe9bb | ||
|
7738c25e7c | ||
|
2f279bc56e | ||
|
cab7615a3d | ||
|
558640b10a | ||
|
38a9b575f7 | ||
|
afd2852fc8 | ||
|
9ca6b38ecb | ||
|
79d8150e56 | ||
|
d635653a49 | ||
|
2d78738cef | ||
|
86b0af8b49 | ||
|
c0f79e8929 | ||
|
5989f372ce | ||
|
08918b8892 | ||
|
d5ee50c696 | ||
|
02de6b43b4 | ||
|
3b2ed257da | ||
|
d0a37df768 | ||
|
0710deb304 | ||
|
c383caf3ff | ||
|
0afb8dd7de | ||
|
afc8834610 | ||
|
3021a72fd7 | ||
|
537149f206 | ||
|
0b7f980e97 | ||
|
da32a2ab36 | ||
|
a34a2d0de9 | ||
|
614826552f | ||
|
5be81cfb8f | ||
|
30f49bd3d7 | ||
|
e696f98467 | ||
|
e47b80a501 | ||
|
d68da6a187 | ||
|
c6e549ac7d | ||
|
b69564caed | ||
|
cb84d60e00 | ||
|
78dcc575d6 | ||
|
ffcb5b11a1 | ||
|
77bd950c6d | ||
|
6d379a4dd6 | ||
|
a101d2c538 | ||
|
a15501a2b5 | ||
|
f8f6633c1b | ||
|
10d590fc66 | ||
|
1c23a008b9 | ||
|
a02a4fbd7a | ||
|
8d1438635a | ||
|
19c23dc05b | ||
|
8bde22106f | ||
|
c222fbb306 | ||
|
415cb252e7 | ||
|
a7b1a6c12f | ||
|
9bdc64635e | ||
|
9524159cf2 | ||
|
512b9036a6 | ||
|
fb856215c3 | ||
|
8e77da0222 | ||
|
1228a1976a | ||
|
d53598a1fe | ||
|
d8d13805df | ||
|
69fe39720c | ||
|
58ec85211a | ||
|
8a75747fb4 | ||
|
cc80a2ad85 | ||
|
74e3390eeb | ||
|
8d48faa815 | ||
|
ddc478dafb | ||
|
816f3561e6 | ||
|
b67bd8ab30 | ||
|
f34dfbc79b | ||
533a4171bf | |||
9d84fedb8e | |||
|
20d7b702c5 | ||
|
ef27b5057d | ||
|
bb7f657b56 | ||
|
e2c0990d9d | ||
|
b7a00ec600 | ||
|
85fdccecd2 | ||
|
727b36a122 | ||
|
9e5043eed1 | ||
|
382eb005aa | ||
|
846143ed73 | ||
|
de0b17afd4 | ||
|
20174e9bce | ||
|
bcae60182f | ||
|
46b6d769f6 | ||
|
7cadcbdf71 | ||
|
a702f65759 | ||
|
d036c7a086 | ||
|
66cb88ff9f | ||
|
d0afcf16f8 | ||
|
123239a2e6 | ||
|
aad980c1e5 | ||
|
df18d48eb7 | ||
|
fb0a3e9a2e | ||
|
a9a851ffb2 | ||
|
5d04fc4763 | ||
|
fa1a13250e | ||
|
cfe667bc38 | ||
|
2c0a5b5494 | ||
|
c6b7fa7abb | ||
|
4101096ad4 | ||
|
2267e3c37c | ||
|
097caf4fa5 | ||
|
5c6513c4e2 | ||
|
e8d01ff32a | ||
|
b85cd55423 | ||
|
27ad1fa476 | ||
|
00ce97a9f6 | ||
|
f7b08bcab9 | ||
|
298b020b9c | ||
|
c9f20e7934 | ||
|
e774c8a6a5 | ||
|
4b8f60f3ec | ||
|
4ab3760bea | ||
|
c9cbed9fe5 | ||
|
3210b1bd39 | ||
|
3b60e15ef0 | ||
|
3c6180f114 | ||
|
fd5d7e122e | ||
|
ee90e2b997 | ||
|
27bb4f7799 | ||
|
cc2aa8acc9 | ||
|
d6fa9420f3 | ||
|
249785377f | ||
|
21f1ec278e | ||
|
6db0bba9fa | ||
|
1fbd1b0a98 | ||
|
2b58784feb | ||
|
94aeb612b8 | ||
|
9f3047d2ff | ||
|
c7fcc66ec2 | ||
|
8c3b5a8554 | ||
|
97560c51d4 | ||
|
2ae9728e94 | ||
|
5c91a93a2c | ||
|
034b41726e | ||
|
eef77dc64d | ||
|
954969c2e4 | ||
|
71f655cd05 | ||
|
df4c1d72bd | ||
|
39e2381b8f | ||
|
54763e03a6 | ||
|
69e2e773a7 | ||
|
e24ffa4185 | ||
|
a5b41381af | ||
|
e6a70d829e | ||
|
863a3ee231 | ||
|
f999e6f692 | ||
|
1e38871d1f | ||
|
7dda0f48d0 | ||
|
bb6598d2f9 | ||
|
9e5666bed3 | ||
|
1655a361eb | ||
|
9797c34305 | ||
|
973fc9c508 | ||
|
ba9f1c474f | ||
|
451075c174 | ||
6011658a43 | |||
|
006c59dbf1 | ||
|
db610f0ae5 | ||
|
3abc6952ce | ||
|
92555090d9 | ||
|
d81e24e827 | ||
|
0f31f97d88 | ||
|
d27a796160 | ||
|
7ca74f9862 | ||
|
61b17ed7df | ||
|
04eea0961a | ||
|
9cf3a59c8a | ||
|
4622450b45 | ||
|
7f92fff58c | ||
|
4d54ab8660 | ||
|
a6c9b73e6f | ||
|
682978f730 | ||
|
aac68b1070 | ||
|
8133b2acc0 | ||
|
a3137c4086 | ||
|
f42cb70e4f | ||
|
61acffe36a | ||
|
fe5258d939 | ||
|
94972a6dc7 | ||
|
9dc7547a6a | ||
|
7833fdefeb | ||
|
6428747c77 | ||
|
7c033ddc15 | ||
|
99291453ae | ||
|
36a16931e5 | ||
|
a6e139351d | ||
|
bf75867eae | ||
|
232f45286f | ||
|
202f6fec50 | ||
|
7772e3db38 | ||
|
cfdfb49fa2 | ||
|
70b0a5c3f3 | ||
|
4aaf3bb109 | ||
|
b833a13485 | ||
|
87e07534b1 | ||
|
111deef923 | ||
|
abdf3d7485 | ||
|
f80c212a26 | ||
|
076413fcae | ||
|
a571cbdc20 | ||
|
7fdfc3ebc2 | ||
|
f2c87c4485 | ||
|
080a3e28d3 | ||
|
c72a87723f | ||
|
2fe31d63d8 | ||
|
d67ea2e925 | ||
|
c318c949b1 | ||
|
c5abd80e42 | ||
|
432c9a43f0 | ||
|
df3d1cb5fc | ||
|
a992d17c3d | ||
|
e6b6af68ed | ||
|
cfdeba3f71 | ||
|
4cb1c76c5a | ||
|
92f325614c | ||
|
1cf264bdd6 | ||
|
26ca0f0722 | ||
|
429ce4b293 | ||
|
3bad9a20d8 | ||
|
da520c3d50 | ||
|
ac469937db | ||
|
d70bc5e9e8 | ||
|
099559e949 | ||
|
a441a00182 | ||
|
a3659d515a | ||
|
56dc0269b3 | ||
|
28d9de878c | ||
|
9d7df3be66 | ||
|
0287d8dfac | ||
|
900f74f334 | ||
|
551f85ad92 | ||
|
0d87850efd | ||
|
74b0b5a71f | ||
|
305e4648aa | ||
|
b8844dcedb | ||
|
690b4a264c | ||
|
4e71349cf2 | ||
|
24c0dd3015 | ||
|
dec1bf5de6 | ||
|
ccf7ec5db3 | ||
|
d2a2462059 | ||
|
be9a6b85aa | ||
|
8f78ab4ba0 | ||
|
b7af321692 | ||
|
d795f51b4b | ||
|
0649c310cb | ||
|
1e853aba3b | ||
|
9501c88bf4 | ||
|
acd0e764c3 | ||
|
9f01517f21 | ||
|
c46fd21747 | ||
|
89fbe80e9f | ||
|
820a79d598 | ||
|
550fed51dc | ||
|
3c42a85613 | ||
|
73412b7ca8 | ||
|
dc7b52e027 | ||
|
5842b5acf9 | ||
|
adb3a03b8d | ||
|
bea6e282ec | ||
|
1122262f36 | ||
|
f57c9b60d5 | ||
|
1155d09dd1 | ||
|
ddca644dfe | ||
|
3525dd5826 | ||
|
0cf829bf9d | ||
|
e332298dc0 | ||
|
58a7054db5 | ||
|
979dd225f7 | ||
|
8f8d7037ee | ||
|
239d6813a1 | ||
|
797e7cddaf | ||
|
b7bdde1f18 | ||
|
c7d5e5708e | ||
|
cc43038692 | ||
|
2a7dd96fac | ||
|
91f27cc70c | ||
|
b48b30a6a6 | ||
|
e0b857744f | ||
|
561cfc6c9f | ||
|
33a4ad1173 | ||
|
f7d0cf3ff6 | ||
|
a4ab98a078 | ||
|
70e690defa | ||
|
4a42a26b59 | ||
|
083cd984ea | ||
|
3dda97319d | ||
|
064cac1110 | ||
|
3d1b53d0ea | ||
|
61e99a390e | ||
|
37f1941027 | ||
|
a7671fba37 | ||
|
d866e77710 | ||
|
aaf31a808b | ||
|
b8b8f43387 | ||
|
7c94cbd169 | ||
|
f97e780f0f | ||
|
879657cc6a | ||
|
e75c667336 | ||
|
46789b61b8 | ||
|
19bebe7ef3 | ||
|
68552c0808 | ||
|
ff9e390840 | ||
|
0fcc246760 | ||
|
7bfffb9fdb | ||
|
adcb0de17d | ||
|
41539b9fe3 | ||
|
9c60cc9619 | ||
|
8c5c881237 | ||
|
26452c82f3 | ||
|
86366d4409 | ||
|
71b59cebae | ||
|
4ca244d444 | ||
|
0ff0ef490e | ||
|
7d9d306ef9 | ||
|
01c49623b0 | ||
|
5e3301945e | ||
|
0298d1f827 | ||
|
40c3bc2779 | ||
|
5effac6e9e | ||
|
6496bc1fca | ||
|
a58c476cc9 | ||
|
7c62bd4279 | ||
|
2966da5698 | ||
|
1a5a70e899 | ||
|
7ccd820373 | ||
|
bfb59dbd35 | ||
|
9188d22e0e | ||
|
6de185b0ac | ||
|
c4b6b0cfab | ||
|
2665ddebd2 | ||
|
4e568a9b9b | ||
|
08ecf1d9d2 | ||
|
25340cc3be | ||
|
0d2690abd1 | ||
|
b57f3b0538 | ||
184961b1d7 | |||
|
b307e6a373 | ||
|
69732671d9 | ||
|
5b8beac8dd | ||
|
52408b193d | ||
|
e734541dcb | ||
|
bb4c0402fc | ||
|
29b4c81b81 | ||
|
828d62cd49 | ||
|
3dda1c3fbd | ||
|
66874ef8f2 | ||
|
5730feb21e | ||
|
12b64b3ff6 | ||
|
0072325a15 | ||
|
09b9394df4 | ||
|
802a9491d0 | ||
|
692c6751c6 | ||
|
2ec3defc2c | ||
|
5f57d6466c | ||
|
bcbd9976e2 | ||
|
2fda052611 | ||
|
b7b9d350e1 | ||
|
a0e8bc32ea | ||
|
efc6d05b3d | ||
|
b5d39d90c6 | ||
|
1fc6b4014b | ||
|
56463d5ca2 | ||
|
84016c2e7c | ||
|
4e80ead785 | ||
|
b2e5cdba73 | ||
|
e5ddca7455 | ||
|
2b06cc8108 | ||
|
549cf123f6 | ||
|
753413a8f2 | ||
|
0c81e852f9 | ||
|
e1e912586f | ||
|
d6f7ec37ad | ||
|
a373e316a3 | ||
|
94c6096e46 | ||
|
2c507e32ac | ||
|
f245e595ab | ||
|
e892513dce | ||
|
e43baeefde | ||
|
261e680c7d | ||
|
0e20a0a30e | ||
|
6b7b731d31 | ||
|
058969c0dc | ||
|
551fde89d3 | ||
|
7d720ea2fd | ||
|
ac137e2b06 | ||
|
30d4c39ea9 | ||
|
15ea9e1a8f | ||
|
5a6ae99206 | ||
|
3588c49f3c | ||
|
ad8adfac19 | ||
|
49cea2d259 | ||
|
64349438ca | ||
|
a6c478025c | ||
|
a0d3d83ce2 | ||
|
ed9c1a0c0a | ||
|
526b1820ff | ||
|
cbf485cdea | ||
|
ab7d6ed739 | ||
|
da2c32a269 | ||
|
803b5d8d92 | ||
|
1899a62c8c | ||
|
92f2eb8653 | ||
|
e9f2386d88 | ||
|
c156cd24c4 | ||
|
489b73d104 | ||
|
bc7bde60c6 | ||
|
6731a79c9c | ||
|
65f445c878 | ||
|
5240492058 | ||
|
0e16fab256 | ||
|
6fb6a10dda | ||
|
37e04bc620 | ||
|
25effe198c | ||
|
b747d74a87 | ||
|
1c958ace90 | ||
|
11a9907d49 | ||
|
e42e610aba | ||
|
53bb5d6d92 | ||
|
1cc9e7feac | ||
|
434bb74929 | ||
|
8433609ea5 | ||
|
428642957c | ||
|
aad79d5364 | ||
|
5a4bf637b5 | ||
|
89a309fb33 | ||
|
ebc827ec9a | ||
|
1832a48f0e | ||
|
1403262cfe | ||
|
a722841c1d | ||
|
e745c8201a | ||
|
aec8f47942 | ||
|
ba1b8c33f1 | ||
|
2a5375d15f | ||
|
5cf762c89d | ||
|
6a3a1b1e9e | ||
|
16bb24a8d9 | ||
|
f5f0c31276 | ||
|
eb88e9c4f5 | ||
|
1a830e56cd | ||
|
77d412a246 | ||
|
486b4232fe | ||
|
7b631564db | ||
|
684caa5ffd | ||
|
f6cc00649c | ||
|
c07703d13f | ||
|
7e1f8f1817 | ||
|
faaec9aa54 | ||
|
cafc580ed5 | ||
|
d785036742 | ||
|
2b2c955143 | ||
|
e3163fc76d | ||
|
ccd8cb213e | ||
|
d611e7e45d | ||
|
ca5a7b8da1 | ||
|
cb56b5e5e2 | ||
|
c08f724a74 | ||
|
b423715f47 | ||
|
40e23532f3 | ||
|
e97c912fac | ||
|
3b2840f960 | ||
|
075a1f03ee | ||
|
e73b132674 | ||
|
84ee6a909f | ||
|
a0172d325c | ||
|
734be0ba3c | ||
|
33edf59bc7 | ||
|
0007e7c984 | ||
|
e37a6d2c11 | ||
|
1393bcdf1e | ||
|
7f10aecbb4 | ||
|
d7fe84ddc0 | ||
|
a228380812 | ||
|
49572e42d2 | ||
|
2fd33102d3 | ||
|
96c5582f01 | ||
|
55390d97c7 | ||
|
b6c30c4c6f | ||
|
0d8237679b | ||
|
3ca1f8b18a | ||
|
7e53df6924 | ||
|
47b711391a | ||
|
c7f445f167 | ||
|
b7396aee4c | ||
|
6b5d452292 | ||
|
b9462fb62f | ||
|
4dbca5afa8 | ||
|
b30fc8294c | ||
|
c95a6b37de | ||
|
6b6dfab52b | ||
|
da7fa2b830 | ||
|
419bf22958 | ||
|
3fccbd7dd9 | ||
|
7dfaf43d7c | ||
|
7a0df7de23 | ||
|
050fe46e9a | ||
|
8005406e87 | ||
|
0e9d9e2c4f | ||
|
61a89217a5 | ||
|
b586df82ef | ||
|
6f7459f96f | ||
|
da37e1ab80 | ||
|
75bc6de636 | ||
|
da487fa545 | ||
|
2dcaa4fe77 | ||
|
952f432058 | ||
|
3e427d2802 | ||
|
eb1d0f1700 | ||
|
52a0c5387b | ||
|
c139160a52 | ||
|
cbcf0d2473 | ||
|
ff1aa17c68 | ||
|
89cd76cf37 | ||
|
9ade028ef9 | ||
|
abc8952153 | ||
|
935d6a5fdc | ||
|
ab8ef76476 | ||
|
a9daf52b33 | ||
|
c8f18dee44 | ||
|
9cb59beef6 | ||
|
8b9f99adbf | ||
|
8617dc0d92 | ||
|
3385e3e2b7 | ||
|
c46655ef9f | ||
|
c1f851a0bd | ||
|
eb0c24c946 | ||
|
c1440a2964 | ||
|
47094219b6 | ||
|
8908bb3c37 | ||
|
4d53179ff5 | ||
|
cd28836d26 | ||
|
e67214a3a2 | ||
|
d5f5ddcddf | ||
|
bddc9bb40a | ||
|
7531a48c1f | ||
|
ef3ba845ed | ||
|
09e8740c04 | ||
|
8384054396 | ||
|
45fe443294 | ||
|
643370cfe0 | ||
|
797bf4db7b | ||
|
ecc6691cc6 | ||
|
96eb993106 | ||
|
651ace73d1 | ||
|
1bd727541a | ||
|
580e9e0bee | ||
|
9a88400fa5 | ||
|
888fd6ab32 | ||
|
e521f372a5 | ||
|
cef4396f7f | ||
|
edc5b9dd93 | ||
|
b00cfdceb4 | ||
|
06de7da7d8 | ||
|
513bba78ed | ||
|
f0040a97fc | ||
|
5287b81134 | ||
|
7b828ceba1 | ||
|
a1705f9823 | ||
|
651fa7d6d4 | ||
|
e10590bb9c | ||
|
010eaceba7 | ||
|
5271163b31 | ||
|
921f7a8e08 | ||
|
95e8b53cab | ||
|
f4ec4db8e5 | ||
|
3701a50c5b | ||
|
4a8dafea33 | ||
|
bb29436280 | ||
|
7638cdac4a | ||
|
46726bfa2e | ||
|
20db70bc3a | ||
|
030f79e69e | ||
|
0f767eb9f7 | ||
|
b7a51773c1 | ||
|
183e67d0e9 | ||
|
151fb346ad | ||
|
7b7b941c84 | ||
|
c43ddab79d | ||
|
c414984258 | ||
|
66f1508a24 | ||
|
505205089d | ||
|
d35883d2dc | ||
|
d965d43b83 | ||
5fd1f99430 | |||
|
a59e63369e | ||
|
86c9cc7c2c | ||
|
e65bd73f67 | ||
|
be877cc6e5 | ||
|
7096133313 | ||
|
56427c2894 | ||
|
2a2ef40e08 | ||
|
55fbf493dc | ||
|
ca6930a109 | ||
|
a60b719c4a | ||
|
cd151f8717 | ||
|
c7c0e5e4dd | ||
|
d33f464634 | ||
|
497f80e046 | ||
|
7868cf61e5 | ||
|
a61654241b | ||
|
8ba7c9387d | ||
|
900039eba6 | ||
|
6a581d3e72 | ||
|
8118d0bda6 | ||
|
8dd6e6dd1b | ||
|
8b72f51544 | ||
|
88e022a116 | ||
|
7ecdc0a862 | ||
|
8bb01bdbe7 | ||
|
daac76acb7 | ||
|
303cc050c6 | ||
|
7b06f10193 | ||
|
1dc3c6e30d | ||
|
0871a7cc5d | ||
|
a4082d0069 | ||
|
6ac604a810 | ||
|
98d5f97557 | ||
|
e1c3d13c39 | ||
|
a0aed9059c | ||
|
4e62c81e72 | ||
|
49b43beaac | ||
|
b1f3de12c7 | ||
|
58cdbf842b | ||
|
a588024d93 | ||
|
b16a844639 | ||
|
575160c5e0 | ||
|
9d32afeb30 | ||
|
02ff3bb45d | ||
|
ea98f0dc5d | ||
|
967bb771c4 | ||
|
c6647ff200 | ||
|
02dc1d325f | ||
|
1f07e7c451 | ||
|
d1b42cac03 | ||
|
697b91704a | ||
|
1e82d109c4 | ||
|
90823a41c7 | ||
|
81c82ea88d | ||
|
5d423e0227 | ||
|
e51bd8ae33 | ||
|
4e3e0a1278 | ||
|
d26895204e | ||
|
161d5f1481 | ||
|
50cd2bea80 | ||
|
93e22d1d5d | ||
|
8d2e93f9e8 | ||
|
28c58465da | ||
|
9663867b47 | ||
|
49f7afdc55 | ||
|
6bca833663 | ||
|
f34542d5d7 | ||
|
57f36a8893 | ||
|
2f089068ff | ||
|
b1f7b37ff0 | ||
|
4be462d122 | ||
|
ef6f8de3ce | ||
|
7fca1d5d3c | ||
|
9cb1db2e25 | ||
05592627f8 | |||
eb5dbf0a6c | |||
|
98b5fca350 | ||
|
a8fbdfec74 | ||
|
6203bfbc82 | ||
|
b17b82ff20 | ||
|
5e6432203d | ||
|
a9bff683f3 | ||
|
b4be186dda | ||
|
0434cf2700 | ||
|
8aa102b595 | ||
|
20a4d46013 | ||
|
bd4751d068 | ||
|
f45fd2e456 | ||
|
f6f0458dbb | ||
|
55094ebdc3 | ||
|
04cc604bd5 | ||
|
cf580c9522 | ||
|
74a92996e4 | ||
|
e0eae08fa1 | ||
|
a8067e9333 | ||
|
48f38cf561 | ||
|
b2a26954fd | ||
|
52e7e7c710 | ||
|
69f15066bb | ||
|
583b0fa1c9 | ||
|
07ca2676aa | ||
|
e138db25e5 | ||
|
67c72954db | ||
|
0f7a225106 | ||
|
988e005d4c | ||
|
6919d12ed5 | ||
|
5268c28fb5 | ||
|
d43163e574 | ||
|
1a362eb432 | ||
|
b59198473b | ||
|
a2389ce519 | ||
|
f5f255ea86 | ||
|
de459576de | ||
|
612ae0e652 | ||
|
8d3790df88 | ||
|
5072989303 | ||
|
b31beca2ec | ||
|
02fe880652 | ||
|
9a8fe9d80b | ||
|
4d4a52fc5e | ||
|
8fde2e5c3a | ||
|
8ef461432f | ||
|
fff9c55a98 | ||
|
b9bc7a6c43 | ||
|
d9e4aaa664 | ||
|
9e01fd7c40 | ||
|
bd0c5c4e09 | ||
|
989bef6130 | ||
|
7bc581e77a | ||
|
da09581f92 | ||
f3522e7b5e | |||
|
89d14027f0 | ||
|
469244dacf | ||
|
d2531eeb81 | ||
|
24359052f4 | ||
|
ffe3988a46 | ||
|
b3aa15e8e6 | ||
|
e74d29f742 | ||
|
ce87e71c48 | ||
|
884887fe3c | ||
|
73b35183aa | ||
|
13c9915305 | ||
|
138d356476 | ||
|
f6ea92b523 | ||
|
08e9ec6a2f | ||
|
b07dfc9386 | ||
|
63762bfcd9 | ||
|
755c541c29 | ||
|
15509d0cff | ||
|
025cc272c5 | ||
|
fff29f3b53 | ||
|
c636ab6029 | ||
|
e7406a997b | ||
|
13db045dd2 | ||
|
b437701540 | ||
|
5f06519bdc | ||
|
4f36bb74ae | ||
|
9c85e6132f | ||
|
d132224b31 | ||
|
d0019abfc6 | ||
|
00fa203f48 | ||
|
44e49146de | ||
|
b09e015234 | ||
|
73bef37e54 | ||
|
ec3b1e1f2b | ||
|
97496beeb7 | ||
|
4f88a29c8f | ||
|
3d75dbc7d5 | ||
c602a641ae | |||
|
2987d3f4f8 | ||
|
b9be5cc943 | ||
|
8db7dd714d | ||
|
60066950e7 | ||
|
373762c912 | ||
|
172a263856 | ||
|
eb5eb804f1 | ||
|
a2f4a82f57 | ||
|
2fa3e5090f | ||
|
e045a9e047 | ||
|
f1d7a42658 | ||
|
6318f12de2 | ||
|
46ce506107 | ||
|
95796946d9 | ||
|
0fb71bc3b6 | ||
|
aaff2825d2 | ||
|
44191cc68a | ||
|
8fbd03739d | ||
|
02671a38d6 | ||
|
44e7d811aa | ||
|
6e8036f619 | ||
|
7e785b9e1d | ||
|
582743f079 | ||
|
8adacee0a0 | ||
|
222e3a68ee | ||
|
23236a9b08 | ||
|
eec6ce53f5 | ||
|
6bb9c351a5 | ||
|
66a642f918 | ||
|
c500553d8b | ||
|
deb591208f | ||
|
d38f83c3c2 | ||
|
3e74f3ecb4 | ||
|
e908db97f8 | ||
|
4979e4049b | ||
|
07a24e3d5e | ||
|
f4c0f754bc | ||
|
d10703369f | ||
|
1996730456 | ||
|
63ba0d0895 | ||
|
02b50c8721 | ||
|
ed98550088 | ||
|
82da91c96c | ||
6dc260a173 | |||
0eb913bba5 | |||
2af0c3b088 | |||
|
3f1b95dc49 | ||
|
9dabbcdb9c | ||
|
ead1adfc46 | ||
|
9b2c5ad257 | ||
|
d68205c1d5 | ||
|
fac9142b62 | ||
cabbdac3f5 | |||
|
ba3bdf5f38 | ||
|
f0f73fd24c | ||
|
a1b2c69441 | ||
|
781fc20d16 | ||
2cb6e86f93 | |||
|
6cd3c0b47a | ||
|
ff6c60b156 | ||
|
cdc7e59e38 | ||
|
8b248a75ff | ||
|
5cd3309251 | ||
8a24f617ec | |||
|
e11d514c7f | ||
|
677c2c716f | ||
|
2ad6b49479 | ||
|
e5f6d798b6 | ||
|
86803f893b | ||
|
16e0206063 | ||
|
14cc2f88e1 | ||
|
a86651fafb | ||
|
4187e0bf14 | ||
|
33ff5ff1af | ||
|
941c4f4dc2 | ||
|
23e6b585cc | ||
|
56c5a6c367 | ||
|
6274c6d3f9 | ||
|
2c2bcbffc6 | ||
|
eee838ee2c | ||
|
a9d91c8158 | ||
|
3d210bcf28 | ||
|
919e941aa1 | ||
|
7307da74d0 | ||
|
d23eb14f0a | ||
|
4915a5c24f | ||
|
e8a47c3404 | ||
|
efba7faf92 | ||
|
916bc643ec | ||
|
31855f912e | ||
|
3b3854e6f3 | ||
|
ea95b2468e | ||
|
81cc75d320 | ||
|
ba32b37941 | ||
|
d5936462a8 | ||
cec8287c3f | |||
|
49b7df2d2d | ||
|
d9b9fac0a1 | ||
|
e70d1fe12b | ||
|
72dfdd7172 | ||
|
af2ff4002c | ||
|
f90f091cba | ||
|
35354c6117 | ||
|
419af0403d | ||
|
6e9ee59ac7 | ||
|
caf7a0a558 | ||
348ebc3bc2 | |||
|
79e4bb27c0 | ||
|
02a446d8b9 | ||
|
6d64b53ac7 | ||
|
ff3db071b9 | ||
|
dfa2199332 | ||
|
07176e8ff0 | ||
|
baa1fa5327 | ||
|
704cc582f1 | ||
|
605f228937 | ||
|
dbb42cdd1b | ||
|
10e3f0b8f7 | ||
|
05a98e4aef | ||
|
4d673a650b | ||
|
67a998c8b2 | ||
|
52b0358e09 | ||
|
78c0aab5a5 | ||
|
6c5f1f7438 | ||
|
339f414515 | ||
|
7308a5b1fa | ||
|
108c27c8ad | ||
|
8f1fa9de6d | ||
|
9c4517df58 | ||
|
ea6500ae35 | ||
|
247786bc5c | ||
|
c10f57d7d5 | ||
|
e848e346d1 | ||
|
bafcba3269 | ||
|
0669cacb6a | ||
|
b01c0b9aff | ||
|
c7a1caba8a | ||
|
c10c255f2d | ||
|
d903a1da07 | ||
|
78c704beba | ||
|
abc4ef1c80 | ||
|
35d863fa4a | ||
|
a18a6032fd | ||
|
21c8d79c71 | ||
|
f725ea1acd | ||
|
b6ff572965 | ||
|
e0a55a18be | ||
|
9f39b162d0 | ||
|
3a073ed4bd | ||
|
879a350963 | ||
|
53a683fe07 | ||
|
8706f118eb | ||
|
f340ab8635 | ||
|
6f8c5ec69e | ||
|
dbde622c27 | ||
|
c9eb2593cf | ||
|
e60f112959 | ||
|
3ed29c1f37 | ||
|
58ad4a8c87 | ||
|
76757b5cf0 | ||
|
ec125653d6 | ||
|
1132e39eeb | ||
|
8d43f62910 | ||
|
44e2a8ca6e | ||
|
0e8bb053f9 | ||
|
46ad2a266d | ||
|
af3a468654 | ||
|
6bea55b8d2 | ||
|
e6c594e4dd | ||
|
76660f6ca7 | ||
|
b037b2f1d7 | ||
|
8a94509dc6 | ||
|
193a0b2270 | ||
|
5206813efe | ||
|
582bdb1507 | ||
|
ad456ee5a9 | ||
|
7154cc48fe | ||
|
d09c9142e8 | ||
|
c709c45413 | ||
|
bbf495a8ce | ||
|
5686a8b5ae | ||
|
2d39033930 | ||
|
01fea8a0f0 | ||
|
54eae13ef4 | ||
|
0be84e8fa0 | ||
|
b7b7d2b01c | ||
|
eef112fbd2 | ||
|
304be089ee | ||
|
839745a48f | ||
|
491bc80181 | ||
|
f03d8a0090 | ||
87e4de6084 | |||
|
35da27cbab | ||
|
019a3028d6 | ||
|
b10bceac79 | ||
|
00a0087d2b | ||
|
ce53616c6b | ||
|
98fe14560b | ||
|
23cf5da832 | ||
|
66b458e53a | ||
|
7663e0ca68 | ||
|
030127933e | ||
|
d4b1366dae | ||
|
e7b31f410c | ||
|
424ece83d0 | ||
|
7042fbc3ce | ||
|
49ae347b1a | ||
|
889a002884 | ||
|
0b70d9800d | ||
|
41d5c0d536 | ||
|
e9af9d2dba | ||
|
16b1608856 | ||
|
f6ae39c70b | ||
|
9feff82fac | ||
|
323376b8e0 | ||
|
13316fc3c2 | ||
|
88e4d42c55 | ||
|
fcb72a9b5c | ||
|
16803cc7f1 | ||
|
0607942243 | ||
|
b06fa2b659 | ||
|
eb0efc0d5c | ||
|
adef4eb786 | ||
|
e6518f69e9 | ||
|
ecdce37046 | ||
|
25033cfacc | ||
|
03132c0dd5 | ||
|
a29d3220f0 | ||
|
28567ed365 | ||
|
5c627a44cd | ||
|
4bbccde8f7 | ||
|
b04c2e38a3 | ||
|
38f52e637f | ||
|
7a2f8edc5f | ||
|
a0cc91b24c | ||
|
afa05760f1 | ||
|
410ea26b0e | ||
|
41e661505b | ||
|
58575efa9d | ||
|
2910c2e921 | ||
|
99d7c3a5b5 | ||
|
094ffccbdc | ||
|
d006f3da4d | ||
|
49c8980bb1 | ||
|
b072f98787 | ||
|
3b2540a2fc | ||
|
944fcc6095 | ||
|
b4e29e7c3b | ||
|
5df3dbf911 | ||
|
800614ea0d | ||
|
dc760f17c7 | ||
|
7805f1fbe6 | ||
|
0cac30a0e1 | ||
|
b5e8481848 | ||
|
43402f3eba | ||
|
52a42ce3dc | ||
|
f92ec16f8e | ||
|
42a24c4136 | ||
|
d4e8617eef | ||
|
33a64665ea | ||
|
af3eee47ae | ||
|
72683fdab0 | ||
|
c9b86b8853 | ||
|
dc700749a2 | ||
|
9cc9b70c54 | ||
|
de4aa58e2a | ||
|
ceeb125ba9 | ||
|
a671e237a0 | ||
|
d1d0880ceb | ||
|
2235eefe09 | ||
|
c60156f6e6 | ||
|
c3826a5416 | ||
|
92b2179abf | ||
|
e2bfc62c02 | ||
|
dd1fc4a04e | ||
|
65b73b3c40 | ||
|
5df25dd3e2 | ||
|
de4e0f1e14 | ||
|
39faad3430 | ||
|
9bd92dca96 | ||
|
6734542fac | ||
|
2adac042ae | ||
|
e3addef78d | ||
|
0b5a3990ad | ||
|
9e61816983 | ||
|
698071fa00 | ||
|
cb27feffd6 | ||
|
341df0375f | ||
|
de504d626f | ||
|
6d20bdc430 | ||
|
8d43fc8aa5 | ||
|
6ca0a39686 | ||
|
4f5b94f83b | ||
|
42e2ee6e39 | ||
|
25ccb39fa0 | ||
|
a1172a1695 | ||
|
64d13509bf | ||
d008f5a5f0 | |||
|
594ff1d642 | ||
|
bcedb464b0 | ||
|
b5053fabe2 | ||
|
c9b8d13261 | ||
|
1ba8f32464 | ||
|
f86df19b7d | ||
|
b04b5d3519 | ||
|
7b181bd71a | ||
|
daf3393398 | ||
|
0d19b89e78 | ||
|
da23a245a2 | ||
|
2d21f674ff | ||
|
cc6c997e58 | ||
|
4362ce7028 | ||
|
8228f2dc13 | ||
|
2f8b0f4ce3 | ||
|
e33ec1466e | ||
|
a30cac6822 | ||
|
b2afe183fe | ||
|
75c1c8a7a0 | ||
|
9a97d3087d | ||
|
688927fd53 | ||
de9bf3d308 | |||
72f977f19b | |||
|
ca7e1efdfe | ||
|
a6278fb671 | ||
|
cd190843ab | ||
|
b2db430510 | ||
|
8fc34e3f4a | ||
|
b7f2928d4a | ||
|
5adacfba98 | ||
|
ddf80158a9 | ||
|
b3cd2b53dc | ||
|
0f455a69a5 | ||
|
1d031aa262 | ||
|
bde58c0298 | ||
|
4581506883 | ||
|
dab8b99c9c | ||
|
855da15b23 | ||
|
9f65dedda9 | ||
|
e7abf704c5 | ||
|
d8d054f8fa | ||
|
646314051b | ||
|
9d788f010f | ||
|
903a630fd0 | ||
|
5d6cbbd3a6 | ||
|
b2fcdf1d32 | ||
|
ef26fb3f57 | ||
|
ab661ccc06 | ||
|
a47cea481f | ||
|
5a5b7f127b | ||
|
3e1801faa0 | ||
|
fec05e98bf | ||
|
536d990ee1 | ||
|
43465bfd35 | ||
|
7cd7c4b897 | ||
|
069f527445 | ||
|
801c33a832 | ||
|
b4bd84cd03 | ||
|
83d02ea7ff | ||
|
ed015569a7 | ||
|
416f8c4ceb | ||
|
58a4fb601a | ||
|
7715e09bef | ||
|
65c8f4790e | ||
|
46148e7fb6 | ||
|
ecde592124 | ||
|
202cb8c222 | ||
|
287468005a | ||
|
b8d932d050 | ||
|
4e4d5426e0 | ||
|
2f82d097b6 | ||
|
a2818218c6 | ||
|
378eb9916c | ||
|
aef7b4c012 | ||
|
f9167b929f | ||
|
e3cbf2309d | ||
|
5ac608b43f | ||
|
90ad79e846 | ||
|
21189acdb0 | ||
|
68a367bea7 | ||
|
0716ed2fe4 | ||
|
c7216f18b2 | ||
|
5a69f4b8e3 | ||
|
d06d2cb476 | ||
|
a162a40a46 | ||
|
523cad12bc | ||
|
2ddceae4a3 | ||
|
25a8c10165 | ||
|
48e8c5bb73 | ||
|
5bd4280e83 | ||
|
a6d66e0a65 | ||
|
64d161d09d | ||
|
e0ec6c1164 | ||
|
debcacc1ba | ||
|
946a32fd96 | ||
|
540215bc5d | ||
|
7ee1d71d13 | ||
|
5362627433 | ||
|
83cb642448 | ||
|
84b265cbe4 | ||
|
5e2dc9da2f | ||
|
93b1f0d915 | ||
|
1149e0e1bd | ||
|
3463bf8521 | ||
|
9b0fbf1256 | ||
|
90a2ced901 | ||
|
8d550ccf7e | ||
|
dd305fa8a8 | ||
|
093d754b74 | ||
|
4068b85470 | ||
|
454d819634 | ||
|
ab914472f0 | ||
|
5543f8c2e9 | ||
|
20e29bcf75 | ||
|
a948173f15 | ||
|
5dd8186103 | ||
|
4294aa0d6b | ||
|
7ba5e7bd99 | ||
|
ba943c61c9 | ||
|
c2eab08582 | ||
|
cbd2475cf9 | ||
|
1698a7a644 | ||
|
b54c4ec103 | ||
|
6902238f1a | ||
|
79476b0a84 | ||
|
e8cef12319 | ||
|
6b9bc3c00f | ||
|
1dd3c10103 | ||
|
77de3cb541 | ||
|
2ad95e3d5a | ||
|
ef63045632 | ||
|
357171fec5 | ||
|
fee32792f9 | ||
|
3b54299f9a | ||
|
aeebf3bb61 | ||
|
2692f1fbb5 | ||
|
d1bb63ff49 | ||
|
73091981a9 | ||
|
69ee9387e3 | ||
|
cd7ffc9e99 | ||
|
d14b39970b | ||
|
3b264e5297 | ||
|
3159c6bcee | ||
|
13df90493c | ||
|
48301a53ac | ||
|
e2a18275b7 | ||
|
6d639b1ad7 | ||
|
319f922eb8 | ||
|
7db0650b53 | ||
|
34a586d449 | ||
|
c0db3f2ae2 | ||
|
406040364a | ||
|
7593e0460a | ||
|
7583ca1959 | ||
|
acce31d4c9 | ||
|
9e3a5cc22c | ||
|
104a0bee05 | ||
|
09294f3111 | ||
|
b1d874ca85 | ||
|
33ae31abc8 | ||
|
ba82756c74 | ||
|
69b5a886cb | ||
|
b260cc6cca | ||
|
009132ce78 | ||
|
9fcf59d3d9 | ||
|
8dde29cc0d | ||
|
bb92781cce | ||
|
dd0dc1ff12 | ||
|
4380ca19f0 | ||
|
c91386cca0 | ||
|
7926243de5 | ||
|
61247972c0 | ||
|
b630ddf2e8 | ||
|
3f197fc96b | ||
|
7aeb04936d | ||
|
15dd359787 | ||
|
e19c9e6bc2 | ||
|
39209a8b6a | ||
|
9591198ecb | ||
|
9208b951f2 | ||
|
2a6cc63d82 | ||
|
214699639c | ||
|
d15360fc1c | ||
|
2dc7f10334 | ||
|
5b1ab2ecb1 | ||
|
eeb8579122 | ||
|
2a992a4582 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -54,7 +54,6 @@ sftp-config.json
|
||||
|
||||
# =========================
|
||||
# Exclude these dirs commonly found in /usr/local
|
||||
bin/
|
||||
games/
|
||||
info/
|
||||
lib64/
|
||||
@@ -69,3 +68,8 @@ emhttp/plugins/dynamix.my.servers/unraid-components/index.html
|
||||
|
||||
# development scripts
|
||||
.dev-scripts/
|
||||
emhttp/plugins/node_modules/
|
||||
emhttp/plugins/.prettierignore
|
||||
emhttp/plugins/.prettierrc
|
||||
emhttp/plugins/package-lock.json
|
||||
emhttp/plugins/package.json
|
77
.vscode/settings.json
vendored
77
.vscode/settings.json
vendored
@@ -4,5 +4,80 @@
|
||||
},
|
||||
"prettier.tabWidth": 4,
|
||||
"editor.tabSize": 4,
|
||||
"editor.indentSize": "tabSize"
|
||||
"editor.indentSize": "tabSize",
|
||||
"intelephense.stubs": [
|
||||
"apache",
|
||||
"bcmath",
|
||||
"bz2",
|
||||
"calendar",
|
||||
"com_dotnet",
|
||||
"Core",
|
||||
"ctype",
|
||||
"curl",
|
||||
"date",
|
||||
"dba",
|
||||
"dom",
|
||||
"enchant",
|
||||
"exif",
|
||||
"FFI",
|
||||
"fileinfo",
|
||||
"filter",
|
||||
"fpm",
|
||||
"ftp",
|
||||
"gd",
|
||||
"gettext",
|
||||
"gmp",
|
||||
"hash",
|
||||
"iconv",
|
||||
"imap",
|
||||
"intl",
|
||||
"json",
|
||||
"ldap",
|
||||
"libxml",
|
||||
"mbstring",
|
||||
"meta",
|
||||
"mysqli",
|
||||
"oci8",
|
||||
"odbc",
|
||||
"openssl",
|
||||
"pcntl",
|
||||
"pcre",
|
||||
"PDO",
|
||||
"pdo_ibm",
|
||||
"pdo_mysql",
|
||||
"pdo_pgsql",
|
||||
"pdo_sqlite",
|
||||
"pgsql",
|
||||
"Phar",
|
||||
"posix",
|
||||
"pspell",
|
||||
"random",
|
||||
"readline",
|
||||
"Reflection",
|
||||
"session",
|
||||
"shmop",
|
||||
"SimpleXML",
|
||||
"snmp",
|
||||
"soap",
|
||||
"sockets",
|
||||
"sodium",
|
||||
"SPL",
|
||||
"sqlite3",
|
||||
"standard",
|
||||
"superglobals",
|
||||
"sysvmsg",
|
||||
"sysvsem",
|
||||
"sysvshm",
|
||||
"tidy",
|
||||
"tokenizer",
|
||||
"xml",
|
||||
"xmlreader",
|
||||
"xmlrpc",
|
||||
"xmlwriter",
|
||||
"xsl",
|
||||
"Zend OPcache",
|
||||
"zip",
|
||||
"zlib",
|
||||
"libvirt-php"
|
||||
]
|
||||
}
|
||||
|
@@ -256,7 +256,7 @@ Unraid OS uses these default options when creating a multiple-device pool:
|
||||
|
||||
`-dconvert=raid1 -mconvert=raid1`
|
||||
|
||||
For more complete documentation, please refer to the btrfs-balance [Manpage](https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs-balance)
|
||||
For more complete documentation, please refer to the btrfs-balance [Manpage](https://man7.org/linux/man-pages/man8/btrfs-balance.8.html)
|
||||
|
||||
*Note: raid5 and raid6 are generally still considered **experimental** by the Linux community*
|
||||
:end
|
||||
@@ -664,6 +664,8 @@ will *hide* the share from *browsing* but is still accessible if you know the sh
|
||||
:smb_time_machine_volume_help:
|
||||
This limits the reported volume size, preventing Time Machine from using the entire real disk space
|
||||
for backup. For example, setting this value to "1024" would limit the reported disk space to 1GB.
|
||||
Note that Ventura 13.6 and later require a value to be present. No entry will prevent Time Machine
|
||||
from working correctly.
|
||||
:end
|
||||
|
||||
:smb_case_sensitive_names_help:
|
||||
@@ -941,6 +943,18 @@ A value of zero will disable the warning threshold (including notifications).
|
||||
A value of zero will disable the critical threshold (including notifications).
|
||||
:end
|
||||
|
||||
:ssd_default_warning_temperature_help:
|
||||
*Warning SSD temperature* sets the default warning threshold for all SSD devices temperature. Exceeding this threshold will result in a warning notification.
|
||||
|
||||
A value of zero will disable the warning threshold (including notifications).
|
||||
:end
|
||||
|
||||
:ssd_default_critical_temperature_help:
|
||||
*Critical disk temperature* sets the default critical threshold for all SSD devices temperature. Exceeding this threshold will result in an alert notification.
|
||||
|
||||
A value of zero will disable the critical threshold (including notifications).
|
||||
:end
|
||||
|
||||
:disk_default_smart_notification_help:
|
||||
SMART notifications are generated on either an increasing RAW value of the attribute, or a decreasing NORMALIZED value which reaches a predefined threshold set by the manufacturer.
|
||||
|
||||
@@ -994,6 +1008,10 @@ Instead of chevrons indicating more data for Port and Volume mapping, all data i
|
||||
The time in seconds to allow a container to gracefully stop before forcing it to stop
|
||||
:end
|
||||
|
||||
:docker_pid_limit_help:
|
||||
Set a PID Limit to limit the number of PIDs that a docker can use. The default is 2048. Set to zero for unlimited PIDs (not recommended).
|
||||
:end
|
||||
|
||||
:docker_vdisk_type_help:
|
||||
Select where to keep the Docker persistent state.
|
||||
|
||||
@@ -1020,6 +1038,15 @@ You must specify a folder for Docker. The system will automatically create this
|
||||
It is recommended to create this folder under a share which resides on the Cache pool (setting: cache=Only). For best performance SSD devices are preferred.
|
||||
:end
|
||||
|
||||
:docker_storage_driver_help:
|
||||
overlay2 (default): Will use overlay2 as the storage driver for Docker, regardless of the underlying filesystem.
|
||||
|
||||
native: The native storage driver for your underlying filesystem will be used (XFS: overlay2 | ZFS: zfs | BTRFS: btrfs).
|
||||
|
||||
ATTENTION: Changing the storage type from an existing Docker installation is not possible, you have to delete your Docker directory first, change the storage type and then reinstall your containers.
|
||||
It is recommended to take a screenshot from your Docker containers before changing the storage type. After deleting and changing the storage type, reinstall the containers by clicking Add Container on the Docker page and select one by one from the drop down to reinstall them with your previous settings).
|
||||
:end
|
||||
|
||||
:docker_appdata_location_help:
|
||||
You can specify a folder to automatically generate and store subfolders containing configuration files for each Docker app (via the /config mapped volume).
|
||||
|
||||
@@ -1101,6 +1128,10 @@ This is the active Docker version.
|
||||
This is the location of the Docker image.
|
||||
:end
|
||||
|
||||
:docker_storage_driver_active_help:
|
||||
This is the storage driver for Docker.
|
||||
:end
|
||||
|
||||
:docker_appdata_location_active_help:
|
||||
This is the storage location for Docker containers.
|
||||
:end
|
||||
@@ -1189,7 +1220,7 @@ SSL certificate. Use this URL to access your server:
|
||||
Note that use of a self-signed SSL certificate will generate a browser
|
||||
warning.
|
||||
|
||||
Select **Strict** to enable *exclusive* use of an Unraid.net SSL
|
||||
Select **Strict** to enable *exclusive* use of a myunraid.net SSL
|
||||
certificate for https access (see **Provision** below). Note that a DNS
|
||||
server must be reachable.
|
||||
|
||||
@@ -1252,11 +1283,19 @@ The Local Access URLs shown above are based on your current settings.
|
||||
To adjust URLs or redirects, see the help text for "Use SSL/TLS".
|
||||
:end
|
||||
|
||||
:mgmt_wg_access_urls_help:
|
||||
These URLs will only work when connected via the appropriate WireGuard tunnel as configured on ***Settings > VPN Manager***
|
||||
:end
|
||||
|
||||
:mgmt_tailscale_access_urls_help:
|
||||
These URLs will only work when connected to the appropriate Tailscale Tailnet.
|
||||
:end
|
||||
|
||||
:mgmt_certificate_expiration_help:
|
||||
**Provision** may be used to install a *free* Unraid.net SSL Certificate from
|
||||
**Provision** may be used to install a *free* myunraid.net SSL Certificate from
|
||||
[Let's Encrypt](https://letsencrypt.org/).
|
||||
|
||||
The Unraid.net SSL certificate can be used in two ways. First,
|
||||
The myunraid.net SSL certificate can be used in two ways. First,
|
||||
having the certificate present enables your server to respond to an
|
||||
alternate URL of the form:
|
||||
|
||||
@@ -1270,24 +1309,20 @@ set to `*.<hash>.myunraid.net` thus validating the https connection.
|
||||
You may enable this URL exclusively on your LAN by setting **Use
|
||||
SSL/TLS** to **Strict**.
|
||||
|
||||
The second use for an Unraid.net certificate is to enable secure
|
||||
remote access available through the My Servers plugin feature. Note
|
||||
The second use for a myunraid.net certificate is to enable secure
|
||||
remote access available through the Unraid Connect plugin feature. Note
|
||||
that it is possible to use secure remote access in conjunction with
|
||||
insecure local access.
|
||||
|
||||
After an Unraid.net SSL Certificate has been installed, two
|
||||
background services are activated while the server is signed in to unraid.net:
|
||||
|
||||
- *updatedns* - This starts 30 seconds after server reboot has completed and contacts the Lime Technology
|
||||
DNS service to register the servers local IP address. Thereafter it wakes up every 10 minutes in case
|
||||
the local IP address has changed.
|
||||
After a myunraid.net SSL Certificate has been installed, a
|
||||
background service is activated:
|
||||
|
||||
- *renewcert* - This starts 60 seconds after server reboot has completed and contacts the Lime Technology
|
||||
certificate renewal service to determine if your Unraid.net SSL certificate needs to be renewed.
|
||||
certificate renewal service to determine if your myunraid.net SSL certificate needs to be renewed.
|
||||
Thereafter it wakes up every 24 hours. If within 30 days of expiration, a new certificate is automatically
|
||||
provisioned and downloaded to your server.
|
||||
|
||||
**Delete** may be used to delete the Unraid.net certificate file.
|
||||
**Delete** may be used to delete the myunraid.net certificate file.
|
||||
|
||||
**nginx certificate handling details**
|
||||
|
||||
@@ -1295,7 +1330,7 @@ nginx makes use of two certificate files stored on the USB flash boot device:<br
|
||||
|
||||
- a self-signed certificate: `config/ssl/certs/<server-name>_unraid_bundle.pem`
|
||||
|
||||
- an Unraid.net certificate: `config/ssl/certs/certificate_bundle.pem`
|
||||
- a myunraid.net certificate: `config/ssl/certs/certificate_bundle.pem`
|
||||
|
||||
The self-signed SSL certificate file is automatically created when nginx
|
||||
starts; and re-created if the server hostname or local TLD is changed.
|
||||
@@ -1479,7 +1514,7 @@ This will increase write performance but might possibly decrease read performanc
|
||||
Let the server act as a central syslog server and collect syslog messages from other systems.
|
||||
The server can listen on UDP, TCP or both with a selectable port number.
|
||||
|
||||
Syslog information is stored per IP address. That is every system gets its own syslog file.
|
||||
Syslog information is stored either per IP address or per hostname. That is every system gets its own syslog file.
|
||||
:end
|
||||
|
||||
:syslog_local_folder_help:
|
||||
@@ -1487,6 +1522,15 @@ Select the share folder where the syslogs will be stored.
|
||||
It is recommended that you use a share located on the cache drive to prevent array disk spinups.
|
||||
:end
|
||||
|
||||
:syslog_remote_system_identifier_help:
|
||||
Select the identifier for the remote system (used in the logfile name).
|
||||
|
||||
* "IP Address" uses the IP address (IPv4 or IPv6) of the sending system.
|
||||
* "Hostname (from syslog message)" uses the hostname included in each syslog message.
|
||||
* "Hostname (from DNS reverse lookup)" performs a DNS reverse lookup for the sending IP and uses the result.
|
||||
|
||||
:end
|
||||
|
||||
:syslog_local_rotation_help:
|
||||
By default LOG rotation is disabled and will create a single LOG file of unlimited size.
|
||||
|
||||
@@ -1513,6 +1557,13 @@ Change this setting to YES when troubleshooting is required and it is not possib
|
||||
A mirror of the syslog file is stored in the **logs** folder of the flash device.
|
||||
:end
|
||||
|
||||
:syslog_shutdown_flash_help:
|
||||
This setting is YES by default and enables the system to copy the syslog file to the USB device on shutdown or reboot.
|
||||
|
||||
After rebooting, the syslog from this run will be visible on Tools > Syslog > syslog-previous;
|
||||
it will also be included in diagnostics as logs/syslog-previous.txt
|
||||
:end
|
||||
|
||||
:confirm_reboot_help:
|
||||
Choose if rebooting or powering down the server needs a confirmation checkbox.
|
||||
:end
|
||||
@@ -1527,6 +1578,12 @@ The display settings below determine how items are displayed on screen. Use thes
|
||||
You can experiment with these settings as desired, they only affect visual properties.
|
||||
:end
|
||||
|
||||
:display_width_help:
|
||||
**Boxed** is the legacy setting which constrains the content width to maximum 1920 pixels
|
||||
|
||||
**Unlimited** allows content to use all available width, which maybe useful on wide screens
|
||||
:end
|
||||
|
||||
:display_font_size_help:
|
||||
Changes the font size in the GUI. This is a per device setting.
|
||||
:end
|
||||
@@ -1577,10 +1634,18 @@ Selects the temperature unit for the disk temperature thresholds. Changing the u
|
||||
Make sure any newly entered values represent the selected temperature unit.
|
||||
:end
|
||||
|
||||
:display_favorites_enabled_help:
|
||||
Enables favorite support. If set to no, will stop heart icon showing for additions. If existing favorites are saved, favorites tab and pre-saved options will still continue to show and function until all are deleted.
|
||||
:end
|
||||
|
||||
:vms_enable_help:
|
||||
Stopping the VM Manager will first attempt to shutdown all running VMs. After 60 seconds, any remaining VM instances will be terminated.
|
||||
:end
|
||||
|
||||
:vms_disable_help:
|
||||
Stop VMs from Autostarting\Starting when VM Manager starts or open is run from the gui to start, error message will be seen.
|
||||
:end
|
||||
|
||||
:vms_libvirt_volume_help:
|
||||
This is the libvirt volume.
|
||||
:end
|
||||
@@ -1644,6 +1709,18 @@ For setting the console options to show on context menus. Web will show only inb
|
||||
Virtual Manager Remote Viewer will only show the Remote Viewer option. Both will show both Web and Remote Viewer.
|
||||
:end
|
||||
|
||||
:vms_rdpopt_help:
|
||||
Adds option to menu to start RDP. RDP file is downloaded. You need to set browser to open when ready.
|
||||
:end
|
||||
|
||||
:vms_usage_help:
|
||||
Show metrics for CPU both guest and host percentage, memory, disk io and network io.
|
||||
:end
|
||||
|
||||
:vms_usage_timer_help:
|
||||
Setting in seconds for metrics refresh time.
|
||||
:end
|
||||
|
||||
:vms_acs_override_help:
|
||||
*PCIe ACS override* allows various hardware components to expose themselves as isolated devices.
|
||||
Typically it is sufficient to isolate *Downstream* ports.
|
||||
@@ -1910,6 +1987,10 @@ Enter the *device* which corresponds to your situation, only applicable when *UP
|
||||
+ **modbus** - /dev/tty**
|
||||
:end
|
||||
|
||||
:apc_ups_override_ups_capacity_help:
|
||||
If your device doesn't natively report Nominal Power (`NOMPOWER`) from `apcupsd`, but does report the Load Percentage (`LOADPCT`), you can manually define the UPS capacity rating in Watts (W) (this is the 'real power' value in Watts (W), not the 'apparent power' in Volt Amps (VA), and should be detailed on your UPS manual or product listing) and the plugin will dynamically calculate a virtual Nominal Power estimate (`≈`) by comparing the Override UPS Capacity (W) and the current Load Percentage. It is only an estimate, as it doesn't factor in things like the UPS' efficiency.
|
||||
:end
|
||||
|
||||
:apc_battery_level_help:
|
||||
If during a power failure, the remaining battery percentage (as reported by the UPS) is below or equal to *Battery level*, apcupsd will initiate a system shutdown.
|
||||
:end
|
||||
@@ -2355,7 +2436,7 @@ Note to Cloudflare users: the Cloudflare proxy is designed for http traffic, it
|
||||
|
||||
:wg_local_server_uses_nat_help:
|
||||
When NAT is enabled, the server uses its own LAN address when forwarding traffic from the tunnel to other devices in the LAN network.
|
||||
Use this setting when no router modifications are desired, but this approach doesn't work with Docker containers using custom IP addressess.
|
||||
Use this setting when no router modifications are desired, but this approach doesn't work with Docker containers using custom IP addresses.
|
||||
|
||||
When NAT is disabled, the server uses the WireGuard tunnel address when forwarding traffic.
|
||||
In this case it is required that the default gateway (router) has a static route configured to refer tunnel address back to the server.
|
||||
@@ -2430,3 +2511,69 @@ Any 3rd party driver installed by a plugin will have a support symbol next to it
|
||||
|
||||
Click the edit button to add/modify/delete any modprobe.d config file in the config/modprobe.d directory on the flash drive.
|
||||
:end
|
||||
|
||||
:console_keyboard_help:
|
||||
Select your default keymap for the local console (not the web Terminal).
|
||||
:end
|
||||
|
||||
:console_screen_help:
|
||||
**Default:** 'Default' will set the blank timeout to 15 minutes and powersave to 60 minutes.
|
||||
|
||||
**Disabled:** 'Disabled' will disable the blank and powersave timeout.
|
||||
|
||||
**All other values:** Will set the blank timout to the selected value and disable the powersave timeout.
|
||||
:end
|
||||
|
||||
:console_bash_help:
|
||||
If set to 'Yes' the bash history will persist reboots, set to 'No' to disable.
|
||||
|
||||
**ATTENTION:** The bash history will be written to the USB Boot device so this will introduce higher wear and tear!
|
||||
|
||||
**Note:** Disabling and Enabling will remove the entire bash history.
|
||||
:end
|
||||
|
||||
:WOL_intro_help:
|
||||
This page allows the setup to start/resume and stop VMs, Containters(Docker and LXC) using WOL magic packets
|
||||
|
||||
It does not setup wake up of the Unraid server.
|
||||
|
||||
The process will look for the defined mac address defined within the service(VM or container) with the exception of dockers. Dockers do not have a mac address until they are running so you will need to define a user mac address to allow you to start them
|
||||
|
||||
If the service is paused a WOL Packet will resume.
|
||||
|
||||
For each service you can set: enable, disable or enable and shutdown
|
||||
|
||||
When the enable and shutdown is set if the service is running when the next WOL packet is recieved a shutdown will be performed.
|
||||
:end
|
||||
|
||||
:WOL_enable_help:
|
||||
If set to yes Unraidwold daemon is set to run.
|
||||
:end
|
||||
|
||||
:WOL_run_docker_help:
|
||||
If set to yes when wake on lan packets are received checks are carrried out for dockers otherwise dockers will be ignored.
|
||||
:end
|
||||
|
||||
:WOL_run_VM_help:
|
||||
If set to yes when wake on lan packets are received checks are carrried out for virtual machines otherwise virtual machines will be ignored.
|
||||
:end
|
||||
|
||||
:WOL_run_LXC_help:
|
||||
If set to yes when wake on lan packets are received checks are carrried out for LXC otherwise LXC will be ignored. The LXC plugin needs to be installed for LXC to be processed.
|
||||
:end
|
||||
|
||||
:WOL_run_shutdown_help:
|
||||
If set to yes when wake on lan packets are received checks are carrried out and if enabled for service and that service is running the entity will be shutdown. System has to be set to Enabled and Shutdwon for it to be action.
|
||||
:end
|
||||
|
||||
:WOL_interface_help:
|
||||
Specify the interface to the daemon to bind to. Some interfaces may not be able to recieve etherframe packets. Recommend to bind to a physical interface.
|
||||
:end
|
||||
|
||||
:WOL_promiscuous_mode_help:
|
||||
Enable to set the NIC not to filer packets.
|
||||
:end
|
||||
|
||||
:WOL_log_file_help:
|
||||
Default is to log to syslog but if you want a different log location set the file name.
|
||||
:end
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
// add translations
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
@@ -27,6 +28,9 @@ if ($_SERVER['REQUEST_URI'] == '/logout') {
|
||||
$error = _('Successfully logged out');
|
||||
}
|
||||
|
||||
// If issue with license key redirect to Tools/Registration, otherwise go to start page
|
||||
$start_page = (!empty(_var($var,'regCheck'))) ? 'Tools/Registration' : _var($var,'START_PAGE','Main');
|
||||
|
||||
$result = exec( "/usr/bin/passwd --status root");
|
||||
if (($result === false) || (substr($result, 0, 6) !== "root P"))
|
||||
include "$docroot/webGui/include/.set-password.php";
|
||||
|
@@ -3,8 +3,8 @@ Title="UPS Details"
|
||||
Tag="battery-3"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2022, Lime Technology
|
||||
* Copyright 2012-2022, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2015, Dan Landon.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -14,10 +14,15 @@ Tag="battery-3"
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
?>
|
||||
<script>
|
||||
function getUPSstatus() {
|
||||
$.post('/plugins/dynamix.apcupsd/include/UPSstatus.php',{level:<?=$cfg['BATTERYLEVEL']?>,runtime:<?=$cfg['MINUTES']?>},function(data) {
|
||||
var batteryLevel = "<?= _var($cfg,'BATTERYLEVEL',0) ?>";
|
||||
var batteryRuntime = "<?= _var($cfg,'MINUTES',0) ?>";
|
||||
|
||||
$.post('/plugins/dynamix.apcupsd/include/UPSstatus.php',{level:batteryLevel,runtime:batteryRuntime},function(data) {
|
||||
data = data.split('\n');
|
||||
$('#ups_summary').html(data[0]);
|
||||
$('#ups_status').html(data[1]);
|
||||
|
@@ -5,8 +5,8 @@ Icon="icon-ups"
|
||||
Tag="battery-3"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2022, Lime Technology
|
||||
* Copyright 2012-2022, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2015, Dan Landon.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -22,13 +22,6 @@ Tag="battery-3"
|
||||
$sName = "dynamix.apcupsd";
|
||||
$cfg = parse_plugin_cfg($sName);
|
||||
?>
|
||||
|
||||
<style>
|
||||
table.ups thead tr th{width:16.6%;padding-left:10px}
|
||||
table.ups tbody tr td{padding-left:10px;font-weight:bold}
|
||||
tr.ups{height:3rem;line-height:3rem}
|
||||
i.ups{margin-right:8px}
|
||||
</style>
|
||||
<script>
|
||||
function toggleCustomCable(form) {
|
||||
var readonly = form.UPSCABLE.value != 'custom';
|
||||
@@ -98,6 +91,11 @@ _(Device)_:
|
||||
|
||||
:apc_ups_device_help:
|
||||
|
||||
_(Override UPS Capacity (Watts))_:
|
||||
: <input type="number" name="OVERRIDE_UPS_CAPACITY" maxlength="5" class="narrow" value="<?=htmlspecialchars($cfg['OVERRIDE_UPS_CAPACITY']);?>">
|
||||
|
||||
:apc_ups_override_ups_capacity_help:
|
||||
|
||||
_(Battery level to initiate shutdown)_ (%):
|
||||
: <input type="text" name="BATTERYLEVEL" class="narrow" maxlength="3" value="<?=htmlspecialchars($cfg['BATTERYLEVEL']);?>">
|
||||
|
||||
|
@@ -3,6 +3,7 @@ UPSCABLE="usb"
|
||||
CUSTOMUPSCABLE=""
|
||||
UPSTYPE="usb"
|
||||
DEVICE=""
|
||||
OVERRIDE_UPS_CAPACITY=""
|
||||
BATTERYLEVEL="10"
|
||||
MINUTES="10"
|
||||
TIMEOUT="0"
|
||||
|
@@ -12,11 +12,16 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
|
||||
// add translations
|
||||
$_SERVER['REQUEST_URI'] = 'settings';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
$cfg = parse_plugin_cfg('dynamix.apcupsd');
|
||||
$overrideUpsCapacity = (int) htmlspecialchars($cfg['OVERRIDE_UPS_CAPACITY'] ?: 0);
|
||||
|
||||
$state = [
|
||||
'ONLINE' => _('Online'),
|
||||
'SLAVE' => '('._('slave').')',
|
||||
@@ -33,7 +38,8 @@ $state = [
|
||||
$red = "class='red-text'";
|
||||
$green = "class='green-text'";
|
||||
$orange = "class='orange-text'";
|
||||
$status = array_fill(0,7,"<td>-</td>");
|
||||
$defaultCell = "<td>-</td>";
|
||||
$status = array_fill(0,7,$defaultCell);
|
||||
$result = [];
|
||||
$level = $_POST['level'] ?: 10;
|
||||
$runtime = $_POST['runtime'] ?: 5;
|
||||
@@ -85,9 +91,17 @@ if (file_exists("/var/run/apcupsd.pid")) {
|
||||
if ($i%2==1) $result[] = "</tr>";
|
||||
}
|
||||
if (count($rows)%2==1) $result[] = "<td></td><td></td></tr>";
|
||||
|
||||
// If the override is defined, override the power value, using the same implementation as above.
|
||||
// This is a better implementation, as it allows the existing Unraid code to work with the override.
|
||||
if ($overrideUpsCapacity > 0) {
|
||||
$power = $overrideUpsCapacity;
|
||||
$status[4] = $power>0 ? "<td $green>$power W</td>" : "<td $red>$power W</td>";
|
||||
}
|
||||
|
||||
if ($power && isset($load)) $status[5] = ($load<90 ? "<td $green>" : "<td $red>").round($power*$load/100)." W (".$status[5].")</td>";
|
||||
elseif (isset($load)) $status[5] = ($load<90 ? "<td $green>" : "<td $red>").$status[5]."</td>";
|
||||
$status[6] = isset($output) ? ((!$volt || ($minv<$output && $output<$maxv) ? "<td $green>" : "<td $red>").$status[6].($freq ? " ~ $freq Hz" : "")."</td>") : $status[6];
|
||||
$status[6] = isset($output) ? ((!$volt || ($minv<$output && $output<$maxv) ? "<td $green>" : "<td $red>").$status[6].(isset($freq) ? " ~ $freq Hz" : "")."</td>") : $status[6];
|
||||
}
|
||||
if (empty($rows)) $result[] = "<tr><td colspan='4' style='text-align:center'>"._('No information available')."</td></tr>";
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2018, Lime Technology
|
||||
* Copyright 2012-2020, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2015, Dan Landon.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
4
emhttp/plugins/dynamix.apcupsd/sheets/UPSsettings.css
Normal file
4
emhttp/plugins/dynamix.apcupsd/sheets/UPSsettings.css
Normal file
@@ -0,0 +1,4 @@
|
||||
table.ups thead tr th{width:16.6%;padding-left:10px}
|
||||
table.ups tbody tr td{padding-left:10px;font-weight:bold}
|
||||
tr.ups{height:3rem;line-height:3rem}
|
||||
i.ups{margin-right:8px}
|
@@ -3,9 +3,9 @@ Cond="(pgrep('dockerd')!==false)"
|
||||
Markdown="false"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2020, Lime Technology
|
||||
* Copyright 2014-2020, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2020, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
|
@@ -5,7 +5,8 @@ Lock="true"
|
||||
Cond="exec(\"grep -o '^DOCKER_ENABLED=.yes' /boot/config/docker.cfg 2>/dev/null\")"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2021, Lime Technology
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@@ -7,8 +7,8 @@ Nchan="docker_load:stop"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2014-2023, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -29,23 +29,10 @@ $cpus = cpu_list();
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.ui.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-$theme.css")?>">
|
||||
<style>
|
||||
.basic{display:block}
|
||||
.advanced{display:none;white-space:nowrap}
|
||||
.log{cursor:zoom-in}
|
||||
.exec{cursor:pointer}
|
||||
table#docker_containers{text-align:left}
|
||||
th.five{width:5%}
|
||||
th.nine{width:9%}
|
||||
th.load{width:140px}
|
||||
input.wait{width:24px;margin:0 4px;padding:0 5px;border:none;box-shadow:none;background-color:transparent}
|
||||
table tbody td{line-height:normal}
|
||||
i.mover{margin-right:8px;display:none}
|
||||
#resetsort{margin-left:12px;display:inline-block;width:32px}
|
||||
</style>
|
||||
|
||||
<table id="docker_containers" class="tablesorter shift">
|
||||
<thead><tr><th><a id="resetsort" class="nohand" onclick="resetSorting()" title="_(Reset sorting)_"><i class="fa fa-th-list"></i></a>_(Application)_</th><th>_(Version)_</th><th>_(Network)_</th><th>_(Port Mappings)_ <small>(_(App to Host)_)</small></th><th>_(Volume Mappings)_ <small>(_(App to Host)_)</small></th><th class="load advanced">_(CPU & Memory load)_</th><th class="nine">_(Autostart)_</th><th class="five">_(Uptime)_</th></tr></thead>
|
||||
<tbody id="docker_list"><tr><td colspan='8'></td></tr></tbody>
|
||||
<thead><tr><th><a id="resetsort" class="nohand" onclick="resetSorting()" title="_(Reset sorting)_"><i class="fa fa-th-list"></i></a>_(Application)_</th><th>_(Version)_</th><th>_(Network)_</th><th>_(Container IP)_</th><th>_(Container Port)_</th><th>_(LAN IP:Port)_</th><th>_(Volume Mappings)_ <small>(_(App to Host)_)</small></th><th class="load advanced">_(CPU & Memory load)_</th><th class="nine">_(Autostart)_</th><th class="five">_(Uptime)_</th></tr></thead>
|
||||
<tbody id="docker_list"><tr><td colspan='9'></td></tr></tbody>
|
||||
</table>
|
||||
<input type="button" onclick="addContainer()" value="_(Add Container)_" style="display:none">
|
||||
<input type="button" onclick="startAll()" value="_(Start All)_" style="display:none">
|
||||
@@ -124,6 +111,7 @@ function LockButton() {
|
||||
}
|
||||
function loadlist(init) {
|
||||
timers.docker = setTimeout(function(){$('div.spinner.fixed').show('slow');},500);
|
||||
docker = [];
|
||||
$.get('/plugins/dynamix.docker.manager/include/DockerContainers.php',function(d) {
|
||||
clearTimeout(timers.docker);
|
||||
var data = d.split(/\0/);
|
||||
@@ -190,4 +178,9 @@ $(function() {
|
||||
loadlist(true);
|
||||
dockerload.start();
|
||||
});
|
||||
|
||||
window.onunload = function(){
|
||||
dockerload.stop();
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@@ -5,8 +5,8 @@ Tag="icon-docker"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2014-2023, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -103,34 +103,12 @@ function base_net($route) {
|
||||
return substr(explode('/',$route)[0],0,-2);
|
||||
}
|
||||
$bgcolor = strstr('white,azure',$display['theme']) ? '#f2f2f2' : '#1c1c1c';
|
||||
|
||||
//Check if docker.cfg not exists
|
||||
$no_dockercfg = !is_file('/boot/config/docker.cfg');
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.filetree.css')?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
|
||||
<style>
|
||||
.errortext{color:#EF3D47;display:none;margin-left:20px}
|
||||
.fileTree{background:<?=$bgcolor?>;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
.basic{display:inline-block}
|
||||
.advanced{display:none}
|
||||
select.mask{min-width:0;margin:0 10px 0 4px}
|
||||
select.net{min-width:0;margin:0 4px 0 2px}
|
||||
select option.hide{display:none}
|
||||
input.ip4{width:100px;margin:0 4px 0 1px}
|
||||
input.ip6{width:140px;margin:0 4px}
|
||||
input.gw4{width:100px;margin:0 4px 0 1px}
|
||||
input.gw6{width:160px;margin:0 4px}
|
||||
input.pool6{width:40px;margin:0 4px 0 1px}
|
||||
span.net{margin-left:4px;margin-right:2px}
|
||||
span.ip4{display:inline-block;width:260px}
|
||||
span.ip6{display:inline-block;width:310px}
|
||||
span.gw4{display:inline-block;width:200px}
|
||||
span.gw6{display:inline-block;width:270px}
|
||||
span.nonexist{margin-left:20px}
|
||||
<?if (strstr('white,azure',$display['theme'])):?>
|
||||
span.disabled{color:#B0B0B0}
|
||||
<?else:?>
|
||||
span.disabled{color:#404040}
|
||||
<?endif;?>
|
||||
</style>
|
||||
<span class="status vhshift"><input type="checkbox" class="advancedview"></span>
|
||||
|
||||
<form markdown="1" id="settingsForm" name="settingsForm" method="POST" action="/update.php" target="progressFrame" onsubmit="return prepareDocker(this)">
|
||||
@@ -141,6 +119,7 @@ span.disabled{color:#404040}
|
||||
<input type="hidden" name="#cleanup" value="true">
|
||||
<input type="hidden" name="DOCKER_CUSTOM_NETWORKS" value="<?=implode(' ',$unset)?> ">
|
||||
<input type="hidden" name="DOCKER_IMAGE_FILE" value="<?=_var($dockercfg,'DOCKER_IMAGE_FILE')?>">
|
||||
|
||||
_(Enable Docker)_:
|
||||
: <select id="DOCKER_ENABLED" name="DOCKER_ENABLED">
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_ENABLED'), 'no', _('No'))?>
|
||||
@@ -164,11 +143,16 @@ _(Enable container table readmore-js)_:
|
||||
|
||||
:docker_readmore_help:
|
||||
|
||||
_(Docker Stop Timeout)_:
|
||||
: <input class='narrow' id="DOCKER_TIMEOUT" type="number" name="DOCKER_TIMEOUT" min='1' value="<?=_var($dockercfg,'DOCKER_TIMEOUT')?>">_(seconds)_
|
||||
_(Docker Stop Timeout)_ (_(seconds)_):
|
||||
: <input class='narrow' id="DOCKER_TIMEOUT" type="number" name="DOCKER_TIMEOUT" min='1' value="<?=_var($dockercfg,'DOCKER_TIMEOUT')?>">
|
||||
|
||||
:docker_timeout_help:
|
||||
|
||||
_(Docker PID Limit)_:
|
||||
: <input class='narrow' id="DOCKER_PID_LIMIT" type="number" name="DOCKER_PID_LIMIT" min='1' value="<?=_var($dockercfg,'DOCKER_PID_LIMIT')?>" placeholder="2048">
|
||||
|
||||
:docker_pid_limit_help:
|
||||
|
||||
<?if ($DockerStopped):?>
|
||||
|
||||
_(Docker data-root)_:
|
||||
@@ -207,8 +191,25 @@ _(Docker directory)_:
|
||||
:docker_vdisk_directory_help:
|
||||
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="backingfs_type" style="display:none">
|
||||
_(Docker storage driver)_:
|
||||
: <select id="DOCKER_BACKINGFS" name="DOCKER_BACKINGFS" onchange="updateBackingFS(this.value)">
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_BACKINGFS'), 'overlay2', _('overlay2'))?>
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_BACKINGFS'), 'native', _('native'))?>
|
||||
</select>
|
||||
<?if ($var['fsState'] != "Started"):?>
|
||||
<span id="WARNING_BACKINGFS" style="display:none;"><i class="fa fa-warning icon warning"></i>_(Only modify if this is a new installation since this can lead to unwanted behaviour!)_</span>
|
||||
<?elseif (is_dir(_var($dockercfg,'DOCKER_IMAGE_FILE'))):?>
|
||||
<span id="WARNING_BACKINGFS" style="display:none;"><i class="fa fa-warning icon warning"></i>_(Switching the Storage Driver requires to delete and rebuild the Docker directory manually!)_</span>
|
||||
<?endif;?>
|
||||
|
||||
:docker_storage_driver_help:
|
||||
|
||||
</div>
|
||||
|
||||
_(Default appdata storage location)_:
|
||||
: <input type="text" id="DOCKER_APP_CONFIG_PATH" name="DOCKER_APP_CONFIG_PATH" autocomplete="off" spellcheck="false" value="<?=_var($dockercfg,'DOCKER_APP_CONFIG_PATH')?>" placeholder="_(e.g.)_ /mnt/user/appdata/" data-pickfilter="HIDE_FILES_FILTER" data-pickroot="<?=is_dir('/mnt/user')?'/mnt/user':'/mnt'?>" data-pickfolders="true" pattern="^[^\\]*/$">
|
||||
: <input type="text" id="DOCKER_APP_CONFIG_PATH" name="DOCKER_APP_CONFIG_PATH" autocomplete="off" spellcheck="false" value="<?=_var($dockercfg,'DOCKER_APP_CONFIG_PATH')?>" placeholder="_(e.g.)_ /mnt/user/appdata/" data-pickfilter="HIDE_FILES_FILTER" data-pickroot="/mnt" data-pickfolders="true" pattern="^[^\\]*/$">
|
||||
<?if ($var['fsState'] != "Started"):?>
|
||||
<span><i class="fa fa-warning icon warning"></i> _(Modify with caution: unable to validate path until Array is Started)_</span>
|
||||
<?elseif (!is_dir(_var($dockercfg,'DOCKER_APP_CONFIG_PATH'))):?>
|
||||
@@ -257,16 +258,14 @@ _(Template Authoring Mode)_:
|
||||
|
||||
:docker_authoring_mode_help:
|
||||
|
||||
<?if ($bridge):?>
|
||||
_(Docker custom network type)_:
|
||||
: <select name="DOCKER_NETWORK_TYPE">
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_NETWORK_TYPE'), '1', _('ipvlan'))?>
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_NETWORK_TYPE'), '', _('macvlan'))?>
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_NETWORK_TYPE'), '1', _('ipvlan'), $bridge?'':'disabled')?>
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_NETWORK_TYPE'), '', _('macvlan'), $bridge?'':'selected')?>
|
||||
</select> _(Please read the Help carefully)_. _(Misconfiguration can cause problems)_.
|
||||
|
||||
:docker_custom_network_type_help:
|
||||
|
||||
<?endif;?>
|
||||
_(Host access to custom networks)_:
|
||||
: <select name="DOCKER_ALLOW_ACCESS">
|
||||
<?=mk_option(_var($dockercfg,'DOCKER_ALLOW_ACCESS'), '', _('Disabled'))?>
|
||||
@@ -439,6 +438,7 @@ _(IPv6 custom network on interface)_ <?=$network?> (_(optional)_):
|
||||
</div>
|
||||
<?else: /* DOCKER STARTED */?>
|
||||
|
||||
|
||||
_(Docker version)_:
|
||||
: <?$arrInfo = $DockerClient->getInfo(); echo $arrInfo['Version']?>
|
||||
|
||||
@@ -454,6 +454,11 @@ _(Docker directory)_:
|
||||
|
||||
:docker_vdisk_location_active_help:
|
||||
|
||||
_(Docker storage driver)_:
|
||||
: <?=_var($dockercfg,'DOCKER_BACKINGFS')?>
|
||||
|
||||
:docker_storage_driver_active_help:
|
||||
|
||||
_(Default appdata storage location)_:
|
||||
: <?=_var($dockercfg,'DOCKER_APP_CONFIG_PATH')?>
|
||||
|
||||
@@ -465,13 +470,11 @@ _(Docker LOG rotation)_:
|
||||
|
||||
:docker_log_rotation_active_help:
|
||||
|
||||
<?if ($bridge):?>
|
||||
_(Docker custom network type)_:
|
||||
: <?=_var($dockercfg,'DOCKER_NETWORK_TYPE')=='1' ? _('ipvlan') : _('macvlan')?>
|
||||
: <?=_var($dockercfg,'DOCKER_NETWORK_TYPE')!='1' || !$bridge ? _('macvlan') : _('ipvlan')?>
|
||||
|
||||
:docker_custom_network_type_help:
|
||||
|
||||
<?endif;?>
|
||||
_(Host access to custom networks)_:
|
||||
: <?=_var($dockercfg,'DOCKER_ALLOW_ACCESS')=='yes' ? _('Enabled') : _('Disabled')?>
|
||||
|
||||
@@ -615,6 +618,9 @@ function prepareDocker(form) {
|
||||
$(form).find('input[name="DOCKER_IMAGE_FILE"]').val($('#DOCKER_IMAGE_TYPE').val()=='folder' ? $("#DOCKER_IMAGE_FILE2").val() : $("#DOCKER_IMAGE_FILE1").val());
|
||||
$("#DOCKER_IMAGE_FILE1").prop('disabled',true);
|
||||
$("#DOCKER_IMAGE_FILE2").prop('disabled',true);
|
||||
<?if ($no_dockercfg):?>
|
||||
$(form).find('input[name="DOCKER_BACKINGFS"]').val($('#DOCKER_IMAGE_TYPE').val()=='folder' ? $("#DOCKER_BACKINGFS").val() : $("#DOCKER_BACKINGFS").val('native'));
|
||||
<?endif;?>
|
||||
<?endif;?>
|
||||
$(form).find('input:hidden[name^="DOCKER_DHCP_"]').each(function(){
|
||||
var id = '#'+$(this).attr('name')+'_';
|
||||
@@ -880,39 +886,54 @@ function btrfsScrub(path) {
|
||||
}
|
||||
});
|
||||
}
|
||||
var originalPath = $("#DOCKER_IMAGE_FILE2").val();
|
||||
function updateLocation(val) {
|
||||
var content1 = $("#DOCKER_IMAGE_FILE1");
|
||||
var content2 = $("#DOCKER_IMAGE_FILE2");
|
||||
var dropdown = $("#DOCKER_BACKINGFS");
|
||||
var path = originalPath.split('/');
|
||||
switch (val) {
|
||||
case 'xfs':
|
||||
var path = content2.val().split('/');
|
||||
path.splice(-1,1);
|
||||
content1.val((path.join('/') + '/docker-xfs.img'));
|
||||
$('#vdisk_file').show('slow');
|
||||
$('#vdisk_dir').hide('slow');
|
||||
$('#backingfs_type').hide();
|
||||
content1.prop('disabled',false).trigger('change');
|
||||
content2.prop('disabled',true);
|
||||
dropdown.val('native');
|
||||
break;
|
||||
case 'folder':
|
||||
var path = content2.val().split('/');
|
||||
if (path[path.length-1]=='') path.splice(-2,2); else path.splice(-1,1);
|
||||
content2.val(path.join('/') + '/docker/');
|
||||
content2.val(path.join('/') + '/');
|
||||
$('#vdisk_file').hide('slow');
|
||||
$('#vdisk_dir').show('slow');
|
||||
$('#backingfs_type').show('slow');
|
||||
content1.prop('disabled',true);
|
||||
content2.prop('disabled',false).trigger('change');
|
||||
break;
|
||||
default:
|
||||
var path = content2.val().split('/');
|
||||
path.splice(-1,1);
|
||||
content1.val((path.join('/') + '/docker.img'));
|
||||
$('#vdisk_file').show('slow');
|
||||
$('#vdisk_dir').hide('slow');
|
||||
$('#backingfs_type').hide();
|
||||
content1.prop('disabled',false).trigger('change');
|
||||
content2.prop('disabled',true);
|
||||
dropdown.val('native');
|
||||
break;
|
||||
}
|
||||
}
|
||||
function updateBackingFS(val) {
|
||||
var backingfs = "<?= _var($dockercfg,'DOCKER_BACKINGFS') ?>";
|
||||
var warning = document.getElementById("WARNING_BACKINGFS");
|
||||
var checkbox = $(".deleteCheckbox");
|
||||
if (val !== backingfs) {
|
||||
warning.style.display = "inline";
|
||||
} else {
|
||||
warning.style.display = "none";
|
||||
}
|
||||
}
|
||||
function checkbox_state(value) {
|
||||
$.post('/plugins/dynamix.docker.manager/include/UpdateConfig.php',{action:'exist',name:value},function(state){state==0 ? $('.deleteLabel').fadeIn() : $('.deleteLabel').fadeOut();});
|
||||
}
|
||||
@@ -920,6 +941,7 @@ $(function() {
|
||||
<?if ($DockerStopped):?>
|
||||
if ($('#DOCKER_IMAGE_TYPE').val()=='folder') {
|
||||
$('#vdisk_dir').show();
|
||||
$('#backingfs_type').show();
|
||||
checkbox_state($("#DOCKER_IMAGE_FILE2").val());
|
||||
$("#DOCKER_IMAGE_FILE2").prop('disabled',false);
|
||||
} else {
|
||||
|
@@ -3,9 +3,9 @@ Cond="(pgrep('dockerd')!==false)"
|
||||
Markdown="false"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2020, Lime Technology
|
||||
* Copyright 2014-2020, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2020, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
|
@@ -8,3 +8,5 @@ DOCKER_USER_NETWORKS="remove"
|
||||
DOCKER_ALLOW_ACCESS=""
|
||||
DOCKER_TIMEOUT=10
|
||||
DOCKER_READMORE="yes"
|
||||
DOCKER_PID_LIMIT=""
|
||||
DOCKER_BACKINGFS="overlay2"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2022, Lime Technology
|
||||
* Copyright 2014-2022, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2022, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
|
||||
$user_prefs = $dockerManPaths['user-prefs'];
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2015-2023, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -12,10 +12,8 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
libxml_use_internal_errors(true);
|
||||
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
|
||||
@@ -215,6 +213,9 @@ if (isset($_GET['xmlTemplate'])) {
|
||||
if (is_file($xmlTemplate)) {
|
||||
$xml = xmlToVar($xmlTemplate);
|
||||
$templateName = $xml['Name'];
|
||||
if (preg_match('/^container:(.*)/', $xml['Network'])) {
|
||||
$xml['Network'] = explode(':', $xml['Network'], 2);
|
||||
}
|
||||
if ($xmlType == 'default') {
|
||||
if (!empty($dockercfg['DOCKER_APP_CONFIG_PATH']) && file_exists($dockercfg['DOCKER_APP_CONFIG_PATH'])) {
|
||||
// override /config
|
||||
@@ -277,18 +278,6 @@ $bgcolor = strstr('white,azure',$display['theme']) ? '#f2f2f2' : '#1c1c1c';
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.filetree.css")?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-{$display['theme']}.css")?>">
|
||||
|
||||
<style>
|
||||
.noshow,.advanced{display:none}
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:<?=$bgcolor?>}
|
||||
.required:after{content:" *";color:#E80000}
|
||||
span.boxed{display:inline-block;line-height:normal;white-space:normal;width:56%}
|
||||
span.cpu,label.checkbox{display:inline-block;width:32px}
|
||||
span.ct{display:inline-block;width:230px}
|
||||
span.net{display:inline-block;width:120px}
|
||||
span.ip{display:inline-block;width:160px}
|
||||
dl,dt,dd{line-height:normal!important}
|
||||
</style>
|
||||
|
||||
<script src="<?autov('/webGui/javascript/jquery.switchbutton.js')?>"></script>
|
||||
<script src="<?autov('/webGui/javascript/jquery.filetree.js')?>" charset="utf-8"></script>
|
||||
<script src="<?autov('/plugins/dynamix.vm.manager/javascript/dynamix.vm.manager.js')?>"></script>
|
||||
@@ -319,6 +308,7 @@ if (!String.prototype.replaceAll) {
|
||||
// Create config nodes using templateDisplayConfig
|
||||
function makeConfig(opts) {
|
||||
confNum += 1;
|
||||
var icons = {'Path':'folder-o', 'Port':'minus-square-o', 'Variable':'file-text-o', 'Label':'tags', 'Device':'play-circle-o'};
|
||||
var newConfig = $("#templateDisplayConfig").html();
|
||||
newConfig = newConfig.format(
|
||||
stripTags(opts.Name),
|
||||
@@ -333,7 +323,8 @@ function makeConfig(opts) {
|
||||
escapeQuote(opts.Value),
|
||||
opts.Buttons,
|
||||
opts.Required=='true' ? 'required' : '',
|
||||
sprintf('Container %s',opts.Type)
|
||||
sprintf('Container %s',opts.Type),
|
||||
icons[opts.Type] || 'question'
|
||||
);
|
||||
newConfig = "<div id='ConfigNum"+opts.Number+"' class='config_"+opts.Display+"'' >"+newConfig+"</div>";
|
||||
newConfig = $($.parseHTML(newConfig));
|
||||
@@ -386,6 +377,13 @@ function getVal(el, name) {
|
||||
}
|
||||
}
|
||||
|
||||
function dialogStyle() {
|
||||
$('.ui-dialog-titlebar-close').css({'display':'none'});
|
||||
$('.ui-dialog-title').css({'text-align':'center','width':'100%','font-size':'1.8rem'});
|
||||
$('.ui-dialog-content').css({'padding-top':'15px','vertical-align':'bottom'});
|
||||
$('.ui-button-text').css({'padding':'0px 5px'});
|
||||
}
|
||||
|
||||
function addConfigPopup() {
|
||||
var title = "_(Add Configuration)_";
|
||||
var popup = $("#dialogAddConfig");
|
||||
@@ -403,11 +401,10 @@ function addConfigPopup() {
|
||||
// Start Dialog section
|
||||
popup.dialog({
|
||||
title: title,
|
||||
height: 'auto',
|
||||
width: 900,
|
||||
resizable: false,
|
||||
width: 800,
|
||||
modal: true,
|
||||
show : {effect: 'fade' , duration: 250},
|
||||
hide : {effect: 'fade' , duration: 250},
|
||||
buttons: {
|
||||
"_(Add)_": function() {
|
||||
$(this).dialog("close");
|
||||
@@ -429,6 +426,9 @@ function addConfigPopup() {
|
||||
Opts.Buttons += "<button type='button' onclick='removeConfig("+confNum+")'>_(Remove)_</button>";
|
||||
}
|
||||
Opts.Number = confNum;
|
||||
if (Opts.Type == "Device") {
|
||||
Opts.Target = Opts.Value;
|
||||
}
|
||||
newConf = makeConfig(Opts);
|
||||
$("#configLocation").append(newConf);
|
||||
reloadTriggers();
|
||||
@@ -439,11 +439,7 @@ function addConfigPopup() {
|
||||
}
|
||||
}
|
||||
});
|
||||
$(".ui-dialog .ui-dialog-titlebar").addClass('menu');
|
||||
$('.ui-dialog .ui-dialog-titlebar-close').css({'display':'none'});
|
||||
$(".ui-dialog .ui-dialog-title").css({'text-align':'center','width':'100%'});
|
||||
$(".ui-dialog .ui-dialog-content").css({'padding-top':'15px','vertical-align':'bottom'});
|
||||
$(".ui-button-text").css({'padding':'0px 5px'});
|
||||
dialogStyle();
|
||||
}
|
||||
|
||||
function editConfigPopup(num,disabled) {
|
||||
@@ -477,11 +473,10 @@ function editConfigPopup(num,disabled) {
|
||||
popup.find(".switch-button-background").css("margin-top", "6px");
|
||||
popup.dialog({
|
||||
title: title,
|
||||
height: 'auto',
|
||||
width: 900,
|
||||
resizable: false,
|
||||
width: 800,
|
||||
modal: true,
|
||||
show: {effect:'fade', duration: 250},
|
||||
hide: {effect:'fade', duration: 250},
|
||||
buttons: {
|
||||
"_(Save)_": function() {
|
||||
$(this).dialog("close");
|
||||
@@ -502,6 +497,9 @@ function editConfigPopup(num,disabled) {
|
||||
}
|
||||
|
||||
Opts.Number = num;
|
||||
if (Opts.Type == "Device") {
|
||||
Opts.Target = Opts.Value;
|
||||
}
|
||||
newConf = makeConfig(Opts);
|
||||
if (config.hasClass("config_"+Opts.Display)) {
|
||||
config.html(newConf);
|
||||
@@ -522,11 +520,7 @@ function editConfigPopup(num,disabled) {
|
||||
}
|
||||
}
|
||||
});
|
||||
$(".ui-dialog .ui-dialog-titlebar").addClass('menu');
|
||||
$('.ui-dialog .ui-dialog-titlebar-close').css({'display':'none'});
|
||||
$(".ui-dialog .ui-dialog-title").css({'text-align':'center','width':'100%'});
|
||||
$(".ui-dialog .ui-dialog-content").css({'padding-top':'15px','vertical-align':'bottom'});
|
||||
$(".ui-button-text").css({'padding':'0px 5px'});
|
||||
dialogStyle();
|
||||
$('.desc_readmore').readmore({maxHeight:10});
|
||||
}
|
||||
|
||||
@@ -763,6 +757,7 @@ _(Categories)_:
|
||||
: <input type="hidden" name="contCategory">
|
||||
<select id="catSelect" size="1" multiple="multiple" style="display:none" onchange="prepareCategory();">
|
||||
<optgroup label="_(Categories)_">
|
||||
<option value="AI:">_(AI)_</option>
|
||||
<option value="Backup:">_(Backup)_</option>
|
||||
<option value="Cloud:">_(Cloud)_</option>
|
||||
<option value="Crypto:">_(Crypto Currency)_</option>
|
||||
@@ -872,6 +867,7 @@ _(Network Type)_:
|
||||
: <select name="contNetwork" onchange="showSubnet(this.value)">
|
||||
<?=mk_option(1,'bridge',_('Bridge'))?>
|
||||
<?=mk_option(1,'host',_('Host'))?>
|
||||
<?=mk_option(1,'container',_('Container'))?>
|
||||
<?=mk_option(1,'none',_('None'))?>
|
||||
<?foreach ($custom as $network):?>
|
||||
<?$name = $network;
|
||||
@@ -894,6 +890,21 @@ _(Fixed IP address)_ (_(optional)_):
|
||||
|
||||
:docker_fixed_ip_help:
|
||||
|
||||
</div>
|
||||
|
||||
<div markdown="1" class="netCONT noshow">
|
||||
_(Container Network)_:
|
||||
: <select name="netCONT" id="netCONT">
|
||||
<?php
|
||||
foreach ($DockerClient->getDockerContainers() as $ct) {
|
||||
if ($ct['Name'] !== $xml['Name']) {
|
||||
$list[] = $ct['Name'];
|
||||
echo mk_option($ct['Name'], $ct['Name'], $ct['Name']);
|
||||
}
|
||||
}
|
||||
?>
|
||||
:docker_container_network_help:
|
||||
</select>
|
||||
</div>
|
||||
_(Console shell command)_:
|
||||
: <select name="contShell">
|
||||
@@ -1008,8 +1019,8 @@ _(Password Mask)_:
|
||||
<input type="hidden" name="confDisplay[]" value="{6}">
|
||||
<input type="hidden" name="confRequired[]" value="{7}">
|
||||
<input type="hidden" name="confMask[]" value="{8}">
|
||||
<span class="{11}">{0}:</span>
|
||||
: <span class="boxed"><input type="text" name="confValue[]" default="{2}" value="{9}" autocomplete="off" spellcheck="false" {11}>{10}<br><span class='orange-text'>{12}: {1}</span><br><span class="orange-text">{4}</span><br>
|
||||
<span class="{11}"><i class="fa fa-fw fa-{13}"></i> {0}:</span>
|
||||
: <span class="boxed"><input type="text" class="setting_input" name="confValue[]" default="{2}" value="{9}" autocomplete="off" spellcheck="false" {11}>{10}<br><span class='orange-text'>{12}: {1}</span><br><span class="orange-text">{4}</span><br></span>
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="templateAllocations" style="display:none">
|
||||
@@ -1027,9 +1038,18 @@ function showSubnet(bridge) {
|
||||
if (bridge.match(/^(bridge|host|none)$/i) !== null) {
|
||||
$('.myIP').hide();
|
||||
$('input[name="contMyIP"]').val('');
|
||||
$('.netCONT').hide();
|
||||
$('#netCONT').val('');
|
||||
} else if (bridge.match(/^(container)$/i) !== null) {
|
||||
$('.netCONT').show();
|
||||
$('#netCONT').val('<?php echo $xml['Network'][1]; ?>');
|
||||
$('.myIP').hide();
|
||||
$('input[name="contMyIP"]').val('');
|
||||
} else {
|
||||
$('.myIP').show();
|
||||
$('#myIP').html('Subnet: '+subnet[bridge]);
|
||||
$('.netCONT').hide();
|
||||
$('#netCONT').val('');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1125,6 +1145,9 @@ $(function() {
|
||||
Opts.Buttons += "<button type='button' onclick='removeConfig("+confNum+")'>_(Remove)_</button>";
|
||||
}
|
||||
Opts.Number = confNum;
|
||||
if (Opts.Type == "Device") {
|
||||
Opts.Target = Opts.Value;
|
||||
}
|
||||
newConf = makeConfig(Opts);
|
||||
if (Opts.Display == 'advanced' || Opts.Display == 'advanced-hide') {
|
||||
$("#configLocationAdvanced").append(newConf);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2014-2023, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -12,10 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
libxml_use_internal_errors(true); # Suppress any warnings from xml errors.
|
||||
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/Helpers.php";
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
@@ -51,13 +48,16 @@ $port = file_exists('/sys/class/net/br0') ? 'BR0' : (file_exists('/sys/class/net
|
||||
|
||||
// Docker configuration file - guaranteed to exist
|
||||
$docker_cfgfile = '/boot/config/docker.cfg';
|
||||
if (file_exists($docker_cfgfile) && exec("grep -Pom1 '_{$port}(_[0-9]+)?=' $docker_cfgfile")=='') {
|
||||
# interface has changed, update configuration
|
||||
exec("sed -ri 's/_(BR0|BOND0|ETH0)(_[0-9]+)?=/_{$port}\\2=/' $docker_cfgfile");
|
||||
if (file_exists($docker_cfgfile)) {
|
||||
exec("grep -Pom2 '_SUBNET_|_{$port}(_[0-9]+)?=' $docker_cfgfile",$cfg);
|
||||
if (isset($cfg[0]) && $cfg[0]=='_SUBNET_' && empty($cfg[1])) {
|
||||
# interface has changed, update configuration
|
||||
exec("sed -ri 's/_(BR0|BOND0|ETH0)(_[0-9]+)?=/_{$port}\\2=/' $docker_cfgfile");
|
||||
}
|
||||
}
|
||||
|
||||
$defaults = @parse_ini_file("$docroot/plugins/dynamix.docker.manager/default.cfg") ?: [];
|
||||
$dockercfg = array_replace_recursive($defaults, @parse_ini_file($docker_cfgfile) ?: []);
|
||||
$defaults = (array)@parse_ini_file("$docroot/plugins/dynamix.docker.manager/default.cfg");
|
||||
$dockercfg = array_replace_recursive($defaults, (array)@parse_ini_file($docker_cfgfile));
|
||||
|
||||
function var_split($item, $i=0) {
|
||||
return array_pad(explode(' ',$item),$i+1,'')[$i];
|
||||
@@ -176,7 +176,7 @@ class DockerTemplates {
|
||||
}
|
||||
// if after above we don't have a valid url, check for GitLab
|
||||
if (empty($github_api['url'])) {
|
||||
$source = file_get_contents($url);
|
||||
$source = $this->download_url($url);
|
||||
// the following should always exist for GitLab Community Edition or GitLab Enterprise Edition
|
||||
if (preg_match("/<meta content='GitLab (Community|Enterprise) Edition' name='description'>/", $source) > 0) {
|
||||
$parse = parse_url($url);
|
||||
@@ -255,7 +255,7 @@ class DockerTemplates {
|
||||
$doc = new DOMDocument();
|
||||
$doc->load($file['path']);
|
||||
if ($name) {
|
||||
if ($doc->getElementsByTagName('Name')->item(0)->nodeValue !== $name) continue;
|
||||
if (@$doc->getElementsByTagName('Name')->item(0)->nodeValue !== $name) continue;
|
||||
}
|
||||
$TemplateRepository = DockerUtil::ensureImageTag($doc->getElementsByTagName('Repository')->item(0)->nodeValue??'');
|
||||
if ($TemplateRepository && $TemplateRepository==$Repository) {
|
||||
@@ -293,7 +293,7 @@ class DockerTemplates {
|
||||
}
|
||||
|
||||
public function getAllInfo($reload=false,$com=true,$communityApplications=false) {
|
||||
global $dockerManPaths, $host;
|
||||
global $driver, $dockerManPaths, $host;
|
||||
$DockerClient = new DockerClient();
|
||||
$DockerUpdate = new DockerUpdate();
|
||||
//$DockerUpdate->verbose = $this->verbose;
|
||||
@@ -307,9 +307,8 @@ class DockerTemplates {
|
||||
$tmp['paused'] = $ct['Paused'];
|
||||
$tmp['autostart'] = in_array($name,$autoStart);
|
||||
$tmp['cpuset'] = $ct['CPUset'];
|
||||
$tmp['url'] = $tmp['url'] ?? '';
|
||||
$tmp['url'] = $ct['Url'] ?? $tmp['url'] ?? '';
|
||||
// read docker label for WebUI & Icon
|
||||
if (isset($ct['Url']) && !$tmp['url']) $tmp['url'] = $ct['Url'];
|
||||
if (isset($ct['Icon'])) $tmp['icon'] = $ct['Icon'];
|
||||
if (isset($ct['Shell'])) $tmp['shell'] = $ct['Shell'];
|
||||
if (!$communityApplications) {
|
||||
@@ -322,8 +321,18 @@ class DockerTemplates {
|
||||
// non-templated webui, user specified
|
||||
$tmp['url'] = $webui;
|
||||
} else {
|
||||
$ip = ($ct['NetworkMode']=='host'||_var($port,'NAT')) ? $host : _var($port,'IP');
|
||||
if ($ct['NetworkMode']=='host') {
|
||||
$ip = $host;
|
||||
} elseif (isset($driver[$ct['NetworkMode']]) && ($driver[$ct['NetworkMode']] == 'ipvlan' || $driver[$ct['NetworkMode']] == 'macvlan')) {
|
||||
$ip = reset($ct['Networks'])['IPAddress'];
|
||||
} elseif (!is_null(_var($port,'PublicPort'))) {
|
||||
$ip = $host;
|
||||
} else {
|
||||
$ip = _var($port,'IP');
|
||||
}
|
||||
$tmp['url'] = $ip ? (strpos($tmp['url'],$ip)!==false ? $tmp['url'] : $this->getControlURL($ct, $ip, $tmp['url'])) : $tmp['url'];
|
||||
if (strpos($ct['NetworkMode'], 'container:') === 0)
|
||||
$tmp['url'] = '';
|
||||
}
|
||||
if ( ($tmp['shell'] ?? false) == false )
|
||||
$tmp['shell'] = $this->getTemplateValue($image, 'Shell');
|
||||
@@ -338,8 +347,12 @@ class DockerTemplates {
|
||||
$tmp['updated'] = var_export($DockerUpdate->getUpdateStatus($image),true);
|
||||
}
|
||||
if (!$com) $tmp['updated'] = 'undef';
|
||||
if (empty($tmp['template']) || $reload) $tmp['template'] = $this->getUserTemplate($name);
|
||||
if ($reload) $DockerUpdate->updateUserTemplate($name);
|
||||
if ($ct['Manager'] !== 'dockerman')
|
||||
$tmp['template'] = null;
|
||||
else if (empty($tmp['template']) || $reload) {
|
||||
$tmp['template'] = $this->getUserTemplate($name);
|
||||
if ($reload) $DockerUpdate->updateUserTemplate($name);
|
||||
}
|
||||
//$this->debug("\n$name");
|
||||
//foreach ($tmp as $c => $d) $this->debug(sprintf(' %-10s: %s', $c, $d));
|
||||
}
|
||||
@@ -353,7 +366,6 @@ class DockerTemplates {
|
||||
if (!$imgUrl) $imgUrl = $tmpIconUrl;
|
||||
if (!$imgUrl || trim($imgUrl) == "/plugins/dynamix.docker.manager/images/question.png") return '';
|
||||
|
||||
$imageName = $contName ?: $name;
|
||||
$iconRAM = sprintf('%s/%s-%s.png', $dockerManPaths['images-ram'], $contName, 'icon');
|
||||
$icon = sprintf('%s/%s-%s.png', $dockerManPaths['images'], $contName, 'icon');
|
||||
|
||||
@@ -367,8 +379,8 @@ class DockerTemplates {
|
||||
if (!is_file($icon) && is_file($iconRAM)) {
|
||||
@copy($iconRAM,$icon);
|
||||
}
|
||||
if ( !is_file($iconRAM) ) {
|
||||
exec("logger -t webGUI -- \"$imageName: Could not download icon $imgUrl\"");
|
||||
if (!is_file($iconRAM)) {
|
||||
my_logger("$contName: Could not download icon $imgUrl");
|
||||
}
|
||||
|
||||
return (is_file($iconRAM)) ? str_replace($docroot, '', $iconRAM) : '';
|
||||
@@ -429,7 +441,7 @@ class DockerUpdate{
|
||||
|
||||
// DEPRECATED: Only used for Docker Index V1 type update checks
|
||||
public function getRemoteVersion($image) {
|
||||
[$strRepo, $strTag] = array_pad(explode(':', DockerUtil::ensureImageTag($image)),2,'');
|
||||
extract(DockerUtil::parseImageTag($image));
|
||||
$apiUrl = sprintf('http://index.docker.io/v1/repositories/%s/tags/%s', $strRepo, $strTag);
|
||||
//$this->debug("API URL: $apiUrl");
|
||||
$apiContent = $this->download_url($apiUrl);
|
||||
@@ -437,7 +449,7 @@ class DockerUpdate{
|
||||
}
|
||||
|
||||
public function getRemoteVersionV2($image) {
|
||||
[$strRepo, $strTag] = array_pad(explode(':', DockerUtil::ensureImageTag($image)),2,'');
|
||||
extract(DockerUtil::parseImageTag($image));
|
||||
/*
|
||||
* Step 1: Check whether or not the image is in a private registry, get corresponding auth data and generate manifest url
|
||||
*/
|
||||
@@ -722,7 +734,7 @@ class DockerClient {
|
||||
$fp = stream_socket_client('unix:///var/run/docker.sock', $errno, $errstr);
|
||||
if ($fp === false) {
|
||||
echo "Couldn't create socket: [$errno] $errstr";
|
||||
return null;
|
||||
return [];
|
||||
}
|
||||
$protocol = $unchunk ? 'HTTP/1.0' : 'HTTP/1.1';
|
||||
$out = "$method {$api}{$url} $protocol\r\nHost:127.0.0.1\r\nConnection:Close\r\n";
|
||||
@@ -812,6 +824,13 @@ class DockerClient {
|
||||
global $docroot, $dockerManPaths;
|
||||
$id = $id ?: $name;
|
||||
$info = DockerUtil::loadJSON($dockerManPaths['webui-info']);
|
||||
|
||||
// Check to see if the container is linked to other containers
|
||||
$networks = array_map(function ($n) { return $n['NetworkMode']; }, $this->getDockerContainers());
|
||||
if (in_array("container:{$name}", $networks)) {
|
||||
return "Container currently assigned as network for another container.";
|
||||
}
|
||||
|
||||
// Attempt to remove container
|
||||
$this->getDockerJSON("/containers/$id?force=1", 'DELETE', $code);
|
||||
if (isset($info[$name])) {
|
||||
@@ -898,7 +917,7 @@ class DockerClient {
|
||||
}
|
||||
|
||||
public function getDockerContainers() {
|
||||
global $driver;
|
||||
global $driver, $host;
|
||||
// Return cached values
|
||||
if (is_array($this::$containersCache)) return $this::$containersCache;
|
||||
$this::$containersCache = [];
|
||||
@@ -916,29 +935,58 @@ class DockerClient {
|
||||
$c['Volumes'] = $info['HostConfig']['Binds'];
|
||||
$c['Created'] = $this->humanTiming($ct['Created']);
|
||||
$c['NetworkMode'] = $ct['HostConfig']['NetworkMode'];
|
||||
$c['Manager'] = $info['Config']['Labels']['net.unraid.docker.managed'] ?? false;
|
||||
if ($c['Manager'] == 'composeman') {
|
||||
$c['ComposeProject'] = $info['Config']['Labels']['com.docker.compose.project'];
|
||||
}
|
||||
[$net, $id] = array_pad(explode(':',$c['NetworkMode']),2,'');
|
||||
$c['CPUset'] = $info['HostConfig']['CpusetCpus'];
|
||||
$c['BaseImage'] = $ct['Labels']['BASEIMAGE'] ?? false;
|
||||
$c['Icon'] = $info['Config']['Labels']['net.unraid.docker.icon'] ?? false;
|
||||
$c['Url'] = $info['Config']['Labels']['net.unraid.docker.webui'] ?? false;
|
||||
$c['Shell'] = $info['Config']['Labels']['net.unraid.docker.shell'] ?? false;
|
||||
$c['Manager'] = $info['Config']['Labels']['net.unraid.docker.managed'] ?? false;
|
||||
$c['Ports'] = [];
|
||||
$c['Networks'] = [];
|
||||
if ($id) $c['NetworkMode'] = $net.str_replace('/',':',DockerUtil::ctMap($id)?:'/???');
|
||||
if (isset($driver[$c['NetworkMode']])) {
|
||||
if ($driver[$c['NetworkMode']]=='bridge') {
|
||||
$ports = &$info['HostConfig']['PortBindings'];
|
||||
$nat = true;
|
||||
} elseif ($driver[$c['NetworkMode']]=='host') {
|
||||
$c['Ports']['host'] = ['host' => ''];
|
||||
} elseif ($driver[$c['NetworkMode']]=='ipvlan' || $driver[$c['NetworkMode']]=='macvlan') {
|
||||
$i = $ct['NetworkSettings']['Networks'][$c['NetworkMode']]['IPAddress'];
|
||||
$c['Ports']['vlan'] = ["$i" => $i];
|
||||
} else {
|
||||
$ports = &$info['Config']['ExposedPorts'];
|
||||
$nat = false;
|
||||
}
|
||||
$ip = $ct['NetworkSettings']['Networks'][$c['NetworkMode']]['IPAddress'];
|
||||
} else if (!$id) {
|
||||
$c['NetworkMode'] = DockerUtil::ctMap($c['NetworkMode']);
|
||||
$ports = &$info['Config']['ExposedPorts'];
|
||||
}
|
||||
foreach($ct['NetworkSettings']['Networks'] as $netName => $netVals) {
|
||||
$i = $c['NetworkMode']=='host' ? $host : $netVals['IPAddress'];
|
||||
$c['Networks'][$netName] = [ 'IPAddress' => $i ];
|
||||
if ($driver[$netName]=='ipvlan' || $driver[$netName]=='macvlan') {
|
||||
if (!isset($c['Ports']['vlan'])) $c['Ports']['vlan'] = [];
|
||||
$c['Ports']['vlan']["$i"] = $i;
|
||||
}
|
||||
}
|
||||
$ip = $c['NetworkMode']=='host' ? $host : $ct['NetworkSettings']['Networks'][$c['NetworkMode']]['IPAddress'] ?? null;
|
||||
$c['Networks'][$c['NetworkMode']] = [ 'IPAddress' => $ip ];
|
||||
$ports = (isset($ports) && is_array($ports)) ? $ports : [];
|
||||
foreach ($ports as $port => $value) {
|
||||
if (!isset($info['HostConfig']['PortBindings'][$port])) {
|
||||
continue;
|
||||
}
|
||||
[$PrivatePort, $Type] = array_pad(explode('/', $port),2,'');
|
||||
$c['Ports'][] = ['IP' => $ip, 'PrivatePort' => $PrivatePort, 'PublicPort' => $nat ? $value[0]['HostPort'] : $PrivatePort, 'NAT' => $nat, 'Type' => $Type];
|
||||
$PublicPort = $info['HostConfig']['PortBindings']["$port"][0]['HostPort'] ?: null;
|
||||
$nat = ($driver[$c['NetworkMode']]=='bridge');
|
||||
if (array_key_exists($PrivatePort, $c['Ports']) && $Type != $c['Ports'][$PrivatePort]['Type'])
|
||||
$Type = $c['Ports'][$PrivatePort]['Type'] . '/' . $Type;
|
||||
$c['Ports'][$PrivatePort] = ['IP' => $ip, 'PrivatePort' => $PrivatePort, 'PublicPort' => $PublicPort, 'NAT' => $nat, 'Type' => $Type, 'Driver' => $driver[$c['NetworkMode']]];
|
||||
}
|
||||
ksort($c['Ports']);
|
||||
$this::$containersCache[] = $c;
|
||||
}
|
||||
array_multisort(array_column($this::$containersCache,'Name'), SORT_NATURAL|SORT_FLAG_CASE, $this::$containersCache);
|
||||
@@ -979,9 +1027,9 @@ class DockerClient {
|
||||
$c['Id'] = $this->extractID($ct['Id']);
|
||||
$c['ParentId'] = $this->extractID($ct['ParentId']);
|
||||
$c['Size'] = $this->formatBytes($ct['Size']);
|
||||
$c['VirtualSize'] = $this->formatBytes($ct['VirtualSize']);
|
||||
$c['VirtualSize'] = $this->formatBytes($ct['VirtualSize'] ?? null);
|
||||
$c['Tags'] = array_map('htmlspecialchars', $ct['RepoTags'] ?? []);
|
||||
$c['Repository'] = vsprintf('%1$s/%2$s', preg_split("#[:\/]#", DockerUtil::ensureImageTag($ct['RepoTags'][0]??'')));
|
||||
$c['Repository'] = DockerUtil::parseImageTag($ct['RepoTags'][0]??'')['strRepo'];
|
||||
$c['usedBy'] = $this->usedBy($c['Id']);
|
||||
$this::$imagesCache[$c['Id']] = $c;
|
||||
}
|
||||
@@ -994,18 +1042,50 @@ class DockerClient {
|
||||
##################################
|
||||
|
||||
class DockerUtil {
|
||||
public static function ensureImageTag($image) {
|
||||
[$strRepo, $strTag] = array_map('trim', array_pad(explode(':', $image.':'),2,''));
|
||||
if (strpos($strRepo, 'sha256:') === 0) {
|
||||
public static function ensureImageTag($image): string
|
||||
{
|
||||
extract(static::parseImageTag($image));
|
||||
|
||||
return "$strRepo:$strTag";
|
||||
}
|
||||
|
||||
public static function parseImageTag($image): array
|
||||
{
|
||||
if (strpos($image, 'sha256:') === 0) {
|
||||
// sha256 was provided instead of actual repo name so truncate it for display:
|
||||
$strRepo = substr($strRepo, 7, 12);
|
||||
} elseif (strpos($strRepo, '/') === false) {
|
||||
// Prefix library/ if there's no author (maybe a Docker offical image?)
|
||||
$strRepo = "library/$strRepo";
|
||||
$strRepo = substr($image, 7, 12);
|
||||
} elseif (strpos($image, '/') === false) {
|
||||
return static::parseImageTag('library/' . $image);
|
||||
} else {
|
||||
$parsedImage = static::splitImage($image);
|
||||
if (!empty($parsedImage)) {
|
||||
$strRepo = $parsedImage['strRepo'];
|
||||
$strTag = $parsedImage['strTag'];
|
||||
} else {
|
||||
// Unprocessable input
|
||||
$strRepo = $image;
|
||||
}
|
||||
}
|
||||
|
||||
// Add :latest tag to image if it's absent
|
||||
if (empty($strTag)) $strTag = 'latest';
|
||||
return "$strRepo:$strTag";
|
||||
|
||||
return array_map('trim', ['strRepo' => $strRepo, 'strTag' => $strTag]);
|
||||
}
|
||||
|
||||
private static function splitImage($image): ?array
|
||||
{
|
||||
if (false === preg_match('@^(.+/)*([^/:]+)(:[^:/]*)*$@', $image, $newSections) || count($newSections) < 3) {
|
||||
return null;
|
||||
} else {
|
||||
[, $strRepo, $image, $strTag] = array_merge($newSections, ['']);
|
||||
$strTag = str_replace(':','',$strTag??'');
|
||||
|
||||
return [
|
||||
'strRepo' => $strRepo . $image,
|
||||
'strTag' => $strTag,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public static function loadJSON($path) {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2014-2023, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -12,8 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
|
||||
@@ -34,7 +33,7 @@ if (!$containers && !$images) {
|
||||
}
|
||||
|
||||
if (file_exists($user_prefs)) {
|
||||
$prefs = @parse_ini_file($user_prefs) ?: [];
|
||||
$prefs = (array)@parse_ini_file($user_prefs);
|
||||
$sort = [];
|
||||
foreach ($containers as $ct) $sort[] = array_search($ct['Name'],$prefs);
|
||||
array_multisort($sort,SORT_NUMERIC,$containers);
|
||||
@@ -46,7 +45,7 @@ $allInfo = $DockerTemplates->getAllInfo();
|
||||
$docker = [];
|
||||
$null = '0.0.0.0';
|
||||
|
||||
$autostart = @file($autostart_file,FILE_IGNORE_NEW_LINES) ?: [];
|
||||
$autostart = (array)@file($autostart_file,FILE_IGNORE_NEW_LINES);
|
||||
$names = array_map('var_split',$autostart);
|
||||
|
||||
function my_lang_time($text) {
|
||||
@@ -70,7 +69,8 @@ foreach ($containers as $ct) {
|
||||
$running = $info['running'] ? 1 : 0;
|
||||
$paused = $info['paused'] ? 1 : 0;
|
||||
$is_autostart = $info['autostart'] ? 'true':'false';
|
||||
$updateStatus = substr($ct['NetworkMode'],-4)==':???' ? 2 : ($info['updated']=='true' ? 0 : ($info['updated']=='false' ? 1 : 3));
|
||||
$composestack = isset($ct['ComposeProject']) ? $ct['ComposeProject'] : '';
|
||||
$updateStatus = substr($ct['NetworkMode'], -4) == ':???' ? 2 : ($info['updated'] == 'true' ? 0 : ($info['updated'] == 'false' ? 1 : 3));
|
||||
$template = $info['template']??'';
|
||||
$shell = $info['shell']??'';
|
||||
$webGui = html_entity_decode($info['url']??'');
|
||||
@@ -84,15 +84,34 @@ foreach ($containers as $ct) {
|
||||
$shape = $running ? ($paused ? 'pause' : 'play') : 'square';
|
||||
$status = $running ? ($paused ? 'paused' : 'started') : 'stopped';
|
||||
$color = $status=='started' ? 'green-text' : ($status=='paused' ? 'orange-text' : 'red-text');
|
||||
$update = $updateStatus==1 ? 'blue-text' : '';
|
||||
$update = $updateStatus==1 && !empty($compose) ? 'blue-text' : '';
|
||||
$icon = $info['icon'] ?: '/plugins/dynamix.docker.manager/images/question.png';
|
||||
$image = substr($icon,-4)=='.png' ? "<img src='$icon?".filemtime("$docroot{$info['icon']}")."' class='img' onerror=this.src='/plugins/dynamix.docker.manager/images/question.png';>" : (substr($icon,0,5)=='icon-' ? "<i class='$icon img'></i>" : "<i class='fa fa-$icon img'></i>");
|
||||
$wait = var_split($autostart[array_search($name,$names)]??'',1);
|
||||
$ports = [];
|
||||
foreach ($ct['Ports'] as $port) {
|
||||
$intern = $running ? ($ct['NetworkMode']=='host' ? $host : _var($port,'IP')) : $null;
|
||||
$extern = $running ? (_var($port,'NAT') ? $host : $intern) : $null;
|
||||
$ports[] = sprintf('%s:%s/%s<i class="fa fa-arrows-h" style="margin:0 6px"></i>%s:%s', $intern, _var($port,'PrivatePort'), strtoupper(_var($port,'Type')), $extern, _var($port,'PublicPort'));
|
||||
$networks = [];
|
||||
$network_ips = [];
|
||||
$ports_internal = [];
|
||||
$ports_external = [];
|
||||
if (isset($ct['Ports']['vlan'])) {
|
||||
foreach ($ct['Ports']['vlan'] as $i)
|
||||
$ports_external[] = sprintf('%s', $i);
|
||||
$ports_internal[0] = sprintf('%s', 'all');
|
||||
}
|
||||
foreach($ct['Networks'] as $netName => $netVals) {
|
||||
$networks[] = $netName;
|
||||
$network_ips[] = $running ? $netVals['IPAddress'] : null;
|
||||
|
||||
if (isset($ct['Networks']['host'])) {
|
||||
$ports_external[] = sprintf('%s', $netVals['IPAddress']);
|
||||
$ports_internal[0] = sprintf('%s', 'all');
|
||||
} else if (!isset($ct['Ports']['vlan']) || strpos($ct['NetworkMode'], 'container:') != 0) {
|
||||
foreach ($ct['Ports'] as $port) {
|
||||
if (_var($port,'PublicPort') && _var($port,'Driver') == 'bridge')
|
||||
$ports_external[] = sprintf('%s:%s', $host, strtoupper(_var($port,'PublicPort')));
|
||||
if ((!isset($ct['Networks']['host'])) || (!isset($ct['Networks']['vlan'])))
|
||||
$ports_internal[] = sprintf('%s:%s', _var($port,'PrivatePort'), strtoupper(_var($port,'Type')));
|
||||
}
|
||||
}
|
||||
}
|
||||
$paths = [];
|
||||
$ct['Volumes'] = is_array($ct['Volumes']) ? $ct['Volumes'] : [];
|
||||
@@ -101,17 +120,17 @@ foreach ($containers as $ct) {
|
||||
$paths[] = sprintf('%s<i class="fa fa-%s" style="margin:0 6px"></i>%s', htmlspecialchars($container_path), $access_mode=='ro'?'long-arrow-left':'arrows-h', htmlspecialchars($host_path));
|
||||
}
|
||||
echo "<tr class='sortable'><td class='ct-name' style='width:220px;padding:8px'><i class='fa fa-arrows-v mover orange-text'></i>";
|
||||
if ($template) {
|
||||
if ($template && empty($composestack)) {
|
||||
$appname = "<a class='exec' onclick=\"editContainer('".addslashes(htmlspecialchars($name))."','".addslashes(htmlspecialchars($template))."')\">".htmlspecialchars($name)."</a>";
|
||||
} else {
|
||||
$appname = htmlspecialchars($name);
|
||||
}
|
||||
echo "<span class='outer'><span id='$id' $menu class='hand'>$image</span><span class='inner'><span class='appname $update'>$appname</span><br><i id='load-$id' class='fa fa-$shape $status $color'></i><span class='state'>"._($status)."</span></span></span>";
|
||||
echo "<span class='outer'><span id='$id' $menu class='hand'>$image</span><span class='inner'><span class='appname $update'>$appname</span><br><i id='load-$id' class='fa fa-$shape $status $color'></i><span class='state'>"._($status).(!empty($composestack) ? '<br/>Compose Stack: ' . $composestack : '')."</span></span></span>";
|
||||
echo "<div class='advanced' style='margin-top:8px'>"._('Container ID').": $id<br>";
|
||||
if ($ct['BaseImage']) echo "<i class='fa fa-cubes' style='margin-right:5px'></i>".htmlspecialchars(${ct['BaseImage']})."<br>";
|
||||
if ($ct['BaseImage']) echo "<i class='fa fa-cubes' style='margin-right:5px'></i>".htmlspecialchars($ct['BaseImage'])."<br>";
|
||||
echo _('By').": ";
|
||||
$registry = $info['registry'];
|
||||
[$author,$version] = my_explode(':',$ct['Image']);
|
||||
['strRepo' => $author, 'strTag' => $version] = DockerUtil::parseImageTag($ct['Image']);
|
||||
if ($registry) {
|
||||
echo "<a href='".htmlspecialchars($registry)."' target='_blank'>".htmlspecialchars(compress($author,24))."</a>";
|
||||
} else {
|
||||
@@ -119,30 +138,64 @@ foreach ($containers as $ct) {
|
||||
}
|
||||
echo "</div></td><td class='updatecolumn'>";
|
||||
switch ($updateStatus) {
|
||||
case 0:
|
||||
echo "<span class='green-text' style='white-space:nowrap;'><i class='fa fa-check fa-fw'></i> "._('up-to-date')."</span>";
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('force update')."</span></a></div>";
|
||||
break;
|
||||
case 1:
|
||||
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> "._('update ready')."</span></div>";
|
||||
echo "<a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('apply update')."</span></a>";
|
||||
break;
|
||||
case 2:
|
||||
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> "._('rebuild ready')."</span></div>";
|
||||
echo "<a class='exec'><span style='white-space:nowrap;'><i class='fa fa-recycle fa-fw'></i> "._('rebuilding')."</span></a>";
|
||||
break;
|
||||
default:
|
||||
echo "<span class='orange-text' style='white-space:nowrap;'><i class='fa fa-unlink'></i> "._('not available')."</span>";
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('force update')."</span></a></div>";
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
if ($ct['Manager'] == "dockerman") {
|
||||
echo "<span class='green-text' style='white-space:nowrap;'><i class='fa fa-check fa-fw'></i> "._('up-to-date')."</span>";
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('force update')."</span></a></div>";
|
||||
} elseif (!empty($composestack)) {
|
||||
echo "<div><span><i class='fa fa-docker fa-fw'/></i> Compose</span></div>";
|
||||
echo "<span tyle='white-space:nowrap;'><i class='fa fa-check fa-fw'></i> "._('up-to-date')."</span>";
|
||||
} else {
|
||||
echo "<div><span><i class='fa fa-docker fa-fw'/></i> 3rd Party</span></div>";
|
||||
echo "<span tyle='white-space:nowrap;'><i class='fa fa-check fa-fw'></i> "._('up-to-date')."</span>";
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> "._('update ready')."</span></div>";
|
||||
if ($ct['Manager'] == "dockerman") {
|
||||
echo "<a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('apply update')."</span></a>";
|
||||
} elseif (!empty($composestack)) {
|
||||
echo "<div><span><i class='fa fa-docker fa-fw'/></i> Compose</span></a></div>";
|
||||
echo "<span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('update available')."</span>";
|
||||
} else {
|
||||
echo "<div><span><i class='fa fa-docker fa-fw'/></i> 3rd Party</span></div>";
|
||||
echo "<span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('update available')."</span>";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> "._('rebuild ready')."</span></div>";
|
||||
echo "<a class='exec'><span style='white-space:nowrap;'><i class='fa fa-recycle fa-fw'></i> "._('rebuilding')."</span></a>";
|
||||
break;
|
||||
default:
|
||||
if ($ct['Manager'] == "dockerman") {
|
||||
echo "<span class='orange-text' style='white-space:nowrap;'><i class='fa fa-unlink'></i> "._('not available')."</span>";
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> "._('force update')."</span></a></div>";
|
||||
} elseif (!empty($composestack)) {
|
||||
echo "<div><span><i class='fa fa-docker fa-fw'/></i> Compose</span></div>";
|
||||
echo "<span style='white-space:nowrap;'><i class='fa fa-unlink'></i> "._('not available')."</span>";
|
||||
} else {
|
||||
echo "<div><span><i class='fa fa-docker fa-fw'/></i> 3rd Party</span></div>";
|
||||
echo "<span style='white-space:nowrap;'><i class='fa fa-unlink'></i> "._('not available')."</span>";
|
||||
}
|
||||
break;
|
||||
}
|
||||
echo "<div class='advanced'><i class='fa fa-info-circle fa-fw'></i> ".compress(_($version),12,0)."</div></td>";
|
||||
echo "<td>{$ct['NetworkMode']}</td>";
|
||||
echo "<td style='white-space:nowrap'><span class='docker_readmore'>".implode('<br>',$ports)."</span></td>";
|
||||
echo "<td style='white-space:nowrap'><span class='docker_readmore'> ".implode('<br>',$networks)."</span></td>";
|
||||
echo "<td style='white-space:nowrap'><span class='docker_readmore'> ".implode('<br>',$network_ips)."</span></td>";
|
||||
echo "<td style='white-space:nowrap'><span class='docker_readmore'>".implode('<br>',$ports_internal)."</span></td>";
|
||||
echo "<td style='white-space:nowrap'><span class='docker_readmore'>".implode('<br>',$ports_external)."</span></td>";
|
||||
echo "<td style='word-break:break-all'><span class='docker_readmore'>".implode('<br>',$paths)."</span></td>";
|
||||
echo "<td class='advanced'><span class='cpu-$id'>0%</span><div class='usage-disk mm'><span id='cpu-$id' style='width:0'></span><span></span></div>";
|
||||
echo "<br><span class='mem-$id'>0 / 0</span></td>";
|
||||
echo "<td><input type='checkbox' id='$id-auto' class='autostart' container='".htmlspecialchars($name)."'".($info['autostart'] ? ' checked':'').">";
|
||||
if (empty($composestack)) {
|
||||
if ($ct['Manager'] == "dockerman") {
|
||||
echo "<td><input type='checkbox' id='$id-auto' class='autostart' container='".htmlspecialchars($name)."'".($info['autostart'] ? ' checked':'').">";
|
||||
} else {
|
||||
echo "<td><i class='fa fa-docker fa-fw'/></i> 3rd Party";
|
||||
}
|
||||
} else {
|
||||
echo "<td><i class='fa fa-docker'/></i> Compose";
|
||||
}
|
||||
echo "<span id='$id-wait' style='float:right;display:none'>"._('wait')."<input class='wait' container='".htmlspecialchars($name)."' type='number' value='$wait' placeholder='0' title=\""._('seconds')."\"></span></td>";
|
||||
echo "<td><div style='white-space:nowrap'>".htmlspecialchars(str_replace('Up',_('Uptime').':',my_lang_log($ct['Status'])))."<div style='margin-top:4px'>"._('Created').": ".htmlspecialchars(my_lang_time($ct['Created']))."</div></div></td></tr>";
|
||||
}
|
||||
@@ -158,3 +211,4 @@ foreach ($images as $image) {
|
||||
}
|
||||
echo "\0".implode($docker)."\0".(pgrep('rc.docker')!==false ? 1:0);
|
||||
?>
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2022, Lime Technology
|
||||
* Copyright 2014-2022, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2022, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -12,10 +12,11 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
$ncsi = exec("wget --spider --no-check-certificate -nv -T10 -t1 https://www.msftncsi.com/ncsi.txt 2>&1|grep -o 'OK'")=='OK';
|
||||
$ncsi = check_network_connectivity();
|
||||
$DockerTemplates = new DockerTemplates();
|
||||
if ($ncsi) $DockerTemplates->downloadTemplates();
|
||||
$DockerTemplates->getAllInfo($ncsi,$ncsi);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2014-2023, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -12,8 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Secure.php";
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2014-2023, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -40,7 +40,11 @@ function postToXML($post, $setOwnership=false) {
|
||||
$xml->Name = xml_encode(preg_replace('/\s+/', '', $post['contName']));
|
||||
$xml->Repository = xml_encode(trim($post['contRepository']));
|
||||
$xml->Registry = xml_encode(trim($post['contRegistry']));
|
||||
$xml->Network = xml_encode($post['contNetwork']);
|
||||
if (!empty(trim($post['netCONT']))) {
|
||||
$xml->Network = xml_encode($post['contNetwork'].':'.$post['netCONT']);
|
||||
} else {
|
||||
$xml->Network = xml_encode($post['contNetwork']);
|
||||
}
|
||||
$xml->MyIP = xml_encode($post['contMyIP']);
|
||||
$xml->Shell = xml_encode($post['contShell']);
|
||||
$xml->Privileged = strtolower($post['contPrivileged']??'')=='on' ? 'true' : 'false';
|
||||
@@ -59,7 +63,7 @@ function postToXML($post, $setOwnership=false) {
|
||||
$xml->DonateLink = xml_encode($post['contDonateLink']);
|
||||
$xml->Requires = xml_encode($post['contRequires']);
|
||||
|
||||
$size = is_array($post['confName']) ? count($post['confName']) : 0;
|
||||
$size = is_array($post['confName']??null) ? count($post['confName']) : 0;
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$Type = $post['confType'][$i];
|
||||
$config = $xml->addChild('Config', xml_encode($post['confValue'][$i]));
|
||||
@@ -132,7 +136,11 @@ function xmlToVar($xml) {
|
||||
$out['Network'] = xml_decode($xml->Networking->Mode);
|
||||
}
|
||||
// check if network exists
|
||||
if (!key_exists($out['Network'],$subnet)) $out['Network'] = 'none';
|
||||
if (preg_match('/^container:(.*)/', $out['Network'])) {
|
||||
$out['Network'] = $out['Network'];
|
||||
} elseif (!key_exists($out['Network'],$subnet)) {
|
||||
$out['Network'] = 'none';
|
||||
}
|
||||
// V1 compatibility
|
||||
if ($xml['version'] != '2') {
|
||||
if (isset($xml->Description)) {
|
||||
@@ -237,11 +245,15 @@ function xmlSecurity(&$template) {
|
||||
}
|
||||
|
||||
function xmlToCommand($xml, $create_paths=false) {
|
||||
global $docroot, $var, $cfg, $driver;
|
||||
global $docroot, $var, $driver;
|
||||
$xml = xmlToVar($xml);
|
||||
$cmdName = strlen($xml['Name']) ? '--name='.escapeshellarg($xml['Name']) : '';
|
||||
$cmdPrivileged = strtolower($xml['Privileged'])=='true' ? '--privileged=true' : '';
|
||||
$cmdNetwork = preg_match('/\-\-net(work)?=/',$xml['ExtraParams']) ? "" : '--net='.escapeshellarg(strtolower($xml['Network']));
|
||||
if (preg_match('/^container:(.*)/', $xml['Network'])) {
|
||||
$cmdNetwork = preg_match('/\-\-net(work)?=/',$xml['ExtraParams']) ? "" : '--net='.escapeshellarg($xml['Network']);
|
||||
} else {
|
||||
$cmdNetwork = preg_match('/\-\-net(work)?=/',$xml['ExtraParams']) ? "" : '--net='.escapeshellarg(strtolower($xml['Network']));
|
||||
}
|
||||
$cmdMyIP = '';
|
||||
foreach (explode(' ',str_replace(',',' ',$xml['MyIP'])) as $myIP) if ($myIP) $cmdMyIP .= (strpos($myIP,':')?'--ip6=':'--ip=').escapeshellarg($myIP).' ';
|
||||
$cmdCPUset = strlen($xml['CPUset']) ? '--cpuset-cpus='.escapeshellarg($xml['CPUset']) : '';
|
||||
@@ -270,6 +282,8 @@ function xmlToCommand($xml, $create_paths=false) {
|
||||
$Mode = strval($config['Mode']);
|
||||
if ($confType != "device" && !strlen($containerConfig)) continue;
|
||||
if ($confType == "path") {
|
||||
if ( ! trim($hostConfig) || ! trim($containerConfig) )
|
||||
continue;
|
||||
$Volumes[] = escapeshellarg($hostConfig).':'.escapeshellarg($containerConfig).':'.escapeshellarg($Mode);
|
||||
if (!file_exists($hostConfig) && $create_paths) {
|
||||
@mkdir($hostConfig, 0777, true);
|
||||
@@ -299,15 +313,27 @@ function xmlToCommand($xml, $create_paths=false) {
|
||||
$Devices[] = escapeshellarg($hostConfig);
|
||||
}
|
||||
}
|
||||
$logSize = $logFile = '';
|
||||
if (($cfg['DOCKER_LOG_ROTATION']??'')=='yes') {
|
||||
$logSize = $cfg['DOCKER_LOG_SIZE'] ?? '10m';
|
||||
$logSize = "--log-opt max-size='$logSize'";
|
||||
$logFile = $cfg['DOCKER_LOG_FILES'] ?? '1';
|
||||
$logFile = "--log-opt max-file='$logFile'";
|
||||
|
||||
/* Read the docker configuration file. */
|
||||
$cfgfile = "/boot/config/docker.cfg";
|
||||
$config_ini = @parse_ini_file($cfgfile, true, INI_SCANNER_RAW);
|
||||
$docker_cfg = ($config_ini !== false) ? $config_ini : [];
|
||||
|
||||
// Add pid limit if user has not specified it as an extra parameter
|
||||
$pidsLimit = preg_match('/--pids-limit (\d+)/', $xml['ExtraParams'], $matches) ? $matches[1] : null;
|
||||
if ($pidsLimit === null) {
|
||||
$pid_limit = "--pids-limit ";
|
||||
if (($docker_cfg['DOCKER_PID_LIMIT']??'') != "") {
|
||||
$pid_limit .= $docker_cfg['DOCKER_PID_LIMIT'];
|
||||
} else {
|
||||
$pid_limit .= "2048";
|
||||
}
|
||||
} else {
|
||||
$pid_limit = "";
|
||||
}
|
||||
$cmd = sprintf($docroot.'/plugins/dynamix.docker.manager/scripts/docker create %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s',
|
||||
$cmdName, $cmdNetwork, $cmdMyIP, $cmdCPUset, $logSize, $logFile, $cmdPrivileged, implode(' -e ', $Variables), implode(' -l ', $Labels), implode(' -p ', $Ports), implode(' -v ', $Volumes), implode(' --device=', $Devices), $xml['ExtraParams'], escapeshellarg($xml['Repository']), $xml['PostArgs']);
|
||||
|
||||
$cmd = sprintf($docroot.'/plugins/dynamix.docker.manager/scripts/docker create %s %s %s %s %s %s %s %s %s %s %s %s %s %s',
|
||||
$cmdName, $cmdNetwork, $cmdMyIP, $cmdCPUset, $pid_limit, $cmdPrivileged, implode(' -e ', $Variables), implode(' -l ', $Labels), implode(' -p ', $Ports), implode(' -v ', $Volumes), implode(' --device=', $Devices), $xml['ExtraParams'], escapeshellarg($xml['Repository']), $xml['PostArgs']);
|
||||
return [preg_replace('/\s\s+/', ' ', $cmd), $xml['Name'], $xml['Repository']];
|
||||
}
|
||||
function stopContainer($name, $t=false, $echo=true) {
|
||||
@@ -501,9 +527,15 @@ function getAllocations() {
|
||||
$nat = $ip = false;
|
||||
$list['Name'] = $ct['Name'];
|
||||
foreach ($ct['Ports'] as $tmp) {
|
||||
$nat = $tmp['NAT'];
|
||||
$ip = $tmp['IP'];
|
||||
$port[] = $tmp['PublicPort'];
|
||||
if (isset($tmp['NAT'])) {
|
||||
$nat = $tmp['NAT'];
|
||||
}
|
||||
if (isset($tmp['IP'])) {
|
||||
$ip = $tmp['IP'];
|
||||
}
|
||||
if (isset($tmp['PublicPort'])) {
|
||||
$port[] = $tmp['PublicPort'];
|
||||
}
|
||||
}
|
||||
sort($port);
|
||||
$ip = $ct['NetworkMode']=='host'||$nat ? $host : ($ip ?: DockerUtil::myIP($ct['Name']) ?: '0.0.0.0');
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2018, Lime Technology
|
||||
* Copyright 2012-2018, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2021, Lime Technology
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2021, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
|
||||
$autostart_file = $dockerManPaths['autostart-file'];
|
||||
@@ -25,7 +25,7 @@ case 'autostart':
|
||||
$container = urldecode(($_POST['container']));
|
||||
$wait = $_POST['wait'];
|
||||
$item = rtrim("$container $wait");
|
||||
$autostart = @file($autostart_file, FILE_IGNORE_NEW_LINES) ?: [];
|
||||
$autostart = (array)@file($autostart_file, FILE_IGNORE_NEW_LINES);
|
||||
$key = array_search($item, $autostart);
|
||||
if ($_POST['auto']=='true') {
|
||||
if ($key===false) $autostart[] = $item;
|
||||
@@ -48,7 +48,7 @@ case 'wait':
|
||||
$container = urldecode(($_POST['container']));
|
||||
$wait = $_POST['wait'];
|
||||
$item = rtrim("$container $wait");
|
||||
$autostart = file($autostart_file, FILE_IGNORE_NEW_LINES) ?: [];
|
||||
$autostart = (array)@file($autostart_file, FILE_IGNORE_NEW_LINES);
|
||||
$names = array_map('var_split', $autostart);
|
||||
$autostart[array_search($container,$names)] = $item;
|
||||
file_put_contents($autostart_file, implode("\n", $autostart)."\n");
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?PHP
|
||||
/* Copyright 2005-2018, Lime Technology
|
||||
* Copyright 2015-2018, Derek Macias, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2018, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
|
||||
$autostart_file = $dockerManPaths['autostart-file'];
|
||||
|
@@ -61,17 +61,15 @@ function popupWithIframe(title, cmd, reload, func) {
|
||||
$('#iframe-popup').dialog({
|
||||
autoOpen:true,
|
||||
title:title,
|
||||
height: 600,
|
||||
width: 900,
|
||||
draggable:true,
|
||||
width: Math.min(Math.max(window.innerWidth/2,900),1600),
|
||||
height: Math.max(window.innerHeight*3/5,600),
|
||||
resizable:true,
|
||||
modal:true,
|
||||
show:{effect:'fade', duration:250},
|
||||
hide:{effect:'fade', duration:250},
|
||||
open:function(ev, ui) {
|
||||
open:function(ev, ui){
|
||||
$('#myIframe').attr('src', cmd);
|
||||
},
|
||||
close:function(event, ui) {
|
||||
close:function(event, ui){
|
||||
if (reload && !$('#myIframe').contents().find('#canvas').length) {
|
||||
if (func) setTimeout(func+'()',0); else location = window.location.href;
|
||||
} else {
|
||||
@@ -79,13 +77,13 @@ function popupWithIframe(title, cmd, reload, func) {
|
||||
}
|
||||
}
|
||||
});
|
||||
$(".ui-dialog .ui-dialog-titlebar").addClass('menu');
|
||||
$('.ui-dialog .ui-dialog-titlebar-close').text('X').prop('title',_('Close'));
|
||||
$(".ui-dialog .ui-dialog-title").css({'text-align':'center','width':'100%'});
|
||||
$(".ui-dialog .ui-dialog-content").css({'padding-top':'15px','vertical-align':'bottom'});
|
||||
$('.ui-dialog-titlebar-close').css({'display':'none'});
|
||||
$('.ui-dialog-title').css({'text-align':'center','width':'100%','font-size':'1.8rem'});
|
||||
$('.ui-dialog-content').css({'padding-top':'15px','vertical-align':'bottom'});
|
||||
$('.ui-button-text').css({'padding':'0px 5px'});
|
||||
}
|
||||
function execUpContainer(container) {
|
||||
var title = _('Updating the container')+': '+container;
|
||||
var title = _('Updating the container TEST')+': '+container;
|
||||
var cmd = '/plugins/dynamix.docker.manager/include/CreateDocker.php?updateContainer=true&ct[]='+encodeURIComponent(container);
|
||||
popupWithIframe(title, cmd, true, 'loadlist');
|
||||
}
|
||||
|
@@ -32,7 +32,7 @@ input:hover[type=button],input:hover[type=reset],input:hover[type=submit],button
|
||||
input[type=button][disabled],input[type=reset][disabled],input[type=submit][disabled],button[disabled],button[type=button][disabled],a.button[disabled]
|
||||
input:hover[type=button][disabled],input:hover[type=reset][disabled],input:hover[type=submit][disabled],button:hover[disabled],button:hover[type=button][disabled],a.button:hover[disabled]
|
||||
input:active[type=button][disabled],input:active[type=reset][disabled],input:active[type=submit][disabled],button:active[disabled],button:active[type=button][disabled],a.button:active[disabled]
|
||||
{cursor:default;color:#808080;background:-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#404040),to(#404040)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#808080),to(#808080)) 100% 100% no-repeat;background:linear-gradient(90deg,#404040 0,#808080) 0 0 no-repeat,linear-gradient(90deg,#404040 0,#808080) 0 100% no-repeat,linear-gradient(0deg,#404040 0,#404040) 0 100% no-repeat,linear-gradient(0deg,#808080 0,#808080) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
{opacity:0.5;cursor:default;color:#808080;background:-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#404040),to(#808080)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#404040),to(#404040)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#808080),to(#808080)) 100% 100% no-repeat;background:linear-gradient(90deg,#404040 0,#808080) 0 0 no-repeat,linear-gradient(90deg,#404040 0,#808080) 0 100% no-repeat,linear-gradient(0deg,#404040 0,#404040) 0 100% no-repeat,linear-gradient(0deg,#808080 0,#808080) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
p.centered{text-align:center}
|
||||
span.error{color:#D8000C;background-color:#FFBABA;display:block;width:100%}
|
||||
span.warn{color:#9F6000;background-color:#FEEFB3;display:block;width:100%}
|
||||
|
@@ -12,8 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
|
||||
@@ -22,7 +21,7 @@ $_SERVER['REQUEST_URI'] = 'docker';
|
||||
$login_locale = _var($display,'locale');
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
$unit = ['B','kB','MB','GB','TB','PB','EB','ZB','YB'];
|
||||
$units = ['B','kB','MB','GB','TB','PB','EB','ZB','YB'];
|
||||
$list = [];
|
||||
|
||||
function write(...$messages){
|
||||
@@ -40,13 +39,13 @@ function write(...$messages){
|
||||
curl_close($com);
|
||||
}
|
||||
function autoscale($value) {
|
||||
global $unit;
|
||||
$size = count($unit);
|
||||
global $units;
|
||||
$size = count($units);
|
||||
$base = $value ? floor(log($value, 1000)) : 0;
|
||||
if ($base>=$size) $base = $size-1;
|
||||
$value /= pow(1000, $base);
|
||||
$decimals = $base ? ($value>=100 ? 0 : ($value>=10 ? 1 : (round($value*100)%100===0 ? 0 : 2))) : 0;
|
||||
return number_format($value, $decimals, '.', $value>9999 ? ',' : '').' '.$unit[$base];
|
||||
return number_format($value, $decimals, '.', $value>9999 ? ',' : '').' '.$units[$base];
|
||||
}
|
||||
function align($text, $w=25) {
|
||||
return $text.str_repeat(' ',$w-min(strlen($text),$w-1));
|
||||
@@ -55,9 +54,9 @@ function gap($text) {
|
||||
return preg_replace('/([kMGTPEZY]?B)$/'," $1",$text);
|
||||
}
|
||||
function byteval($data) {
|
||||
global $unit;
|
||||
global $units;
|
||||
[$value,$base] = explode(' ',gap($data));
|
||||
return $value*pow(1000,array_search($base,$unit));
|
||||
return $value*pow(1000,array_search($base,$units));
|
||||
}
|
||||
|
||||
exec("docker ps -sa --format='{{.Names}}|{{.Size}}'",$container);
|
||||
|
@@ -13,27 +13,46 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
/* Define the path to the docker configuration file */
|
||||
$cfgfile = "/boot/config/docker.cfg";
|
||||
|
||||
/* Define the default configuration values */
|
||||
$cfg_defaults = [
|
||||
"DOCKER_ENABLED" => "no",
|
||||
"DOCKER_IMAGE_FILE" => "/mnt/user/system/docker/docker.img",
|
||||
"DOCKER_IMAGE_SIZE" => "20",
|
||||
"DOCKER_APP_CONFIG_PATH" => "/mnt/user/appdata/",
|
||||
"DOCKER_APP_UNRAID_PATH" => "",
|
||||
"DOCKER_READMORE" => "yes"
|
||||
"DOCKER_ENABLED" => "no",
|
||||
"DOCKER_IMAGE_FILE" => "/mnt/user/system/docker/docker.img",
|
||||
"DOCKER_IMAGE_SIZE" => "20",
|
||||
"DOCKER_APP_CONFIG_PATH" => "/mnt/user/appdata/",
|
||||
"DOCKER_APP_UNRAID_PATH" => "",
|
||||
"DOCKER_READMORE" => "yes",
|
||||
"DOCKER_PID_LIMIT" => ""
|
||||
];
|
||||
|
||||
/* Initialize the new configuration with the default values */
|
||||
$cfg_new = $cfg_defaults;
|
||||
|
||||
/* Check if the configuration file exists */
|
||||
if (file_exists($cfgfile)) {
|
||||
$cfg_old = parse_ini_file($cfgfile);
|
||||
if (!empty($cfg_old)) {
|
||||
$cfg_new = array_merge($cfg_defaults, $cfg_old);
|
||||
if (empty(array_diff($cfg_new, $cfg_old))) unset($cfg_new);
|
||||
}
|
||||
/* Parse the existing configuration file */
|
||||
$cfg_old = parse_ini_file($cfgfile);
|
||||
|
||||
/* If the existing configuration is not empty, merge it with the defaults */
|
||||
if (!empty($cfg_old)) {
|
||||
/* Merge only missing keys from defaults */
|
||||
$cfg_new = array_merge($cfg_defaults, $cfg_old);
|
||||
|
||||
/* If there are no changes between the new and old configurations, unset the new configuration */
|
||||
if (empty(array_diff_assoc($cfg_new, $cfg_old))) {
|
||||
$cfg_new = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the new configuration is set, write it to the configuration file */
|
||||
if (isset($cfg_new)) {
|
||||
$tmp = '';
|
||||
foreach ($cfg_new as $key => $value) $tmp .= "$key=\"$value\"\n";
|
||||
file_put_contents($cfgfile, $tmp);
|
||||
$tmp = '';
|
||||
foreach ($cfg_new as $key => $value) {
|
||||
$tmp .= "$key=\"$value\"\n";
|
||||
}
|
||||
file_put_contents($cfgfile, $tmp);
|
||||
}
|
||||
?>
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2014-2023, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* Copyright 2005-2024, Lime Technology
|
||||
* Copyright 2012-2024, Bergware International.
|
||||
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -13,10 +13,10 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
// this command will set the $notify array
|
||||
extract(parse_plugin_cfg('dynamix', true));
|
||||
|
||||
// Multi-language support
|
||||
@@ -24,7 +24,7 @@ $_SERVER['REQUEST_URI'] = "scripts";
|
||||
$login_locale = _var($display,'locale');
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
exec("pgrep docker", $pid);
|
||||
exec('pgrep --ns $$ docker', $pid);
|
||||
if (count($pid) == 1) exit(0);
|
||||
|
||||
$DockerClient = new DockerClient();
|
||||
@@ -44,8 +44,8 @@ if (!isset($check)) {
|
||||
$DockerTemplates->getAllInfo(true);
|
||||
echo " Done.";
|
||||
} else {
|
||||
$notify = "$docroot/webGui/scripts/notify";
|
||||
$var = @parse_ini_file("/var/local/emhttp/var.ini") ?: [];
|
||||
$script = "$docroot/webGui/scripts/notify";
|
||||
$var = (array)@parse_ini_file("/var/local/emhttp/var.ini");
|
||||
$server = strtoupper(_var($var,'NAME','tower'));
|
||||
$output = _var($notify,'docker_notify');
|
||||
$info = $DockerTemplates->getAllInfo(true);
|
||||
@@ -60,7 +60,7 @@ if (!isset($check)) {
|
||||
$event = str_replace("'","'",_("Docker")." - $name [$new]");
|
||||
$subject = str_replace("'","'",sprintf(_("Notice [%s] - Version update %s"),$server,$new));
|
||||
$description = str_replace("'","'",sprintf(_("A new version of %s is available"),$name));
|
||||
exec("$notify -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Docker' -x");
|
||||
exec("$script -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Docker' -x");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
|
||||
|
||||
$DockerClient = new DockerClient();
|
||||
|
@@ -12,8 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
|
||||
@@ -179,11 +178,16 @@ foreach (explode('*',rawurldecode($argv[1])) as $value) {
|
||||
$startContainer = false;
|
||||
if (!empty($oldContainerInfo) && !empty($oldContainerInfo['State']) && !empty($oldContainerInfo['State']['Running'])) {
|
||||
// since container was already running, put it back it to a running state after update
|
||||
$cmd = str_replace('/docker create ', '/docker run -d ', $cmd);
|
||||
$startContainer = true;
|
||||
// attempt graceful stop of container first
|
||||
stopContainer_nchan($Name);
|
||||
}
|
||||
if ( ($argv[2]??null) == "ca_docker_run_override" )
|
||||
$startContainer = true;
|
||||
|
||||
if ( $startContainer )
|
||||
$cmd = str_replace('/docker create ', '/docker run -d ', $cmd);
|
||||
|
||||
// force kill container if still running after 10 seconds
|
||||
if (empty($_GET['communityApplications'])) removeContainer_nchan($Name);
|
||||
execCommand_nchan($cmd);
|
||||
|
@@ -0,0 +1 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#f2f2f2}
|
@@ -0,0 +1 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#1c1c1c}
|
@@ -0,0 +1 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#1c1c1c}
|
@@ -0,0 +1 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#f2f2f2}
|
@@ -0,0 +1,14 @@
|
||||
.noshow,.advanced{display:none}
|
||||
.required:after{content:" *";color:#E80000}
|
||||
span.boxed{display:inline-block;line-height:normal;white-space:normal;width:60%}
|
||||
span.cpu,label.checkbox{display:inline-block;width:32px}
|
||||
span.ct{display:inline-block;width:230px}
|
||||
span.net{display:inline-block;width:120px}
|
||||
span.ip{display:inline-block;width:160px}
|
||||
dl,dt,dd{line-height:normal!important;height:auto!important}
|
||||
dl{padding:8px 0!important}
|
||||
dl>dt:nth-of-type(2),dl>dd:nth-of-type(2){padding:20px 0 0 0!important}
|
||||
input.setting_input{margin-right:4rem}
|
||||
input,select{margin-top:-0.8rem!important}
|
||||
div#configLocation,div#configLocation dl{padding:0!important}
|
||||
div#configLocation dt{margin-top:-0.18rem!important}
|
@@ -0,0 +1,12 @@
|
||||
.basic{display:block}
|
||||
.advanced{display:none;white-space:nowrap}
|
||||
.log{cursor:zoom-in}
|
||||
.exec{cursor:pointer}
|
||||
table#docker_containers{text-align:left}
|
||||
th.five{width:5%}
|
||||
th.nine{width:9%}
|
||||
th.load{width:140px}
|
||||
input.wait{width:24px;margin:0 4px;padding:0 5px;border:none;box-shadow:none;background-color:transparent}
|
||||
table tbody td{line-height:normal}
|
||||
i.mover{margin-right:8px;display:none}
|
||||
#resetsort{margin-left:12px;display:inline-block;width:32px}
|
@@ -0,0 +1,2 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
span.disabled{color:#B0B0B0}
|
@@ -0,0 +1,2 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
span.disabled{color:#404040}
|
@@ -0,0 +1,2 @@
|
||||
.fileTree{background:#1c1c1c;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
span.disabled{color:#404040}
|
@@ -0,0 +1,2 @@
|
||||
.fileTree{background:#f2f2f2;width:300px;max-height:150px;overflow-y:scroll;overflow-x:hidden;position:absolute;z-index:100;display:none}
|
||||
span.disabled{color:#B0B0B0}
|
@@ -0,0 +1,17 @@
|
||||
.errortext{color:#EF3D47;display:none;margin-left:20px}
|
||||
.basic{display:inline-block}
|
||||
.advanced{display:none}
|
||||
select.mask{min-width:0;margin:0 10px 0 4px}
|
||||
select.net{min-width:0;margin:0 4px 0 2px}
|
||||
select option.hide{display:none}
|
||||
input.ip4{width:100px;margin:0 4px 0 1px}
|
||||
input.ip6{width:140px;margin:0 4px}
|
||||
input.gw4{width:100px;margin:0 4px 0 1px}
|
||||
input.gw6{width:160px;margin:0 4px}
|
||||
input.pool6{width:40px;margin:0 4px 0 1px}
|
||||
span.net{margin-left:4px;margin-right:2px}
|
||||
span.ip4{display:inline-block;width:260px}
|
||||
span.ip6{display:inline-block;width:310px}
|
||||
span.gw4{display:inline-block;width:200px}
|
||||
span.gw6{display:inline-block;width:270px}
|
||||
span.nonexist{margin-left:20px}
|
@@ -0,0 +1 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#f2f2f2}
|
@@ -0,0 +1 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#1c1c1c}
|
@@ -0,0 +1 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#1c1c1c}
|
@@ -0,0 +1 @@
|
||||
.fileTree{width:240px;max-height:200px;overflow-y:scroll;overflow-x:hidden;position:absolute;display:none;background:#f2f2f2}
|
@@ -0,0 +1,14 @@
|
||||
.noshow,.advanced{display:none}
|
||||
.required:after{content:" *";color:#E80000}
|
||||
span.boxed{display:inline-block;line-height:normal;white-space:normal;width:60%}
|
||||
span.cpu,label.checkbox{display:inline-block;width:32px}
|
||||
span.ct{display:inline-block;width:230px}
|
||||
span.net{display:inline-block;width:120px}
|
||||
span.ip{display:inline-block;width:160px}
|
||||
dl,dt,dd{line-height:normal!important;height:auto!important}
|
||||
dl{padding:8px 0!important}
|
||||
dl>dt:nth-of-type(2),dl>dd:nth-of-type(2){padding:20px 0 0 0!important}
|
||||
input.setting_input{margin-right:4rem}
|
||||
input,select{margin-top:-0.8rem!important}
|
||||
div#configLocation,div#configLocation dl{padding:0!important}
|
||||
div#configLocation dt{margin-top:-0.18rem!important}
|
@@ -1,62 +1,14 @@
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{
|
||||
font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{
|
||||
color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)
|
||||
}
|
||||
.ui-dropdownchecklist .ui-state-default{
|
||||
background:#f2f2f2;
|
||||
border:none;
|
||||
box-shadow:none;
|
||||
outline:none;
|
||||
cursor:pointer;
|
||||
height:2.2rem;
|
||||
line-height:2.2rem;
|
||||
}
|
||||
.ui-dropdownchecklist-group{
|
||||
font-weight:normal;
|
||||
font-style:italic;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector{
|
||||
border:1px solid #1c1c1c;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector-wrapper{
|
||||
vertical-align:middle;
|
||||
font-size:0;
|
||||
}
|
||||
.ui-widget-header{
|
||||
border:none;
|
||||
background:#e3e3e3;
|
||||
color:#1c1c1c;
|
||||
font-weight:bold;
|
||||
}
|
||||
.ui-widget-content{
|
||||
border:1px solid #1c1c1c;
|
||||
background:#f2f2f2;
|
||||
color:#1c1c1c;
|
||||
|
||||
.ui-state-active{
|
||||
background:#e8e8e8;
|
||||
}
|
||||
.ui-dropdownchecklist-dropcontainer{
|
||||
background:#f2f2f2;
|
||||
border:1px solid #1c1c1c;
|
||||
}
|
||||
.ui-state-disabled{
|
||||
color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5;
|
||||
}
|
||||
.ui-dropdownchecklist-indent{
|
||||
padding-left:7px;
|
||||
}
|
||||
.ui-dropdownchecklist-text{
|
||||
color:#1c1c1c;
|
||||
font-size:1.3rem;
|
||||
}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{
|
||||
background:#f2f2f2;
|
||||
border:0px;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.ui-dropdownchecklist .ui-state-default{background:#f2f2f2;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
|
||||
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #1c1c1c;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
|
||||
.ui-widget-header{border:none;background:#e3e3e3;color:#1c1c1c;font-weight:bold}
|
||||
.ui-widget-content{border:1px solid #1c1c1c;background:#f2f2f2;color:#1c1c1c}
|
||||
.ui-state-active{background:#e8e8e8}
|
||||
.ui-dropdownchecklist-dropcontainer{background:#f2f2f2;border:1px solid #1c1c1c}
|
||||
.ui-state-disabled{color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5}
|
||||
.ui-dropdownchecklist-indent{padding-left:7px}
|
||||
.ui-dropdownchecklist-text{color:#1c1c1c;font-size:1.3rem}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#f2f2f2;border:0px}
|
||||
|
@@ -1,62 +1,14 @@
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{
|
||||
font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{
|
||||
color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)
|
||||
}
|
||||
.ui-dropdownchecklist .ui-state-default{
|
||||
background:#1c1c1c;
|
||||
border:none;
|
||||
box-shadow:none;
|
||||
outline:none;
|
||||
cursor:pointer;
|
||||
height:2.2rem;
|
||||
line-height:2.2rem;
|
||||
}
|
||||
.ui-dropdownchecklist-group{
|
||||
font-weight:normal;
|
||||
font-style:italic;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector{
|
||||
border:1px solid #e5e5e5;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector-wrapper{
|
||||
vertical-align:middle;
|
||||
font-size:0;
|
||||
}
|
||||
.ui-widget-header{
|
||||
border:none;
|
||||
background:#2b2b2b;
|
||||
color:#f2f2f2;
|
||||
font-weight:bold;
|
||||
}
|
||||
.ui-widget-content{
|
||||
border:1px solid #e5e5e5;
|
||||
background:#1c1c1c;
|
||||
color:#f2f2f2;
|
||||
|
||||
.ui-state-active{
|
||||
background:#262626;
|
||||
}
|
||||
.ui-dropdownchecklist-dropcontainer{
|
||||
background:#1c1c1c;
|
||||
border:1px solid #e5e5e5;
|
||||
}
|
||||
.ui-state-disabled{
|
||||
color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5;
|
||||
}
|
||||
.ui-dropdownchecklist-indent{
|
||||
padding-left:7px;
|
||||
}
|
||||
.ui-dropdownchecklist-text{
|
||||
color:#f2f2f2;
|
||||
font-size:1.3rem;
|
||||
}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{
|
||||
background:#1c1c1c;
|
||||
border:0px;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.ui-dropdownchecklist .ui-state-default{background:#1c1c1c;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
|
||||
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #e5e5e5;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
|
||||
.ui-widget-header{border:none;background:#2b2b2b;color:#f2f2f2;font-weight:bold}
|
||||
.ui-widget-content{border:1px solid #e5e5e5;background:#1c1c1c;color:#f2f2f2}
|
||||
.ui-state-active{background:#262626}
|
||||
.ui-dropdownchecklist-dropcontainer{background:#1c1c1c;border:1px solid #e5e5e5}
|
||||
.ui-state-disabled{color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5}
|
||||
.ui-dropdownchecklist-indent{padding-left:7px}
|
||||
.ui-dropdownchecklist-text{color:#f2f2f2;font-size:1.3rem}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#1c1c1c;border:0px}
|
||||
|
@@ -1,62 +1,14 @@
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{
|
||||
font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{
|
||||
color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)
|
||||
}
|
||||
.ui-dropdownchecklist .ui-state-default{
|
||||
background:#1c1c1c;
|
||||
border:none;
|
||||
box-shadow:none;
|
||||
outline:none;
|
||||
cursor:pointer;
|
||||
height:2.2rem;
|
||||
line-height:2.2rem;
|
||||
}
|
||||
.ui-dropdownchecklist-group{
|
||||
font-weight:normal;
|
||||
font-style:italic;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector{
|
||||
border:1px solid #e5e5e5;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector-wrapper{
|
||||
vertical-align:middle;
|
||||
font-size:0;
|
||||
}
|
||||
.ui-widget-header{
|
||||
border:none;
|
||||
background:#2b2b2b;
|
||||
color:#f2f2f2;
|
||||
font-weight:bold;
|
||||
}
|
||||
.ui-widget-content{
|
||||
border:1px solid #e5e5e5;
|
||||
background:#1c1c1c;
|
||||
color:#f2f2f2;
|
||||
|
||||
.ui-state-active{
|
||||
background:#262626;
|
||||
}
|
||||
.ui-dropdownchecklist-dropcontainer{
|
||||
background:#1c1c1c;
|
||||
border:1px solid #e5e5e5;
|
||||
}
|
||||
.ui-state-disabled{
|
||||
color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5;
|
||||
}
|
||||
.ui-dropdownchecklist-indent{
|
||||
padding-left:7px;
|
||||
}
|
||||
.ui-dropdownchecklist-text{
|
||||
color:#f2f2f2;
|
||||
font-size:1.3rem;
|
||||
}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{
|
||||
background:#1c1c1c;
|
||||
border:0px;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.ui-dropdownchecklist .ui-state-default{background:#1c1c1c;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
|
||||
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #e5e5e5;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
|
||||
.ui-widget-header{border:none;background:#2b2b2b;color:#f2f2f2;font-weight:bold}
|
||||
.ui-widget-content{border:1px solid #e5e5e5;background:#1c1c1c;color:#f2f2f2}
|
||||
.ui-state-active{background:#262626}
|
||||
.ui-dropdownchecklist-dropcontainer{background:#1c1c1c;border:1px solid #e5e5e5}
|
||||
.ui-state-disabled{color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5}
|
||||
.ui-dropdownchecklist-indent{padding-left:7px}
|
||||
.ui-dropdownchecklist-text{color:#f2f2f2;font-size:1.3rem}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#1c1c1c;border:0px}
|
||||
|
@@ -1,62 +1,14 @@
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{
|
||||
font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{
|
||||
color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)
|
||||
}
|
||||
.ui-dropdownchecklist .ui-state-default{
|
||||
background:#f2f2f2;
|
||||
border:none;
|
||||
box-shadow:none;
|
||||
outline:none;
|
||||
cursor:pointer;
|
||||
height:2.2rem;
|
||||
line-height:2.2rem;
|
||||
}
|
||||
.ui-dropdownchecklist-group{
|
||||
font-weight:normal;
|
||||
font-style:italic;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector{
|
||||
border:1px solid #1c1c1c;
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
padding:1px 9px 1px 8px;
|
||||
}
|
||||
.ui-dropdownchecklist-selector-wrapper{
|
||||
vertical-align:middle;
|
||||
font-size:0;
|
||||
}
|
||||
.ui-widget-header{
|
||||
border:none;
|
||||
background:#e3e3e3;
|
||||
color:#1c1c1c;
|
||||
font-weight:bold;
|
||||
}
|
||||
.ui-widget-content{
|
||||
border:1px solid #1c1c1c;
|
||||
background:#f2f2f2;
|
||||
color:#1c1c1c;
|
||||
|
||||
.ui-state-active{
|
||||
background:#e8e8e8;
|
||||
}
|
||||
.ui-dropdownchecklist-dropcontainer{
|
||||
background:#f2f2f2;
|
||||
border:1px solid #1c1c1c;
|
||||
}
|
||||
.ui-state-disabled{
|
||||
color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5;
|
||||
}
|
||||
.ui-dropdownchecklist-indent{
|
||||
padding-left:7px;
|
||||
}
|
||||
.ui-dropdownchecklist-text{
|
||||
color:#1c1c1c;
|
||||
font-size:1.3rem;
|
||||
}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{
|
||||
background:#f2f2f2;
|
||||
border:0px;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
|
||||
.ui-dropdownchecklist .ui-state-default{background:#f2f2f2;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
|
||||
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector{border:1px solid #1c1c1c;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
|
||||
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
|
||||
.ui-widget-header{border:none;background:#e3e3e3;color:#1c1c1c;font-weight:bold}
|
||||
.ui-widget-content{border:1px solid #1c1c1c;background:#f2f2f2;color:#1c1c1c}
|
||||
.ui-state-active{background:#e8e8e8}
|
||||
.ui-dropdownchecklist-dropcontainer{background:#f2f2f2;border:1px solid #1c1c1c}
|
||||
.ui-state-disabled{color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5}
|
||||
.ui-dropdownchecklist-indent{padding-left:7px}
|
||||
.ui-dropdownchecklist-text{color:#1c1c1c;font-size:1.3rem}
|
||||
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#f2f2f2;border:0px}
|
||||
|
28
emhttp/plugins/dynamix.docker.manager/system/Docker
Executable file
28
emhttp/plugins/dynamix.docker.manager/system/Docker
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
# Get active containers
|
||||
ACTIVE_CONTAINERS="$(docker ps -q --no-trunc 2>/dev/null)"
|
||||
|
||||
# Exit if no containers are active and return zero
|
||||
if [ -z "${ACTIVE_CONTAINERS}" ]; then
|
||||
echo "0"
|
||||
exit
|
||||
fi
|
||||
|
||||
# Get all relevant memory entries from containers
|
||||
for container in ${ACTIVE_CONTAINERS} ; do
|
||||
CONT_MEMORY="$(cat /sys/fs/cgroup/docker/${container}/memory.stat 2>/dev/null | grep -Ew "anon|kernel|kernel_stack|pagetables|sec_pagetables|percpu|sock|vmalloc|shmem" | awk '{print $2}')"
|
||||
# Add up memory values
|
||||
for value in ${CONT_MEMORY} ; do
|
||||
if [[ ${value} =~ ^[0-9]+$ ]]; then
|
||||
((MEMORY_USAGE += value))
|
||||
fi
|
||||
done
|
||||
unset CONT_MEMORY
|
||||
done
|
||||
|
||||
# Check if value is a integer and return the value otherwiese return zero
|
||||
if [[ ${MEMORY_USAGE} =~ ^[0-9]+$ ]]; then
|
||||
echo "${MEMORY_USAGE}"
|
||||
else
|
||||
echo "0"
|
||||
fi
|
115
emhttp/plugins/dynamix.gui.search/gui_search.page
Normal file
115
emhttp/plugins/dynamix.gui.search/gui_search.page
Normal file
@@ -0,0 +1,115 @@
|
||||
Menu='Buttons:1'
|
||||
Icon='icon-u-search'
|
||||
Title='Search'
|
||||
Code='e956'
|
||||
---
|
||||
<?
|
||||
###################################################
|
||||
# #
|
||||
# GUI Search copyright 2021-2023, Andrew Zawadzki #
|
||||
# Licenced under GPLv2 #
|
||||
# #
|
||||
###################################################
|
||||
|
||||
$currentUnraidPage = str_replace('Browse','Main',basename(explode('?',$_SERVER['REQUEST_URI'])[0]));
|
||||
$guiSearchBoxSpan = "<span id='guiSearchBoxSpan'><input type='text' id='guiSearchBox' autocomplete='new-password'></input></span><span class='guiSearchBoxResults'></span>";
|
||||
?>
|
||||
<script>
|
||||
var languageVisible;
|
||||
var guiSearchSuggestions;
|
||||
|
||||
var browserName = (function(agent){
|
||||
switch (true) {
|
||||
case agent.indexOf('edge') >= 0: return 'Edge'; // Edge
|
||||
case agent.indexOf('edg/') >= 0: return 'Edge'; // Edge Chromium Based
|
||||
case agent.indexOf('opr') >= 0 && !!window.opr: return 'Opera';
|
||||
case agent.indexOf('chrome') >= 0 && !!window.chrome: return 'Chrome';
|
||||
case agent.indexOf('trident') >= 0: return 'MS IE';
|
||||
case agent.indexOf('firefox') >= 0: return 'Mozilla Firefox';
|
||||
case agent.indexOf('safari') >= 0: return 'Safari';
|
||||
default: return 'other';
|
||||
}
|
||||
})(window.navigator.userAgent.toLowerCase());
|
||||
|
||||
$(function(){
|
||||
<?if ($themes2):?>
|
||||
$('.nav-item.gui_search').hover(function(){gui_search();},function(e){closeSearchBox(e);});
|
||||
<?endif;?>
|
||||
$.post('/plugins/dynamix.gui.search/include/exec.php',function(data) {
|
||||
if (data) {
|
||||
try {guiSearchSuggestions = JSON.parse(data); setupGUIsearch();}
|
||||
catch(e) {console.log('Invalid JSON for GUI search autocomplete');}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function guiSearchBoxSpan() {
|
||||
return $('#guiSearchBoxSpan').length>0;
|
||||
}
|
||||
|
||||
function setupGUIsearch() {
|
||||
window.addEventListener('keydown',function(e){
|
||||
if (!e.shiftKey && !e.altKey && (navigator.appVersion.indexOf('Mac')==-1 ? e.ctrlKey : e.metaKey) && e.keyCode==75) {
|
||||
e.preventDefault();
|
||||
<?if ($themes1):?>
|
||||
if (guiSearchBoxSpan()) closeSearchBox(e); else gui_search();
|
||||
<?endif;?>
|
||||
}
|
||||
});
|
||||
if (browserName != 'Chrome' && browserName != 'Edge') {
|
||||
var hashTag = (window.location.hash||'').substr(1).replace('%20',' ').replace('%2d','-');
|
||||
if (hashTag.length) $('body').mark(hashTag,{'accuracy': {'value': 'exactly','limiters': ['.',':','?']},'separateWordSearch': false});
|
||||
}
|
||||
}
|
||||
|
||||
function gui_search() {
|
||||
<?if ($themes1):?>
|
||||
languageVisible = $('.nav-item.LanguageButton').is(':visible');
|
||||
$('.nav-tile.right').prepend("<?=$guiSearchBoxSpan?>").css('overflow','visible');
|
||||
$('.nav-item.util,.nav-user.show').hide();
|
||||
<?else:?>
|
||||
if (!guiSearchBoxSpan()) $('.nav-item.gui_search a').append("<?=$guiSearchBoxSpan?>");
|
||||
$('.nav-item.gui_search').css('overflow','visible');
|
||||
<?endif;?>
|
||||
if (guiSearchSuggestions) {
|
||||
var guiSearchAwesomplete = new Awesomplete(document.getElementById('guiSearchBox'));
|
||||
guiSearchAwesomplete.list = guiSearchSuggestions;
|
||||
guiSearchAwesomplete.maxItems = 15;
|
||||
guiSearchAwesomplete.autoFirst = true;
|
||||
Awesomplete.$('#guiSearchBox').removeEventListener('awesomplete-selectcomplete',guiSearch);
|
||||
Awesomplete.$('#guiSearchBox').addEventListener('awesomplete-selectcomplete',guiSearch);
|
||||
$('#guiSearchBox').attr('autocomplete','new-password'); // Stop awesomplete from resetting autocomplete
|
||||
}
|
||||
$('#guiSearchBox').focus().keydown(function(e){if (e.which==27) closeSearchBox(e);}).blur(function(e){closeSearchBox(e);});
|
||||
}
|
||||
|
||||
function closeSearchBox(e) {
|
||||
e.stopPropagation();
|
||||
$('#guiSearchBoxSpan').remove();
|
||||
<?if ($themes1):?>
|
||||
$('.nav-tile.right').css({'overflow-x':'auto','overflow-y':'hidden'});
|
||||
$('.nav-item.util,.nav-user.show').show();
|
||||
if (!languageVisible) $('.nav-item.LanguageButton').hide();
|
||||
<?else:?>
|
||||
$('.nav-item.gui_search').css('overflow','hidden');
|
||||
<?endif;?>
|
||||
}
|
||||
|
||||
function guiSearch() {
|
||||
var searchInfo = $('#guiSearchBox').val().split('**');
|
||||
var separator = (browserName == 'Chrome' || browserName == 'Edge') ? '#:~:text=' : '#';
|
||||
var scrollText = (typeof searchInfo[1] != 'undefined') ? separator+searchInfo[1].replace(' ','%20').replace('-','%2d') : '';
|
||||
var newPage = "<?=$currentUnraidPage?>/Settings/Tools".replace(searchInfo[0]+'/','');
|
||||
|
||||
closeSearchBox(event);
|
||||
if (newPage == 'Dashboard/Settings/Tools') newPage = 'Settings';
|
||||
location.replace('/'+newPage+'/'+searchInfo[0]+scrollText);
|
||||
}
|
||||
|
||||
if (browserName != 'Chrome' && browserName != 'Edge') {
|
||||
var script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.src = '<?autov('/plugins/dynamix.gui.search/javascript/jquery.mark.js')?>';
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
}
|
||||
</script>
|
2
emhttp/plugins/gui.search/exec.php → emhttp/plugins/dynamix.gui.search/include/exec.php
Executable file → Normal file
2
emhttp/plugins/gui.search/exec.php → emhttp/plugins/dynamix.gui.search/include/exec.php
Executable file → Normal file
@@ -29,7 +29,7 @@ if ( $locale ) {
|
||||
}
|
||||
}
|
||||
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: "/usr/local/emhttp";
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
|
||||
$_SERVER['REQUEST_URI'] = $uri;
|
||||
$_SESSION['locale'] = $locale;
|
10
emhttp/plugins/dynamix.gui.search/javascript/jquery.mark.js
Normal file
10
emhttp/plugins/dynamix.gui.search/javascript/jquery.mark.js
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
|
||||
#guiSearchBoxSpan{display:inline-block;margin:0 0 0 20px;padding:0;height:auto;line-height:normal;font-size:1.3rem}
|
||||
#guiSearchBox{position:relative;top:0;left:0;width:50rem;border:none;border-radius:20px;margin:0;padding:5px 12px;color:#1c1b1b;background-color:#feefb3}
|
@@ -0,0 +1,3 @@
|
||||
#guiSearchBoxSpan{display:inline-block;position:relative;margin:4px 2px 2px 2px;padding:0;text-align:left;height:auto;line-height:normal;font-size:1.3rem}
|
||||
#guiSearchBoxSpan:after{font-family:unraid;content:'\e956';position:absolute;top:.8rem;left:1.5rem;font-size:1.3rem}
|
||||
#guiSearchBox{width:50rem;border:none;border-radius:20px;padding-left:4rem;opacity:0.5;invert(100%)}
|
@@ -0,0 +1,2 @@
|
||||
#guiSearchBoxSpan{display:inline-block;margin:0 0 0 20px;padding:0;height:auto;line-height:normal;font-size:1.3rem}
|
||||
#guiSearchBox{position:relative;top:0;left:0;width:50rem;border:none;border-radius:20px;margin:0;padding:5px 12px;color:#1c1b1b;background-color:#feefb3}
|
@@ -0,0 +1,3 @@
|
||||
#guiSearchBoxSpan{display:inline-block;position:relative;margin:4px 2px 2px 2px;padding:0;text-align:left;height:auto;line-height:normal;font-size:1.3rem}
|
||||
#guiSearchBoxSpan:after{font-family:unraid;content:'\e956';position:absolute;top:.8rem;left:1.5rem;font-size:1.3rem}
|
||||
#guiSearchBox{width:50rem;border:none;border-radius:20px;padding-left:4rem;opacity:0.5;invert(100%)}
|
@@ -1,10 +1,10 @@
|
||||
Menu="About"
|
||||
Menu="About:30"
|
||||
Type="xmenu"
|
||||
Title="Registration"
|
||||
Icon="icon-registration"
|
||||
Tag="pencil"
|
||||
---
|
||||
<?PHP
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -15,248 +15,6 @@ Tag="pencil"
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
function my_time_any($time) {
|
||||
return $time ? _(my_time($time),0) : _('Anytime');
|
||||
}
|
||||
function my_time_now($time) {
|
||||
return $time ? _(my_time($time),0) : _('Unknown');
|
||||
}
|
||||
|
||||
$regGen = (int)$var['regGen'] ?? 0;
|
||||
$trialExtensionEligible = $regGen === 0 || $regGen === 1;
|
||||
?>
|
||||
<style>
|
||||
span.thanks{padding-left:12px;color:#6FA239;font-weight:bold;}
|
||||
span.thanks.red{color:#F0000C;}
|
||||
div.device{padding:0 12px;font-weight:normal;font-style:italic;}
|
||||
div.remark{padding:0 12px;text-align:justify;}
|
||||
</style>
|
||||
|
||||
<?if ( (strstr($var['regTy'], "unregistered")) or ($var['regTy']=="Trial") or (strstr($var['regTy'], "no connection")) or (strstr($var['regTy'], "withdrawn")) or (strstr($var['regTy'], "expired")) ):?>
|
||||
|
||||
<span class="thanks">_(Thank you for trying Unraid OS)_!</span>
|
||||
|
||||
<?elseif ( ($var['regTy']=="Basic") or ($var['regTy']=="Plus") or ($var['regTy']=="Pro") ):?>
|
||||
|
||||
<span class="thanks">_(Thank you for choosing Unraid OS)_!</span>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "unregistered")):?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
:registration_1_plug:
|
||||
Your server will not be usable until you purchase a Registration key or install a free 30 day *Trial* key. A *Trial*
|
||||
key provides all the functionality of a *Pro* Registration key.
|
||||
|
||||
Registration keys are bound to your USB Flash boot device serial number (GUID). Please use a high quality name brand device
|
||||
at least 1GB in size (min 4GB recommended).
|
||||
|
||||
Note: USB memory card readers are generally **not** supported because most do not present unique serial numbers.
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if ($var['regTy']=="Trial"):?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
:registration_3_plug:
|
||||
Your *Trial* key includes all the functionality and device support of a *Pro* Registration key.
|
||||
|
||||
After your *Trial* key has reached expiration, your server **still functions normally** until the next time you **Stop** the array.
|
||||
|
||||
At that point, you may either purchase a Registration key, or request a *Trial* extension.
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "no connection")):?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
<span class='red-text'>_(Cannot connect to key-server)_!</span>
|
||||
|
||||
_(Your *Trial* key requires an internet connection)_. _(Please check your)_ [_(Network Settings)_](NetworkSettings).
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "withdrawn")):?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
<span class='red-text'>_(Release has been withdrawn)_!</span>
|
||||
|
||||
_(This release has been withdrawn for use with *Trial* keys)_.
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "expired")):?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
<span class='red-text'>_(Your *Trial* key has expired)_.</span>
|
||||
|
||||
<? if ($trialExtensionEligible): ?>
|
||||
:registration_4_plug:
|
||||
To continue using Unraid OS you may purchase a Registration key. Alternately, you may request a *Trial* extension key.
|
||||
:end
|
||||
<? else: ?>
|
||||
:registration_trial_extension_ineligible_plug:
|
||||
You have used all your Trial extensions. To continue using Unraid OS you may purchase a Registration key.
|
||||
:end
|
||||
<? endif; ?>
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "invalid installation")):?>
|
||||
|
||||
<span class='thanks red'>_(Invalid *Trial* Installation)_</span>
|
||||
<div markdown="1" class="remark">
|
||||
:registration_5_plug:
|
||||
It is not possible to use a *Trial* key with an existing Unraid OS installation.
|
||||
|
||||
You may purchase a Registration key corresponding to this USB Flash device to continue using this installation.
|
||||
|
||||
For more information, please [Contact Support](https://lime-technology.com/contact).
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "missing")):?>
|
||||
|
||||
<span class='thanks red'>_(Missing Key File)_</span>
|
||||
<div markdown="1" class="remark">
|
||||
:registration_6_plug:
|
||||
It appears that your Registration key file is corrupted or missing. The key file should be located in the
|
||||
[config](/Registration/Browse?dir=/boot/config) directory on your USB Flash boot device.
|
||||
|
||||
If you do not have a backup copy of your Registration key file, [Contact Support](https://lime-technology.com/contact).
|
||||
|
||||
If this was a *Trial* installation, you may purchase a Registration key.
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "invalid key")):?>
|
||||
|
||||
<span class='thanks red'>_(The registered GUID does not match the USB Flash boot device GUID)_</span>
|
||||
|
||||
<?if (strstr($var['regTy'], "Trial")):?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
:registration_7_plug:
|
||||
*Trial* installations are only valid with the originally registered USB Flash device.
|
||||
|
||||
To continue using this installation with this USB Flash device, you may purchase a Registration key.
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?else:?>
|
||||
|
||||
<div markdown="1" class="remark">
|
||||
:registration_8_plug:
|
||||
The Registration key file does not correspond to the USB Flash boot device.
|
||||
Please copy the correct key file to the [config](/Registration/Browse?dir=/boot/config) directory
|
||||
on your USB Flash boot device. If you do not have a backup copy of your key file, [Contact Support](https://lime-technology.com/contact).
|
||||
|
||||
If you want to replace your Registration key with a new key bound to this USB Flash device, click Replace Key below. An original key may be
|
||||
replaced anytime. Thereafter, a replacement key may be replaced again after one year has passed. If you require
|
||||
another replacement key sooner, [Contact Support](https://lime-technology.com/contact).
|
||||
|
||||
**Note:** Replacing a Registration key results in permanently *blacklisting* the previous USB Flash GUID.
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "blacklisted")):?>
|
||||
|
||||
<span class='thanks red'>_(Blacklisted USB Flash GUID)_</span>
|
||||
<div markdown="1" class="remark">
|
||||
:registration_9_plug:
|
||||
This USB Flash boot device has been *blacklisted*. This can occur as a result of transfering your Registration key to
|
||||
a replacement USB Flash device, and you are currently booted from your old USB Flash device.
|
||||
|
||||
A USB Flash device may also be *blacklisted* if there is no serial number, or if we discover the serial number
|
||||
is not unique (this is common with USB card readers).
|
||||
|
||||
For more information, please [Contact Support](https://lime-technology.com/contact).
|
||||
:end
|
||||
</div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if ( ( !(strstr($var['regTy'], "invalid key")) and ((strstr($var['regTy'], "Trial"))) ) || (strstr($var['regTy'], "no connection")) || (strstr($var['regTy'], "withdrawn")) ):?>
|
||||
|
||||
_(***Trial*** key expires on)_:
|
||||
: <?=my_time_now($var['regTm2'])?>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if ( strstr($var['regTy'], "invalid installation") || ( (strstr($var['regTy'], "invalid key")) && (strstr($var['regTy'], "Trial")) )):?>
|
||||
|
||||
_(Expiration)_:
|
||||
: <?=my_time_now($var['regTm2'])?>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if ( (strstr($var['regTy'], "invalid installation")) || (strstr($var['regTy'], "invalid key")) || ($var['regTy']=="Basic") || ($var['regTy']=="Plus") || ($var['regTy']=="Pro") ):?>
|
||||
|
||||
_(Registered to)_:
|
||||
: <?=htmlspecialchars($var['regTo'])?>
|
||||
|
||||
_(Registered on)_:
|
||||
: <?=my_time_now($var['regTm'])?>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if ( (strstr($var['regTy'], "invalid installation")) or ( (strstr($var['regTy'], "invalid key")) and (!(strstr($var['regTy'], "Trial")))) ):?>
|
||||
|
||||
_(Registered GUID)_:
|
||||
: <?=$var['regGUID']?>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if (strstr($var['regTy'], "flash device error")):?>
|
||||
|
||||
<span class='thanks red'>_(Error accessing your physical USB Flash boot device)_</span>
|
||||
<div markdown="1" class="remark">
|
||||
_(There is a physical problem accessing your USB Flash boot device)_. _(Please)_ [Contact Support](https://lime-technology.com/contact).
|
||||
|
||||
_(Flash GUID)_:
|
||||
: _(Error code)_: <?=$var['regCheck']?>
|
||||
|
||||
<?else:?>
|
||||
|
||||
_(Flash GUID)_:
|
||||
: <?=$var['flashGUID']?>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
_(Flash Vendor)_:
|
||||
: <?=$var['flashVendor']?>
|
||||
|
||||
_(Flash Product)_:
|
||||
: <?=$var['flashProduct']?>
|
||||
|
||||
<?if ( ((strstr($var['regTy'], "invalid key")) and !(strstr($var['regTy'], "Trial"))) || ($var['regTy']=="Basic") || ($var['regTy']=="Plus") || ($var['regTy']=="Pro") ):?>
|
||||
|
||||
_(Replaceable)_:
|
||||
: <?=my_time_any($var['regTm2'])?>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
<?if ( !(strstr($var['regTy'], "flash device error")) || !(strstr($var['regTy'], "blacklisted")) ):?>
|
||||
|
||||
<div class="device"><?=sprintf(_("This server has %s attached storage device".($var['deviceCount']==1?'.':'s.')),$var['deviceCount'])?></div>
|
||||
|
||||
<?endif;?>
|
||||
|
||||
|
||||
: <unraid-i18n-host><unraid-key-actions></unraid-key-actions></unraid-i18n-host>
|
||||
<unraid-i18n-host>
|
||||
<unraid-registration></unraid-registration>
|
||||
</unraid-i18n-host>
|
||||
|
@@ -1,5 +1,14 @@
|
||||
<?php
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
$var = (array)parse_ini_file('state/var.ini');
|
||||
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
@@ -7,6 +16,8 @@ require_once "$docroot/webGui/include/Helpers.php";
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/state.php";
|
||||
|
||||
$serverState = new ServerState();
|
||||
|
||||
header('Content-type: application/json');
|
||||
|
||||
echo json_encode($serverState);
|
||||
echo $serverState->getServerStateJson();
|
||||
|
@@ -1,3 +1,14 @@
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<style>
|
||||
#header {
|
||||
z-index: 102 !important;
|
||||
@@ -16,6 +27,15 @@
|
||||
margin-left: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tools page, rotate the Downgrade icon to prevent needing to add a new icon to the icon font.
|
||||
* The pseudo element is targeted here otherwise the rotation of the span would mess up spacing with the text.
|
||||
*/
|
||||
a[href="/Tools/Downgrade"] .icon-update:before {
|
||||
display: inline-block; /* required otherwise the rotation won't work */
|
||||
rotate: 180deg;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
// Set the path for the local manifest file
|
||||
@@ -39,4 +59,4 @@ if ($fileValue !== null) {
|
||||
echo '<script src="' . $prefixedPath . $fileValue . '"></script>';
|
||||
} else {
|
||||
echo '<script>console.error("%cNo matching key containing \'' . $searchText . '\' found.", "font-weight: bold; color: white; background-color: red");</script>';
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,22 @@
|
||||
<?php
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once("$docroot/plugins/dynamix.my.servers/include/state.php");
|
||||
require_once("$docroot/plugins/dynamix.my.servers/include/translations.php");
|
||||
|
||||
$serverState = new ServerState();
|
||||
$wCTranslations = new WebComponentTranslations();
|
||||
?>
|
||||
<script>
|
||||
window.LOCALE_DATA = '<?= rawurlencode(json_encode($webComponentTranslations, JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE)) ?>';
|
||||
window.LOCALE_DATA = '<?= $wCTranslations->getTranslationsJson(true) ?>';
|
||||
/**
|
||||
* So we're not needing to modify DefaultLayout with an additional include, we'll add the Modals web component to the bottom of the body.
|
||||
*/
|
||||
@@ -18,8 +30,7 @@ if (!document.getElementsByTagName(modalsWebComponent).length) {
|
||||
$i18nHost.appendChild($modals);
|
||||
}
|
||||
</script>
|
||||
<?
|
||||
echo "
|
||||
|
||||
<unraid-i18n-host>
|
||||
<unraid-user-profile server='" . json_encode($serverState) . "'></unraid-user-profile>
|
||||
</unraid-i18n-host>";
|
||||
<unraid-user-profile server="<?= $serverState->getServerStateJsonForHtmlAttr() ?>"></unraid-user-profile>
|
||||
</unraid-i18n-host>
|
||||
|
168
emhttp/plugins/dynamix.my.servers/include/reboot-details.php
Normal file
168
emhttp/plugins/dynamix.my.servers/include/reboot-details.php
Normal file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
/**
|
||||
* RebootDetails class is responsible for detecting the type and version of a system reboot required in the context of an unRAID server.
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* $rebootDetails = new RebootDetails();
|
||||
* $rebootType = $rebootDetails->rebootType;
|
||||
* ```
|
||||
*/
|
||||
class RebootDetails
|
||||
{
|
||||
const CURRENT_CHANGES_TXT_PATH = '/boot/changes.txt';
|
||||
const CURRENT_README_RELATIVE_PATH = 'plugins/unRAIDServer/README.md';
|
||||
const CURRENT_VERSION_PATH = '/etc/unraid-version';
|
||||
const PREVIOUS_BZ_ROOT_PATH = '/boot/previous/bzroot';
|
||||
const PREVIOUS_CHANGES_TXT_PATH = '/boot/previous/changes.txt';
|
||||
|
||||
private $currentVersion = '';
|
||||
|
||||
public $rebootType = ''; // 'update', 'downgrade', 'thirdPartyDriversDownloading'
|
||||
public $rebootReleaseDate = '';
|
||||
public $rebootVersion = '';
|
||||
|
||||
public $previousReleaseDate = '';
|
||||
public $previousVersion = '';
|
||||
|
||||
/**
|
||||
* Constructs a new RebootDetails object and automatically detects the reboot type during initialization.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->detectRebootType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the type of reboot required based on the contents of the unRAID server's README.md file.
|
||||
* Sets the $rebootType property accordingly.
|
||||
*/
|
||||
private function detectRebootType()
|
||||
{
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
|
||||
/**
|
||||
* Read the reboot readme, and see if it says "REBOOT REQUIRED" or "DOWNGRADE"
|
||||
* only relying on the README.md file to save reads from the flash drive.
|
||||
* because we started allowing downgrades from the account.unraid.net Update OS page, we can't
|
||||
* fully rely on the README.md value of being accurate.
|
||||
* For instance if on 6.13.0-beta.2.1 then chose to "Downgrade" to 6.13.0-beta.1.10 from the account app
|
||||
* the README.md file would still say "REBOOT REQUIRED".
|
||||
*/
|
||||
$rebootReadme = @file_get_contents("$docroot/" . self::CURRENT_README_RELATIVE_PATH, false, null, 0, 20) ?: '';
|
||||
$rebootDetected = preg_match("/^\*\*(REBOOT REQUIRED|DOWNGRADE)/", $rebootReadme);
|
||||
if (!$rebootDetected) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* if a reboot is required, then:
|
||||
* get current Unraid version from /etc/unraid-version
|
||||
* then get the version of the last update from self::CURRENT_CHANGES_TXT_PATH
|
||||
* if they're different, then a reboot is required
|
||||
* if the version in self::CURRENT_CHANGES_TXT_PATH is less than the current version, then a downgrade is required
|
||||
* if the version in self::CURRENT_CHANGES_TXT_PATH is greater than the current version, then an update is required
|
||||
*/
|
||||
$this->setCurrentVersion();
|
||||
$this->setRebootDetails();
|
||||
if ($this->currentVersion == '' || $this->rebootVersion == '') {
|
||||
return; // return to prevent potential incorrect outcome
|
||||
}
|
||||
|
||||
$compareVersions = version_compare($this->rebootVersion, $this->currentVersion);
|
||||
switch ($compareVersions) {
|
||||
case -1:
|
||||
$this->setRebootType('downgrade');
|
||||
break;
|
||||
case 0:
|
||||
// we should never get here, but if we do, then no reboot is required and just return
|
||||
return;
|
||||
case 1:
|
||||
$this->setRebootType('update');
|
||||
break;
|
||||
}
|
||||
|
||||
// Detect if third-party drivers were part of the update process
|
||||
$processWaitingThirdPartyDrivers = "inotifywait -q " . self::CURRENT_CHANGES_TXT_PATH . " -e move_self,delete_self";
|
||||
// Run the ps command to list processes and check if the process is running
|
||||
$ps_command = "ps aux | grep -E \"$processWaitingThirdPartyDrivers\" | grep -v \"grep -E\"";
|
||||
$output = shell_exec($ps_command) ?? '';
|
||||
if ($this->rebootType != '' && strpos($output, $processWaitingThirdPartyDrivers) !== false) {
|
||||
$this->setRebootType('thirdPartyDriversDownloading');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects and retrieves the version information related to the system reboot based on the contents of the '/boot/changes.txt' file.
|
||||
*
|
||||
* @return string The system version information or 'Not found' if not found, or 'File not found' if the file is not present.
|
||||
*/
|
||||
private function readChangesTxt(string $file_path = self::CURRENT_CHANGES_TXT_PATH)
|
||||
{
|
||||
// Check if the file exists
|
||||
if (file_exists($file_path)) {
|
||||
exec("head -n4 $file_path", $rows);
|
||||
foreach ($rows as $row) {
|
||||
$i = stripos($row,'version');
|
||||
if ($i !== false) {
|
||||
[$version, $releaseDate] = explode(' ', trim(substr($row, $i+7)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'releaseDate' => $releaseDate ?? 'Not found',
|
||||
'version' => $version ?? 'Not found',
|
||||
];
|
||||
} else {
|
||||
return 'File not found';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current version of the Unraid server for comparison with the reboot version.
|
||||
*/
|
||||
private function setCurrentVersion() {
|
||||
// output ex: version="6.13.0-beta.2.1"
|
||||
$raw = @file_get_contents(self::CURRENT_VERSION_PATH) ?: '';
|
||||
// Regular expression to match the version between the quotes
|
||||
$pattern = '/version="([^"]+)"/';
|
||||
if (preg_match($pattern, $raw, $matches)) {
|
||||
$this->currentVersion = $matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
private function setRebootDetails()
|
||||
{
|
||||
$rebootDetails = $this->readChangesTxt();
|
||||
$this->rebootReleaseDate = $rebootDetails['releaseDate'];
|
||||
$this->rebootVersion = $rebootDetails['version'];
|
||||
}
|
||||
|
||||
private function setRebootType($rebootType)
|
||||
{
|
||||
$this->rebootType = $rebootType;
|
||||
}
|
||||
|
||||
/**
|
||||
* If self::PREVIOUS_BZ_ROOT_PATH exists, then the user has the option to downgrade to the previous version.
|
||||
* Parse the text file /boot/previous/changes.txt to get the version number of the previous version.
|
||||
* Then we move some files around and reboot.
|
||||
*/
|
||||
public function setPrevious()
|
||||
{
|
||||
if (@file_exists(self::PREVIOUS_BZ_ROOT_PATH) && @file_exists(self::PREVIOUS_CHANGES_TXT_PATH)) {
|
||||
$parseOutput = $this->readChangesTxt(self::PREVIOUS_CHANGES_TXT_PATH);
|
||||
$this->previousVersion = $parseOutput['version'];
|
||||
$this->previousReleaseDate = $parseOutput['releaseDate'];
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,81 +1,342 @@
|
||||
<?php
|
||||
// read flashbackup ini file
|
||||
$flashbackup_ini = '/var/local/emhttp/flashbackup.ini';
|
||||
$flashbackup_status = (file_exists($flashbackup_ini)) ? @parse_ini_file($flashbackup_ini) : [];
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
/**
|
||||
* @todo refactor globals – currently if you try to use $GLOBALS the class will break.
|
||||
*/
|
||||
$webguiGlobals = $GLOBALS;
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$nginx = parse_ini_file('/var/local/emhttp/nginx.ini');
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
|
||||
/**
|
||||
* ServerState class encapsulates server-related information and settings.
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* require_once "$docroot/plugins/dynamix.my.servers/include/state.php";
|
||||
* $serverStateClass = new ServerState();
|
||||
*
|
||||
* $serverStateClass->getServerState();
|
||||
* or
|
||||
* $serverStateClass->getServerStateJson();
|
||||
* ```
|
||||
*/
|
||||
class ServerState
|
||||
{
|
||||
protected $webguiGlobals;
|
||||
|
||||
// base OS only, plugin not installed • show ad for plugin
|
||||
$connectPluginInstalled = '';
|
||||
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net')) $connectPluginInstalled = 'dynamix.unraid.net.plg';
|
||||
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net.staging')) $connectPluginInstalled = 'dynamix.unraid.net.staging.plg';
|
||||
// plugin install failed if the unraid-api file doesn't fully install • append failure detected so we can show warning about failed install via UPC
|
||||
if ($connectPluginInstalled && !file_exists('/usr/local/sbin/unraid-api')) $connectPluginInstalled .= '_installFailed';
|
||||
private $var;
|
||||
private $apiKey = '';
|
||||
private $apiVersion = '';
|
||||
private $avatar = '';
|
||||
private $email = '';
|
||||
private $extraOrigins = [];
|
||||
private $flashBackupActivated = '';
|
||||
private $hasRemoteApikey = false;
|
||||
private $registeredTime = '';
|
||||
private $username = '';
|
||||
private $connectPluginInstalled = '';
|
||||
private $connectPluginVersion;
|
||||
private $configErrorEnum = [
|
||||
"error" => 'UNKNOWN_ERROR',
|
||||
"ineligible" => 'INELIGIBLE',
|
||||
"invalid" => 'INVALID',
|
||||
"nokeyserver" => 'NO_KEY_SERVER',
|
||||
"withdrawn" => 'WITHDRAWN',
|
||||
];
|
||||
private $osVersion;
|
||||
private $osVersionBranch;
|
||||
private $rebootDetails;
|
||||
private $caseModel = '';
|
||||
private $keyfileBase64UrlSafe = '';
|
||||
private $updateOsCheck;
|
||||
private $updateOsNotificationsEnabled = false;
|
||||
private $updateOsResponse;
|
||||
private $updateOsIgnoredReleases = [];
|
||||
|
||||
$connectPluginVersion = file_exists('/var/log/plugins/dynamix.unraid.net.plg')
|
||||
? trim(@exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.plg 2>/dev/null'))
|
||||
: (file_exists('/var/log/plugins/dynamix.unraid.net.staging.plg')
|
||||
? trim(@exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.staging.plg 2>/dev/null'))
|
||||
: 'base-' . $var['version']);
|
||||
public $myServersFlashCfg = [];
|
||||
public $myServersMemoryCfg = [];
|
||||
public $host = 'unknown';
|
||||
public $combinedKnownOrigins = [];
|
||||
|
||||
public $nginxCfg = [];
|
||||
public $flashbackupStatus = [];
|
||||
public $registered = false;
|
||||
public $myServersMiniGraphConnected = false;
|
||||
public $keyfileBase64 = '';
|
||||
|
||||
$myservers_flash_cfg_path='/boot/config/plugins/dynamix.my.servers/myservers.cfg';
|
||||
$myservers = file_exists($myservers_flash_cfg_path) ? @parse_ini_file($myservers_flash_cfg_path,true) : [];
|
||||
/**
|
||||
* Constructor to initialize class properties and gather server information.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
/**
|
||||
* @note – necessary evil until full webgui is class based.
|
||||
* @see - getWebguiGlobal() for usage
|
||||
* */
|
||||
global $webguiGlobals;
|
||||
$this->webguiGlobals =& $webguiGlobals;
|
||||
// echo "<pre>" . json_encode($this->webguiGlobals, JSON_PRETTY_PRINT) . "</pre>";
|
||||
|
||||
$configErrorEnum = [
|
||||
"error" => 'UNKNOWN_ERROR',
|
||||
"invalid" => 'INVALID',
|
||||
"nokeyserver" => 'NO_KEY_SERVER',
|
||||
"withdrawn" => 'WITHDRAWN',
|
||||
];
|
||||
$this->var = (array)parse_ini_file('state/var.ini');
|
||||
$this->nginxCfg = @parse_ini_file('/var/local/emhttp/nginx.ini') ?? [];
|
||||
|
||||
$registered = !empty($myservers['remote']['username']) && $connectPluginInstalled;
|
||||
$this->osVersion = $this->var['version'];
|
||||
$this->osVersionBranch = trim(@exec('plugin category /var/log/plugins/unRAIDServer.plg') ?? 'stable');
|
||||
|
||||
$serverState = [
|
||||
"apiKey" => $myservers['upc']['apikey'] ?? '',
|
||||
"apiVersion" => $myservers['api']['version'] ?? '',
|
||||
"avatar" => (!empty($myservers['remote']['avatar']) && $connectPluginInstalled) ? $myservers['remote']['avatar'] : '',
|
||||
"config" => [
|
||||
'valid' => ($var['configValid'] === 'yes'),
|
||||
'error' => isset($configErrorEnum[$var['configValid']]) ? $configErrorEnum[$var['configValid']] : 'UNKNOWN_ERROR',
|
||||
],
|
||||
"connectPluginInstalled" => $connectPluginInstalled,
|
||||
"connectPluginVersion" => $connectPluginVersion,
|
||||
"csrf" => $var['csrf_token'],
|
||||
"description" => $var['COMMENT'] ? htmlspecialchars($var['COMMENT']) : '',
|
||||
"deviceCount" => $var['deviceCount'],
|
||||
"email" => $myservers['remote']['email'] ?? '',
|
||||
"expireTime" => 1000 * (($var['regTy'] === 'Trial' || strstr($var['regTy'], 'expired')) ? $var['regTm2'] : 0),
|
||||
"extraOrigins" => explode(',', $myservers['api']['extraOrigins'] ?? ''),
|
||||
"flashProduct" => $var['flashProduct'],
|
||||
"flashVendor" => $var['flashVendor'],
|
||||
"flashBackupActivated" => empty($flashbackup_status['activated']) ? '' : 'true',
|
||||
"guid" => $var['flashGUID'],
|
||||
"hasRemoteApikey" => !empty($myservers['remote']['apikey']),
|
||||
"internalPort" => $_SERVER['SERVER_PORT'],
|
||||
"keyfile" => empty($var['regFILE']) ? '' : str_replace(['+', '/', '='], ['-', '_', ''], trim(base64_encode(@file_get_contents($var['regFILE'])))),
|
||||
"lanIp" => ipaddr(),
|
||||
"locale" => ($_SESSION['locale']) ? $_SESSION['locale'] : 'en_US',
|
||||
"model" => $var['SYS_MODEL'],
|
||||
"name" => htmlspecialchars($var['NAME']),
|
||||
"osVersion" => $var['version'],
|
||||
"protocol" => $_SERVER['REQUEST_SCHEME'],
|
||||
"regGen" => (int)$var['regGen'],
|
||||
"regGuid" => $var['regGUID'],
|
||||
"registered" => $registered,
|
||||
"registeredTime" => $myservers['remote']['regWizTime'] ?? '',
|
||||
"site" => $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'],
|
||||
"state" => strtoupper(empty($var['regCheck']) ? $var['regTy'] : $var['regCheck']),
|
||||
"theme" => [
|
||||
"banner" => !empty($display['banner']),
|
||||
"bannerGradient" => $display['showBannerGradient'] === 'yes' ?? false,
|
||||
"bgColor" => ($display['background']) ? '#' . $display['background'] : '',
|
||||
"descriptionShow" => (!empty($display['headerdescription']) && $display['headerdescription'] !== 'no'),
|
||||
"metaColor" => ($display['headermetacolor'] ?? '') ? '#' . $display['headermetacolor'] : '',
|
||||
"name" => $display['theme'],
|
||||
"textColor" => ($display['header']) ? '#' . $display['header'] : '',
|
||||
],
|
||||
"ts" => time(),
|
||||
"uptime" => 1000 * (time() - round(strtok(exec("cat /proc/uptime"), ' '))),
|
||||
"username" => $myservers['remote']['username'] ?? '',
|
||||
"wanFQDN" => $nginx['NGINX_WANFQDN'] ?? '',
|
||||
];
|
||||
$caseModelFile = '/boot/config/plugins/dynamix/case-model.cfg';
|
||||
$this->caseModel = file_exists($caseModelFile) ? htmlspecialchars(@file_get_contents($caseModelFile), ENT_HTML5, 'UTF-8') : '';
|
||||
|
||||
$this->rebootDetails = new RebootDetails();
|
||||
|
||||
$this->keyfileBase64 = empty($this->var['regFILE']) ? null : @file_get_contents($this->var['regFILE']);
|
||||
if ($this->keyfileBase64 !== false) {
|
||||
$this->keyfileBase64 = @base64_encode($this->keyfileBase64);
|
||||
$this->keyfileBase64UrlSafe = str_replace(['+', '/', '='], ['-', '_', ''], trim($this->keyfileBase64));
|
||||
}
|
||||
|
||||
$this->updateOsCheck = new UnraidOsCheck();
|
||||
$this->updateOsIgnoredReleases = $this->updateOsCheck->getIgnoredReleases();
|
||||
$this->updateOsNotificationsEnabled = !empty(@$this->getWebguiGlobal('notify', 'unraidos'));
|
||||
$this->updateOsResponse = $this->updateOsCheck->getUnraidOSCheckResult();
|
||||
|
||||
$this->setConnectValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value of a webgui global setting.
|
||||
*/
|
||||
public function getWebguiGlobal(string $key, string $subkey = null) {
|
||||
if (!$subkey) {
|
||||
return _var($this->webguiGlobals, $key, '');
|
||||
}
|
||||
$keyArray = _var($this->webguiGlobals, $key, []);
|
||||
return _var($keyArray, $subkey, '');
|
||||
}
|
||||
|
||||
private function setConnectValues() {
|
||||
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net')) {
|
||||
$this->connectPluginInstalled = 'dynamix.unraid.net.plg';
|
||||
}
|
||||
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net.staging')) {
|
||||
$this->connectPluginInstalled = 'dynamix.unraid.net.staging.plg';
|
||||
}
|
||||
if ($this->connectPluginInstalled && !file_exists('/usr/local/sbin/unraid-api')) {
|
||||
$this->connectPluginInstalled .= '_installFailed';
|
||||
}
|
||||
|
||||
// exit early if the plugin is not installed
|
||||
if (!$this->connectPluginInstalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->connectPluginVersion = file_exists('/var/log/plugins/dynamix.unraid.net.plg')
|
||||
? trim(@exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.plg 2>/dev/null'))
|
||||
: (file_exists('/var/log/plugins/dynamix.unraid.net.staging.plg')
|
||||
? trim(@exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.staging.plg 2>/dev/null'))
|
||||
: 'base-' . $this->var['version']);
|
||||
|
||||
$this->getMyServersCfgValues();
|
||||
$this->getConnectKnownOrigins();
|
||||
$this->getFlashBackupStatus();
|
||||
}
|
||||
|
||||
private function getFlashBackupStatus() {
|
||||
$flashbackupCfg = '/var/local/emhttp/flashbackup.ini';
|
||||
$this->flashbackupStatus = (file_exists($flashbackupCfg)) ? @parse_ini_file($flashbackupCfg) : [];
|
||||
$this->flashBackupActivated = empty($this->flashbackupStatus['activated']) ? '' : 'true';
|
||||
}
|
||||
|
||||
private function getMyServersCfgValues() {
|
||||
/**
|
||||
* @todo can we read this from somewhere other than the flash? Connect page uses this path and /boot/config/plugins/dynamix.my.servers/myservers.cfg…
|
||||
* - $myservers_memory_cfg_path ='/var/local/emhttp/myservers.cfg';
|
||||
* - $mystatus = (file_exists($myservers_memory_cfg_path)) ? @parse_ini_file($myservers_memory_cfg_path) : [];
|
||||
*/
|
||||
$flashCfgPath = '/boot/config/plugins/dynamix.my.servers/myservers.cfg';
|
||||
$this->myServersFlashCfg = file_exists($flashCfgPath) ? @parse_ini_file($flashCfgPath, true) : [];
|
||||
// ensure some vars are defined here so we don't have to test them later
|
||||
if (empty($this->myServersFlashCfg['remote']['apikey'])) {
|
||||
$this->myServersFlashCfg['remote']['apikey'] = "";
|
||||
}
|
||||
if (empty($this->myServersFlashCfg['remote']['wanaccess'])) {
|
||||
$this->myServersFlashCfg['remote']['wanaccess'] = "no";
|
||||
}
|
||||
if (empty($this->myServersFlashCfg['remote']['wanport'])) {
|
||||
$this->myServersFlashCfg['remote']['wanport'] = 33443;
|
||||
}
|
||||
if (empty($this->myServersFlashCfg['remote']['upnpEnabled'])) {
|
||||
$this->myServersFlashCfg['remote']['upnpEnabled'] = "no";
|
||||
}
|
||||
if (empty($this->myServersFlashCfg['remote']['dynamicRemoteAccessType'])) {
|
||||
$this->myServersFlashCfg['remote']['dynamicRemoteAccessType'] = "DISABLED";
|
||||
}
|
||||
|
||||
$this->apiKey = $this->myServersFlashCfg['upc']['apikey'] ?? '';
|
||||
$this->apiVersion = $this->myServersFlashCfg['api']['version'] ?? '';
|
||||
$this->avatar = (!empty($this->myServersFlashCfg['remote']['avatar']) && $this->connectPluginInstalled) ? $this->myServersFlashCfg['remote']['avatar'] : '';
|
||||
$this->email = $this->myServersFlashCfg['remote']['email'] ?? '';
|
||||
$this->hasRemoteApikey = !empty($this->myServersFlashCfg['remote']['apikey']);
|
||||
$this->registered = !empty($this->myServersFlashCfg['remote']['apikey']) && $this->connectPluginInstalled;
|
||||
$this->registeredTime = $this->myServersFlashCfg['remote']['regWizTime'] ?? '';
|
||||
$this->username = $this->myServersFlashCfg['remote']['username'] ?? '';
|
||||
}
|
||||
|
||||
private function getConnectKnownOrigins() {
|
||||
/**
|
||||
* Allowed origins warning displayed when the current webGUI URL is NOT included in the known lists of allowed origins.
|
||||
* Include localhost in the test, but only display HTTP(S) URLs that do not include localhost.
|
||||
*/
|
||||
$this->host = $_SERVER['HTTP_HOST'] ?? "unknown";
|
||||
$memoryCfgPath = '/var/local/emhttp/myservers.cfg';
|
||||
$this->myServersMemoryCfg = (file_exists($memoryCfgPath)) ? @parse_ini_file($memoryCfgPath) : [];
|
||||
$this->myServersMiniGraphConnected = (($this->myServersMemoryCfg['minigraph']??'') === 'CONNECTED');
|
||||
|
||||
$allowedOrigins = $this->myServersMemoryCfg['allowedOrigins'] ?? "";
|
||||
$extraOrigins = $this->myServersFlashCfg['api']['extraOrigins'] ?? "";
|
||||
$combinedOrigins = $allowedOrigins . "," . $extraOrigins; // combine the two strings for easier searching
|
||||
$combinedOrigins = str_replace(" ", "", $combinedOrigins); // replace any spaces with nothing
|
||||
$hostNotKnown = stripos($combinedOrigins, $this->host) === false; // check if the current host is in the combined list of origins
|
||||
|
||||
if ($extraOrigins) {
|
||||
$this->extraOrigins = explode(",", $extraOrigins);
|
||||
}
|
||||
|
||||
if ($hostNotKnown) {
|
||||
$this->combinedKnownOrigins = explode(",", $combinedOrigins);
|
||||
|
||||
if ($this->combinedKnownOrigins) {
|
||||
foreach($this->combinedKnownOrigins as $key => $origin) {
|
||||
if ( (strpos($origin, "http") === false) || (strpos($origin, "localhost") !== false) ) {
|
||||
// clean up $this->combinedKnownOrigins, only display warning if origins still remain to display
|
||||
unset($this->combinedKnownOrigins[$key]);
|
||||
}
|
||||
}
|
||||
// for some reason the unset creates an associative array, so reindex the array with just the values. Otherwise we get an object passed to the UPC JS instead of an array.
|
||||
if ($this->combinedKnownOrigins) {
|
||||
$this->combinedKnownOrigins = array_values($this->combinedKnownOrigins);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the server information as an associative array
|
||||
*
|
||||
* @return array An array containing server information.
|
||||
*/
|
||||
public function getServerState()
|
||||
{
|
||||
$serverState = [
|
||||
"array" => [
|
||||
"state" => @$this->getWebguiGlobal('var', 'fsState'),
|
||||
"progress" => @$this->getWebguiGlobal('var', 'fsProgress'),
|
||||
],
|
||||
"apiKey" => $this->apiKey,
|
||||
"apiVersion" => $this->apiVersion,
|
||||
"avatar" => $this->avatar,
|
||||
"caseModel" => $this->caseModel,
|
||||
"config" => [
|
||||
'valid' => ($this->var['configValid'] === 'yes'),
|
||||
'error' => isset($this->configErrorEnum[$this->var['configValid']]) ? $this->configErrorEnum[$this->var['configValid']] : null,
|
||||
],
|
||||
"connectPluginInstalled" => $this->connectPluginInstalled,
|
||||
"connectPluginVersion" => $this->connectPluginVersion,
|
||||
"csrf" => $this->var['csrf_token'],
|
||||
"dateTimeFormat" => [
|
||||
"date" => @$this->getWebguiGlobal('display', 'date') ?? '',
|
||||
"time" => @$this->getWebguiGlobal('display', 'time') ?? '',
|
||||
],
|
||||
"description" => $this->var['COMMENT'] ? htmlspecialchars($this->var['COMMENT'], ENT_HTML5, 'UTF-8') : '',
|
||||
"deviceCount" => $this->var['deviceCount'],
|
||||
"email" => $this->email,
|
||||
"expireTime" => 1000 * (($this->var['regTy'] === 'Trial' || strstr($this->var['regTy'], 'expired')) ? $this->var['regTm2'] : 0),
|
||||
"extraOrigins" => $this->extraOrigins,
|
||||
"flashProduct" => $this->var['flashProduct'],
|
||||
"flashVendor" => $this->var['flashVendor'],
|
||||
"flashBackupActivated" => $this->flashBackupActivated,
|
||||
"guid" => $this->var['flashGUID'],
|
||||
"hasRemoteApikey" => $this->hasRemoteApikey,
|
||||
"internalPort" => _var($_SERVER, 'SERVER_PORT'),
|
||||
"keyfile" => $this->keyfileBase64UrlSafe,
|
||||
"lanIp" => ipaddr(),
|
||||
"locale" => (!empty($_SESSION) && $_SESSION['locale']) ? $_SESSION['locale'] : 'en_US',
|
||||
"model" => $this->var['SYS_MODEL'] ? htmlspecialchars($this->var['SYS_MODEL'], ENT_HTML5, 'UTF-8') : '',
|
||||
"name" => htmlspecialchars($this->var['NAME'], ENT_HTML5, 'UTF-8'),
|
||||
"osVersion" => $this->osVersion,
|
||||
"osVersionBranch" => $this->osVersionBranch,
|
||||
"protocol" => _var($_SERVER, 'REQUEST_SCHEME'),
|
||||
"rebootType" => $this->rebootDetails->rebootType,
|
||||
"rebootVersion" => $this->rebootDetails->rebootVersion,
|
||||
"regDevs" => @(int)$this->var['regDevs'] ?? 0,
|
||||
"regGen" => @(int)$this->var['regGen'],
|
||||
"regGuid" => @$this->var['regGUID'] ?? '',
|
||||
"regTo" => @htmlspecialchars($this->var['regTo'], ENT_HTML5, 'UTF-8') ?? '',
|
||||
"regTm" => $this->var['regTm'] ? @$this->var['regTm'] * 1000 : '', // JS expects milliseconds
|
||||
"regTy" => @$this->var['regTy'] ?? '',
|
||||
"regExp" => $this->var['regExp'] ? @$this->var['regExp'] * 1000 : '', // JS expects milliseconds
|
||||
"registered" => $this->registered,
|
||||
"registeredTime" => $this->registeredTime,
|
||||
"site" => _var($_SERVER, 'REQUEST_SCHEME') . "://" . _var($_SERVER, 'HTTP_HOST'),
|
||||
"state" => strtoupper(empty($this->var['regCheck']) ? $this->var['regTy'] : $this->var['regCheck']),
|
||||
"theme" => [
|
||||
"banner" => !empty($this->getWebguiGlobal('display', 'banner')),
|
||||
"bannerGradient" => $this->getWebguiGlobal('display', 'showBannerGradient') === 'yes' ?? false,
|
||||
"bgColor" => ($this->getWebguiGlobal('display', 'background')) ? '#' . $this->getWebguiGlobal('display', 'background') : '',
|
||||
"descriptionShow" => (!empty($this->getWebguiGlobal('display', 'headerdescription')) && $this->getWebguiGlobal('display', 'headerdescription') !== 'no'),
|
||||
"metaColor" => ($this->getWebguiGlobal('display', 'headermetacolor') ?? '') ? '#' . $this->getWebguiGlobal('display', 'headermetacolor') : '',
|
||||
"name" => $this->getWebguiGlobal('display', 'theme'),
|
||||
"textColor" => ($this->getWebguiGlobal('display', 'header')) ? '#' . $this->getWebguiGlobal('display', 'header') : '',
|
||||
],
|
||||
"ts" => time(),
|
||||
"uptime" => 1000 * (time() - round(strtok(exec("cat /proc/uptime"), ' '))),
|
||||
"username" => $this->username,
|
||||
"wanFQDN" => @$this->nginxCfg['NGINX_WANFQDN'] ?? '',
|
||||
];
|
||||
|
||||
if ($this->combinedKnownOrigins) {
|
||||
$serverState['combinedKnownOrigins'] = $this->combinedKnownOrigins;
|
||||
}
|
||||
|
||||
if ($this->updateOsIgnoredReleases) {
|
||||
$serverState['updateOsIgnoredReleases'] = $this->updateOsIgnoredReleases;
|
||||
}
|
||||
|
||||
if ($this->updateOsNotificationsEnabled) {
|
||||
$serverState['updateOsNotificationsEnabled'] = $this->updateOsNotificationsEnabled;
|
||||
}
|
||||
|
||||
if ($this->updateOsResponse) {
|
||||
$serverState['updateOsResponse'] = $this->updateOsResponse;
|
||||
}
|
||||
|
||||
return $serverState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the server information as JSON
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getServerStateJson() {
|
||||
return json_encode($this->getServerState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the server information as JSON string with converted special characters to HTML entities
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getServerStateJsonForHtmlAttr() {
|
||||
$json = json_encode($this->getServerState());
|
||||
return htmlspecialchars($json, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
}
|
@@ -1,210 +1,410 @@
|
||||
<?php
|
||||
$webComponentTranslations = [
|
||||
($_SESSION['locale']) ? $_SESSION['locale'] : 'en_US' => [
|
||||
'LAN IP' => _('LAN IP'),
|
||||
'LAN IP {0}' => sprintf(_('LAN IP %s'), '{0}'),
|
||||
'LAN IP Copied' => _('LAN IP Copied'),
|
||||
'Click to Copy LAN IP {0}' => sprintf(_('Click to copy LAN IP %s'), '{0}'),
|
||||
'Trial Key Expired at {0}' => sprintf(_('Trial Key Expired at %s'), '{0}'),
|
||||
'Trial Key Expires at {0}' => sprintf(_('Trial Key Expires at %s'), '{0}'),
|
||||
'Trial Key Expired {0}' => sprintf(_('Trial Key Expired %s'), '{0}'),
|
||||
'Trial Key Expires in {0}' => sprintf(_('Trial Key Expires in %s'), '{0}'),
|
||||
'Server Up Since {0}' => sprintf(_('Server Up Since %s'), '{0}'),
|
||||
'Uptime {0}' => sprintf(_('Uptime %s'), '{0}'),
|
||||
'year' => sprintf(_('%s year'), '{n}') . ' | ' . sprintf(_('%s years'), '{n}'),
|
||||
'month' => sprintf(_('%s month'), '{n}') . ' | ' . sprintf(_('%s months'), '{n}'),
|
||||
'day' => sprintf(_('%s day'), '{n}') . ' | ' . sprintf(_('%s days'), '{n}'),
|
||||
'hour' => sprintf(_('%s hour'), '{n}') . ' | ' . sprintf(_('%s hours'), '{n}'),
|
||||
'minute' => sprintf(_('%s minute'), '{n}') . ' | ' . sprintf(_('%s minutes'), '{n}'),
|
||||
'second' => sprintf(_('%s second'), '{n}') . ' | ' . sprintf(_('%s seconds'), '{n}'),
|
||||
'ago' => _('ago'),
|
||||
'Purchase' => _('Purchase'),
|
||||
'Upgrade' => _('Upgrade'),
|
||||
'Fix Error' => _('Fix Error'),
|
||||
'Get Started' => _('Get Started'),
|
||||
'Trial Expired, see options below' => _('Trial Expired, see options below'),
|
||||
'Learn more about the error' => _('Learn more about the error'),
|
||||
'Close Dropdown' => _('Close Dropdown'),
|
||||
'Open Dropdown' => _('Open Dropdown'),
|
||||
'Thank you for installing Connect!' => _('Thank you for installing Connect!'),
|
||||
'Sign In to your Unraid.net account to get started' => _('Sign In to your Unraid.net account to get started'),
|
||||
'Go to Connect' => _('Go to Connect'),
|
||||
'Opens Connect in new tab' => _('Opens Connect in new tab'),
|
||||
'Manage Unraid.net Account' => _('Manage Unraid.net Account'),
|
||||
'Manage Unraid.net Account in new tab' => _('Manage Unraid.net Account in new tab'),
|
||||
'Settings' => _('Settings'),
|
||||
'Go to Connect plugin settings' => _('Go to Connect plugin settings'),
|
||||
'Enhance your Unraid experience with Connect' => _('Enhance your Unraid experience with Connect'),
|
||||
'Beta' => _('Beta'),
|
||||
'Loading' => _('Loading'),
|
||||
'Restarting unraid-api…' => _('Restarting unraid-api…'),
|
||||
'unraid-api is offline' => _('unraid-api is offline'),
|
||||
'Introducing Unraid Connect' => _('Introducing Unraid Connect'),
|
||||
'Enhance your Unraid experience' => _('Enhance your Unraid experience'),
|
||||
'Connected' => _('Connected'),
|
||||
'Dynamic Remote Access' => _('Dynamic Remote Access'),
|
||||
'Toggle on/off server accessibility with dynamic remote access. Automatically turn on UPnP and open a random WAN port on your router at the click of a button and close off access in seconds.' => _('Toggle on/off server accessibility with dynamic remote access.') . ' ' . _('Automatically turn on UPnP and open a random WAN port on your router at the click of a button and close off access in seconds.'),
|
||||
'Manage Your Server Within Connect' => _('Manage Your Server Within Connect'),
|
||||
'Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI. Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window.' => _('Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI.') . ' ' . _('Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window.'),
|
||||
'Deep Linking' => _('Deep Linking'),
|
||||
'The Connect dashboard links to relevant sections of the webgui, allowing quick access to those settings and server sections.' => _('The Connect dashboard links to relevant sections of the webgui, allowing quick access to those settings and server sections.'),
|
||||
'Online Flash Backup' => _('Online Flash Backup'),
|
||||
'Never ever be left without a backup of your config. If you need to change flash drives, generate a backup from Connect and be up and running in minutes.' => _('Never ever be left without a backup of your config.') . ' ' . _('If you need to change flash drives, generate a backup from Connect and be up and running in minutes.'),
|
||||
'Real-time Monitoring' => _('Real-time Monitoring'),
|
||||
'Get an overview of your server\'s state, storage space, apps and VMs status, and more.' => _('Get an overview of your server\'s state, storage space, apps and VMs status, and more.'),
|
||||
'Customizable Dashboard Tiles' => _('Customizable Dashboard Tiles'),
|
||||
'Set custom server tiles how you like and automatically display your server\'s banner image on your Connect Dashboard.' => _('Set custom server tiles how you like and automatically display your server\'s banner image on your Connect Dashboard.'),
|
||||
'License Management' => _('License Management'),
|
||||
'Manage your license keys at any time via the My Keys section.' => _('Manage your license keys at any time via the My Keys section.'),
|
||||
'Plus more on the way' => _('Plus more on the way'),
|
||||
'All you need is an active internet connection, an Unraid.net account, and the Connect plugin. Get started by installing the plugin.' => _('All you need is an active internet connection, an Unraid.net account, and the Connect plugin.') . ' ' . _('Get started by installing the plugin.'),
|
||||
'Checkout the Connect Documentation' => _('Checkout the Connect Documentation'),
|
||||
'No thanks' => _('No thanks'),
|
||||
'Learn more' => _('Learn more'),
|
||||
'Install Connect' => _('Install Connect'),
|
||||
'Close Modal' => _('Close Modal'),
|
||||
'Close' => _('Close'),
|
||||
'Reload' => _('Reload'),
|
||||
'Unraid logo animating with a wave like effect' => _('Unraid logo animating with a wave like effect'),
|
||||
'Click to close modal' => _('Click to close modal'),
|
||||
'Error' => _('Error'),
|
||||
'Performing actions' => _('Performing actions'),
|
||||
'Success!' => _('Success!'),
|
||||
'Something went wrong' => _('Something went wrong'),
|
||||
'Please keep this window open while we perform some actions' => _('Please keep this window open while we perform some actions'),
|
||||
'You\'re one step closer to enhancing your Unraid experience' => _('You\'re one step closer to enhancing your Unraid experience'),
|
||||
'Thank you for purchasing an Unraid {0} Key!' => sprintf(_('Thank you for purchasing an Unraid %s Key!'), '{0}'),
|
||||
'Thank you for upgrading to an Unraid {0} Key!' => sprintf(_('Thank you for upgrading to an Unraid %s Key!'), '{0}'),
|
||||
'Your {0} Key has been replaced!' => sprintf(_('Your %s Key has been replaced!'), '{0}'),
|
||||
'Your Trial key has been extended!' => _('Your Trial key has been extended!'),
|
||||
'Copied' => _('Copied'),
|
||||
'Copy Key URL' => _('Copy Key URL'),
|
||||
'Copy your Key URL: {0}' => sprintf(_('Copy your Key URL: %s'), '{0}'),
|
||||
'Then go to Tools > Registration to manually install it' => _('Then go to Tools > Registration to manually install it'),
|
||||
'Enhance your experience with Unraid Connect' => _('Enhance your experience with Unraid Connect'),
|
||||
'Sign In to utilize Unraid Connect' => _('Sign In to utilize Unraid Connect'),
|
||||
'Configure Connect Features' => _('Configure Connect Features'),
|
||||
'The primary method of support for Unraid Connect is through our forums and Discord.' => _('The primary method of support for Unraid Connect is through our forums and Discord.'),
|
||||
'If you are asked to supply logs, please open a support request on our Contact Page and reply to the email message you receive with your logs attached.' => _('If you are asked to supply logs, please open a support request on our Contact Page and reply to the email message you receive with your logs attached.'),
|
||||
'The logs may contain sensitive information so do not post them publicly.' => _('The logs may contain sensitive information so do not post them publicly.'),
|
||||
'Download unraid-api Logs' => _('Download unraid-api Logs'),
|
||||
'Unraid Connect Forums' => _('Unraid Connect Forums'),
|
||||
'Unraid Discord' => _('Unraid Discord'),
|
||||
'Unraid Contact Page' => _('Unraid Contact Page'),
|
||||
'DNS issue, unable to resolve wanip4.unraid.net' => _('DNS issue, unable to resolve wanip4.unraid.net'),
|
||||
'Unable to fetch client WAN IPv4' => _('Unable to fetch client WAN IPv4'),
|
||||
'Checking WAN IPs…' => _('Checking WAN IPs…'),
|
||||
'Remark: your WAN IPv4 is {0}' => sprintf(_('Remark: your WAN IPv4 is %s'), '{0}'),
|
||||
'Remark: Unraid\'s WAN IPv4 {0} does not match your client\'s WAN IPv4 {1}.' => sprintf(_('Remark: Unraid\'s WAN IPv4 %1s does not match your client\'s WAN IPv4 %2s.'), '{0}', '{1}'),
|
||||
'This may indicate a complex network that will not work with this Remote Access solution.' => _('This may indicate a complex network that will not work with this Remote Access solution.'),
|
||||
'Ignore this message if you are currently connected via Remote Access or VPN.' => _('Ignore this message if you are currently connected via Remote Access or VPN.'),
|
||||
'Ready to update Connect account configuration' => _('Ready to update Connect account configuration'),
|
||||
'Signing in {0}…' => sprintf(_('Signing in %s…'), '{0}'),
|
||||
'Signing out {0}…' => sprintf(_('Signing out %s…'), '{0}'),
|
||||
'{0} Signed In Successfully' => sprintf(_('%s Signed In Successfully'), '{0}'),
|
||||
'{0} Signed Out Successfully' => sprintf(_('%s Signed Out Successfully'), '{0}'),
|
||||
'Sign In Failed' => _('Sign In Failed'),
|
||||
'Sign Out Failed' => _('Sign Out Failed'),
|
||||
'Failed to update Connect account configuration' => _('Failed to update Connect account configuration'),
|
||||
'Callback redirect type not present or incorrect' => _('Callback redirect type not present or incorrect'),
|
||||
'Failed to install key' => _('Failed to install key'),
|
||||
'Ready to Install Key' => _('Ready to Install Key'),
|
||||
'Installing Extended Trial' => _('Installing Extended Trial'),
|
||||
'Installing Recovered' => _('Installing Recovered'),
|
||||
'Installing Replaced' => _('Installing Replaced'),
|
||||
'{0} {1} Key…' => sprintf(_('%1s %2s Key…'), '{0}', '{1}'),
|
||||
'{1} Key {0} Successfully' => sprintf(_('%2s Key %1s Successfully'), '{0}', '{1}'),
|
||||
'Failed to {0} {1} Key' => sprintf(_('Failed to %1s %2s Key'), '{0}', '{1}'),
|
||||
'Purchase Key' => _('Purchase Key'),
|
||||
'Upgrade Key' => _('Upgrade Key'),
|
||||
'Recover Key' => _('Recover Key'),
|
||||
'Redeem Activation Code' => _('Redeem Activation Code'),
|
||||
'Replace Key' => _('Replace Key'),
|
||||
'Sign In with Unraid.net Account' => _('Sign In with Unraid.net Account'),
|
||||
'Sign Out of Unraid.net' => _('Sign Out of Unraid.net'),
|
||||
'Extend Trial' => _('Extend Trial'),
|
||||
'Start Free 30 Day Trial' => _('Start Free 30 Day Trial'),
|
||||
'Go to Management Access Now' => _('Go to Management Access Now'),
|
||||
'Contact Support' => _('Contact Support'),
|
||||
'Learn More' => _('Learn More'),
|
||||
'No Keyfile' => _('No Keyfile'),
|
||||
'Let\'s Unleash your Hardware!' => _('Let\'s Unleash your Hardware!'),
|
||||
'<p>Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key. A <em>Trial</em> key provides all the functionality of a Pro Registration key.</p><p>Registration keys are bound to your USB Flash boot device serial number (GUID). Please use a high quality name brand device at least 1GB in size.</p><p>Note: USB memory card readers are generally not supported because most do not present unique serial numbers.</p><p><strong>Important:</strong></p><ul class="list-disc pl-16px"><li>Please make sure your server time is accurate to within 5 minutes</li><li>Please make sure there is a DNS server specified</li></ul>' => '<p>' . _('Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key.') . ' ' . _('A <em>Trial</em> key provides all the functionality of a Pro Registration key.') . '</p><p>' . _('Registration keys are bound to your USB Flash boot device serial number (GUID).') . ' ' . _('Please use a high quality name brand device at least 1GB in size.') . '</p><p>' . _('Note: USB memory card readers are generally not supported because most do not present unique serial numbers.') . '</p><p>' . _('*Important:*') . '</p><ul class="list-disc pl-16px"><li>' . _('Please make sure your server time is accurate to within 5 minutes') . '</li><li>' . _('Please make sure there is a DNS server specified') . '</li>>' . '</ul>',
|
||||
'Trial' => _('Trial'),
|
||||
'Thank you for choosing Unraid OS!' => _('Thank you for choosing Unraid OS!'),
|
||||
'<p>Your <em>Trial</em> key includes all the functionality and device support of a <em>Pro</em> key.</p><p>After your <em>Trial</em> has reached expiration, your server <strong>still functions normally</strong> until the next time you Stop the array or reboot your server.</p><p>At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>' => '<p>' . _('Your **Trial** key includes all the functionality and device support of a **Pro** key') . '</p><p>' . _('After your **Trial** has reached expiration, your server *still functions normally* until the next time you Stop the array or reboot your server') . '</p><p>' . _('At that point you may either purchase a license key or request a *Trial* extension.') . '</p>',
|
||||
'Trial Expired' => _('Trial Expired'),
|
||||
'Your Trial has expired' => _('Your Trial has expired'),
|
||||
'<p>To continue using Unraid OS you may purchase a license key. Alternately, you may request a Trial extension.</p>' => '<p>' . _('To continue using Unraid OS you may purchase a license key.') . ' ' . _('Alternately, you may request a Trial extension.') . '</p>',
|
||||
'<p>You have used all your Trial extensions. To continue using Unraid OS you may purchase a license key.</p>' => '<p>' . _('You have used all your Trial extensions.') . ' ' . _('To continue using Unraid OS you may purchase a license key.') . '</p>',
|
||||
'Basic' => _('Basic'),
|
||||
'<p>Register for Connect by signing in to your Unraid.net account</p>' => '<p>' . _('Register for Connect by signing in to your Unraid.net account') . '</p>',
|
||||
'<p>To support more storage devices as your server grows, click Upgrade Key.</p>' => '<p>' . _('To support more storage devices as your server grows, click Upgrade Key.') . '</p>',
|
||||
'Plus' => _('Plus'),
|
||||
'Pro' => _('Pro'),
|
||||
'Flash GUID Error' => _('Flash GUID Error'),
|
||||
'Registration key / USB Flash GUID mismatch' => _('Registration key / USB Flash GUID mismatch'),
|
||||
'<p>Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.</p>' => '<p>' . _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.') . '</p>',
|
||||
'<p>The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key.</p><p>Your Unraid registration key is ineligible for replacement as it is blacklisted.</p>' => '<p>' . _('The license key file does not correspond to the USB Flash boot device.') . ' ' . _('Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key') . '</p><p>' . _('Your Unraid registration key is ineligible for replacement as it is blacklisted.') . '</p>',
|
||||
'<p>The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key.</p><p>Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.</p>' => '<p>' . _('The license key file does not correspond to the USB Flash boot device.') . ' ' . _('Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key') . '</p><p>' . _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.') . '</p>',
|
||||
'<p>The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /config directory on your USB Flash boot device.</p><p>You may also attempt to Purchase or Replace your key.</p>' => '<p>' . _('The license key file does not correspond to the USB Flash boot device.') . ' ' . _('Please copy the correct key file to the /config directory on your USB Flash boot device') . '</p><p>' . _('You may also attempt to Purchase or Replace your key.') . '</p>',
|
||||
'Multiple License Keys Present' => _('Multiple License Keys Present'),
|
||||
'<p>There are multiple license key files present on your USB flash device and none of them correspond to the USB Flash boot device. Please remove all key files, except the one you want to replace, from the /config directory on your USB Flash boot device.</p><p>Alternately you may purchase a license key for this USB flash device.</p><p>If you want to replace one of your license keys with a new key bound to this USB Flash device, please first remove all other key files first.</p>' => '<p>' . _('There are multiple license key files present on your USB flash device and none of them correspond to the USB Flash boot device.') . ' ' . _('Please remove all key files, except the one you want to replace, from the /config directory on your USB Flash boot device') . '</p><p>' . _('Alternately you may purchase a license key for this USB flash device') . '</p><p>' . _('If you want to replace one of your license keys with a new key bound to this USB Flash device, please first remove all other key files first.') . '</p>',
|
||||
'Missing key file' => _('Missing key file'),
|
||||
'<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>You may attempt to recover your key with your Unraid.net account.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>' => '<p>' . _('Your license key file is corrupted or missing.') . ' ' . _('The key file should be located in the /config directory on your USB Flash boot device') . '</p><p>' . _('If you do not have a backup copy of your license key file you may attempt to recover your key with your Unraid.net account') . '</p><p>' . _('If this was an expired Trial installation, you may purchase a license key.') . '</p>',
|
||||
'<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>If you do not have a backup copy of your license key file you may attempt to recover your key.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>' => '<p>' . _('Your license key file is corrupted or missing.') . ' ' . _('The key file should be located in the /config directory on your USB Flash boot device') . '</p><p>' . _('If you do not have a backup copy of your license key file you may attempt to recover your key with your Unraid.net account') . '</p><p>' . _('If this was an expired Trial installation, you may purchase a license key.') . '</p>',
|
||||
'Invalid installation' => _('Invalid installation'),
|
||||
'<p>It is not possible to use a Trial key with an existing Unraid OS installation.</p><p>You may purchase a license key corresponding to this USB Flash device to continue using this installation.</p>' => '<p>' . _('It is not possible to use a Trial key with an existing Unraid OS installation') . '</p><p>' . _('You may purchase a license key corresponding to this USB Flash device to continue using this installation.') . '</p>',
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
/**
|
||||
* Welcome to the Thunderdome. A place where you can get lost in a sea of translations.
|
||||
*
|
||||
* This file is used to generate the translations for the Vue3 based web components.
|
||||
*
|
||||
* These key value pairs are derived from web/locales/en_US.json.
|
||||
* We use the en_US.json file as the source of truth for the translations.
|
||||
* This file is then used to generate the translations for the web components and delivered to them via PHP as a JSON object in myservers2.php (my favorite file name).
|
||||
* The web components then use the translations to display the appropriate text to the user.
|
||||
*
|
||||
* Workflow is as follows:
|
||||
* 1. Create a new translation in en_US.json
|
||||
* 2. Create a new translation in this file
|
||||
* 3. Open unraid/lang-en_US and add the new translation to the appropriate file – typically translations.txt.
|
||||
* 3a. This is done so that the translation is available to the rest of the Unraid webgui.
|
||||
* 3b. Unfortunately there are numerous "special characters" that aren't allowed in Unraid's translation keys as they're automatically stripped out.
|
||||
* 3c. This means that we have to create a new translation key that is a "safe" version of the translation key used in the web components.
|
||||
* 3d. Special characters that are not allowed are: ? { } | & ~ ! [ ] ( ) / : * ^ . " '
|
||||
* 3e. There are likely more but I'm unable to find the documentation PDF - updated list of invalid characters above as mentioned in the language guide document.
|
||||
*
|
||||
* Usage example:
|
||||
* ```
|
||||
* $wCTranslations = new WebComponentTranslations();
|
||||
* $wCTranslations->getTranslations();
|
||||
* ```
|
||||
*/
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
'No USB flash configuration data' => _('No USB flash configuration data'),
|
||||
'<p>There is a problem with your USB Flash device</p>' => '<p>' . _('There is a problem with your USB Flash device') . '</p>',
|
||||
'No Flash' => _('No Flash'),
|
||||
'Cannot access your USB Flash boot device' => _('Cannot access your USB Flash boot device'),
|
||||
'<p>There is a physical problem accessing your USB Flash boot device</p>' => '<p>' . _('There is a physical problem accessing your USB Flash boot device') . '</p>',
|
||||
'BLACKLISTED' => _('BLACKLISTED'),
|
||||
'Blacklisted USB Flash GUID' => _('Blacklisted USB Flash GUID'),
|
||||
'<p>This USB Flash boot device has been blacklisted. This can occur as a result of transferring your license key to a replacement USB Flash device, and you are currently booted from your old USB Flash device.</p><p>A USB Flash device may also be blacklisted if we discover the serial number is not unique – this is common with USB card readers.</p>' => '<p>' . _('This USB Flash boot device has been blacklisted.') . ' ' . _('This can occur as a result of transferring your license key to a replacement USB Flash device, and you are currently booted from your old USB Flash device.') . '</p><p>' . _('A USB Flash device may also be blacklisted if we discover the serial number is not unique – this is common with USB card readers.') . '</p>',
|
||||
'USB Flash device error' => _('USB Flash device error'),
|
||||
'<p>This USB Flash device has an invalid GUID. Please try a different USB Flash device</p>' => '<p>' . _('This USB Flash device has an invalid GUID. Please try a different USB Flash device') . '</p>',
|
||||
'USB Flash has no serial number' => _('USB Flash has no serial number'),
|
||||
'Trial Requires Internet Connection' => _('Trial Requires Internet Connection'),
|
||||
'Cannot validate Unraid Trial key' => _('Cannot validate Unraid Trial key'),
|
||||
'<p>Your Trial key requires an internet connection.</p><p><a href="/Settings/NetworkSettings" class="underline">Please check Settings > Network</a></p>' => '<p>' . _('Your Trial key requires an internet connection') . '</p><p><a href="/Settings/NetworkSettings" class="underline">' . _('Please check Settings > Network') . '</a></p>',
|
||||
'Stale' => _('Stale'),
|
||||
'Stale Server' => _('Stale Server'),
|
||||
'<p>Please refresh the page to ensure you load your latest configuration</p>' => '<p>' . _('Please refresh the page to ensure you load your latest configuration') . '</p>',
|
||||
'Invalid API Key' => _('Invalid API Key'),
|
||||
'Please sign out then sign back in to refresh your API key.' => _('Please sign out then sign back in to refresh your API key.'),
|
||||
'Invalid API Key Format' => _('Invalid API Key Format'),
|
||||
'Too Many Devices' => _('Too Many Devices'),
|
||||
'You have exceeded the number of devices allowed for your license. Please remove a device before adding another.' => _('You have exceeded the number of devices allowed for your license. Please remove a device before adding another.'),
|
||||
'Unraid Connect Install Failed' => _('Unraid Connect Install Failed'),
|
||||
'Rebooting will likely solve this.' => _('Rebooting will likely solve this.'),
|
||||
'SSL certificates for unraid.net deprecated' => _('SSL certificates for unraid.net deprecated'),
|
||||
'On January 1st, 2023 SSL certificates for unraid.net were deprecated. You MUST provision a new SSL certificate to use our new myunraid.net domain. You can do this on the Settings > Management Access page.' => _('On January 1st, 2023 SSL certificates for unraid.net were deprecated. You MUST provision a new SSL certificate to use our new myunraid.net domain. You can do this on the Settings > Management Access page.'),
|
||||
'Unraid Connect Error' => _('Unraid Connect Error'),
|
||||
'Trial Key Creation Failed' => _('Trial Key Creation Failed'),
|
||||
'Error creatiing a trial key. Please try again later.' => _('Error creatiing a trial key. Please try again later.'),
|
||||
'Extending your free trial by 15 days' => _('Extending your free trial by 15 days'),
|
||||
'Please keep this window open' => _('Please keep this window open'),
|
||||
'Starting your free 30 day trial' => _('Starting your free 30 day trial'),
|
||||
'Trial Key Created' => _('Trial Key Created'),
|
||||
'Please wait while the page reloads to install your trial key' => _('Please wait while the page reloads to install your trial key'),
|
||||
'A Trial key provides all the functionality of a Pro Registration key' => _('A Trial key provides all the functionality of a Pro Registration key'),
|
||||
'Extension Installed' => _('Extension Installed'),
|
||||
'Recovered' => _('Recovered'),
|
||||
'Replaced' => _('Replaced'),
|
||||
'Installing' => _('Installing'),
|
||||
'Installed' => _('Installed'),
|
||||
'Install' => _('Install'),
|
||||
'Install Extended' => _('Install Extended'),
|
||||
'Install Recovered' => _('Install Recovered'),
|
||||
'Install Replaced' => _('Install Replaced'),
|
||||
'Your free Trial key provides all the functionality of a Pro Registration key' => _('Your free Trial key provides all the functionality of a Pro Registration key'),
|
||||
'Calculating trial expiration…' => _('Calculating trial expiration…'),
|
||||
'Signing In' => _('Signing In'),
|
||||
'Signing Out' => _('Signing Out'),
|
||||
'Sign In requires the local unraid-api to be running' => _('Sign In requires the local unraid-api to be running'),
|
||||
'Sign Out requires the local unraid-api to be running' => _('Sign Out requires the local unraid-api to be running')
|
||||
],
|
||||
];
|
||||
class WebComponentTranslations
|
||||
{
|
||||
private $translations = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->initializeTranslations();
|
||||
}
|
||||
|
||||
private function initializeTranslations()
|
||||
{
|
||||
$this->translations[$_SESSION['locale'] ?? 'en_US'] = [
|
||||
'{0} {1} Key…' => sprintf(_('%1s %2s Key…'), '{0}', '{1}'),
|
||||
'{0} devices' => sprintf(_('%s devices'), '{0}'),
|
||||
'{0} out of {1} allowed devices – upgrade your key to support more devices' => sprintf(_('%1s out of %2s allowed devices – upgrade your key to support more devices'), '{0}', '{1}'),
|
||||
'{0} out of {1} devices' => sprintf(_('%1s out of %2s devices'), '{0}', '{1}'),
|
||||
'{0} Release Notes' => sprintf(_('%s Release Notes'), '{0}'),
|
||||
'{0} Signed In Successfully' => sprintf(_('%s Signed In Successfully'), '{0}'),
|
||||
'{0} Signed Out Successfully' => sprintf(_('%s Signed Out Successfully'), '{0}'),
|
||||
'{0} Update Available' => sprintf(_('%s Update Available'), '{0}'),
|
||||
'{1} Key {0} Successfully' => sprintf(_('%2s Key %1s Successfully'), '{0}', '{1}'),
|
||||
'<p>It is not possible to use a Trial key with an existing Unraid OS installation.</p><p>You may purchase a license key corresponding to this USB Flash device to continue using this installation.</p>' => '<p>' . _('It is not possible to use a Trial key with an existing Unraid OS installation') . '</p><p>' . _('You may purchase a license key corresponding to this USB Flash device to continue using this installation.') . '</p>',
|
||||
'<p>Please refresh the page to ensure you load your latest configuration</p>' => '<p>' . _('Please refresh the page to ensure you load your latest configuration') . '</p>',
|
||||
'<p>Register for Connect by signing in to your Unraid.net account</p>' => '<p>' . _('Register for Connect by signing in to your Unraid.net account') . '</p>',
|
||||
'<p>The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key.</p><p>Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.</p>' => '<p>' . _('The license key file does not correspond to the USB Flash boot device.') . ' ' . _('Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key') . '</p><p>' . _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.') . '</p>',
|
||||
'<p>The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key.</p><p>Your Unraid registration key is ineligible for replacement as it is blacklisted.</p>' => '<p>' . _('The license key file does not correspond to the USB Flash boot device.') . ' ' . _('Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key') . '</p><p>' . _('Your Unraid registration key is ineligible for replacement as it is blacklisted.') . '</p>',
|
||||
'<p>The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /config directory on your USB Flash boot device.</p><p>You may also attempt to Purchase or Replace your key.</p>' => '<p>' . _('The license key file does not correspond to the USB Flash boot device.') . ' ' . _('Please copy the correct key file to the /config directory on your USB Flash boot device') . '</p><p>' . _('You may also attempt to Purchase or Replace your key.') . '</p>',
|
||||
'<p>There are multiple license key files present on your USB flash device and none of them correspond to the USB Flash boot device. Please remove all key files, except the one you want to replace, from the /config directory on your USB Flash boot device.</p><p>Alternately you may purchase a license key for this USB flash device.</p><p>If you want to replace one of your license keys with a new key bound to this USB Flash device, please first remove all other key files first.</p>' => '<p>' . _('There are multiple license key files present on your USB flash device and none of them correspond to the USB Flash boot device.') . ' ' . _('Please remove all key files, except the one you want to replace, from the /config directory on your USB Flash boot device') . '</p><p>' . _('Alternately you may purchase a license key for this USB flash device') . '</p><p>' . _('If you want to replace one of your license keys with a new key bound to this USB Flash device, please first remove all other key files first.') . '</p>',
|
||||
'<p>There is a physical problem accessing your USB Flash boot device</p>' => '<p>' . _('There is a physical problem accessing your USB Flash boot device') . '</p>',
|
||||
'<p>There is a problem with your USB Flash device</p>' => '<p>' . _('There is a problem with your USB Flash device') . '</p>',
|
||||
'<p>This USB Flash boot device has been blacklisted. This can occur as a result of transferring your license key to a replacement USB Flash device, and you are currently booted from your old USB Flash device.</p><p>A USB Flash device may also be blacklisted if we discover the serial number is not unique – this is common with USB card readers.</p>' => '<p>' . _('This USB Flash boot device has been blacklisted.') . ' ' . _('This can occur as a result of transferring your license key to a replacement USB Flash device, and you are currently booted from your old USB Flash device.') . '</p><p>' . _('A USB Flash device may also be blacklisted if we discover the serial number is not unique – this is common with USB card readers.') . '</p>',
|
||||
'<p>This USB Flash device has an invalid GUID. Please try a different USB Flash device</p>' => '<p>' . _('This USB Flash device has an invalid GUID. Please try a different USB Flash device') . '</p>',
|
||||
'<p>To continue using Unraid OS you may purchase a license key. Alternately, you may request a Trial extension.</p>' => '<p>' . _('To continue using Unraid OS you may purchase a license key.') . ' ' . _('Alternately, you may request a Trial extension.') . '</p>',
|
||||
'<p>To support more storage devices as your server grows, click Upgrade Key.</p>' => '<p>' . _('To support more storage devices as your server grows, click Upgrade Key.') . '</p>',
|
||||
'<p>You have used all your Trial extensions. To continue using Unraid OS you may purchase a license key.</p>' => '<p>' . _('You have used all your Trial extensions.') . ' ' . _('To continue using Unraid OS you may purchase a license key.') . '</p>',
|
||||
'<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>After your <em>Trial</em> has reached expiration, your server <strong>still functions normally</strong> until the next time you Stop the array or reboot your server.</p><p>At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>' => '<p>' . _('Your **Trial** key includes all the functionality and device support of an **Unleashed** key') . '</p><p>' . _('After your **Trial** has reached expiration, your server *still functions normally* until the next time you Stop the array or reboot your server') . '</p><p>' . _('At that point you may either purchase a license key or request a *Trial* extension.') . '</p>',
|
||||
'<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>If you do not have a backup copy of your license key file you may attempt to recover your key.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>' => '<p>' . _('Your license key file is corrupted or missing.') . ' ' . _('The key file should be located in the /config directory on your USB Flash boot device') . '</p><p>' . _('If you do not have a backup copy of your license key file you may attempt to recover your key with your Unraid.net account') . '</p><p>' . _('If this was an expired Trial installation, you may purchase a license key.') . '</p>',
|
||||
'<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>You may attempt to recover your key with your Unraid.net account.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>' => '<p>' . _('Your license key file is corrupted or missing.') . ' ' . _('The key file should be located in the /config directory on your USB Flash boot device') . '</p><p>' . _('If you do not have a backup copy of your license key file you may attempt to recover your key with your Unraid.net account') . '</p><p>' . _('If this was an expired Trial installation, you may purchase a license key.') . '</p>',
|
||||
'<p>Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key. A <em>Trial</em> key provides all the functionality of an Unleashed Registration key.</p><p>Registration keys are bound to your USB Flash boot device serial number (GUID). Please use a high quality name brand device at least 1GB in size.</p><p>Note: USB memory card readers are generally not supported because most do not present unique serial numbers.</p><p><strong>Important:</strong></p><ul class="list-disc pl-16px"><li>Please make sure your server time is accurate to within 5 minutes</li><li>Please make sure there is a DNS server specified</li></ul>' => '<p>' . _('Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key.') . ' ' . _('A <em>Trial</em> key provides all the functionality of an Unleashed Registration key.') . '</p><p>' . _('Registration keys are bound to your USB Flash boot device serial number (GUID).') . ' ' . _('Please use a high quality name brand device at least 1GB in size.') . '</p><p>' . _('Note: USB memory card readers are generally not supported because most do not present unique serial numbers.') . '</p><p>' . _('*Important:*') . '</p><ul class="list-disc pl-16px"><li>' . _('Please make sure your server time is accurate to within 5 minutes') . '</li><li>' . _('Please make sure there is a DNS server specified') . '</li>>' . '</ul>',
|
||||
'<p>Your Trial key requires an internet connection.</p><p><a href="/Settings/NetworkSettings" class="underline">Please check Settings > Network</a></p>' => '<p>' . _('Your Trial key requires an internet connection') . '</p><p><a href="/Settings/NetworkSettings" class="underline">' . _('Please check Settings > Network') . '</a></p>',
|
||||
'<p>Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.</p>' => '<p>' . _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.') . '</p>',
|
||||
'A Trial key provides all the functionality of an Unleashed Registration key' => _('A Trial key provides all the functionality of an Unleashed Registration key'),
|
||||
'Acklowledge that you have made a Flash Backup to enable this action' => _('Acklowledge that you have made a Flash Backup to enable this action'),
|
||||
'ago' => _('ago'),
|
||||
'All you need is an active internet connection, an Unraid.net account, and the Connect plugin. Get started by installing the plugin.' => _('All you need is an active internet connection, an Unraid.net account, and the Connect plugin.') . ' ' . _('Get started by installing the plugin.'),
|
||||
'Attached Storage Devices' => _('Attached Storage Devices'),
|
||||
'Backing up...this may take a few minutes' => _('Backing up...this may take a few minutes'),
|
||||
'Basic' => _('Basic'),
|
||||
'Begin downgrade to {0}' => sprintf(_('Begin downgrade to %s'), '{0}'),
|
||||
'Beta' => _('Beta'),
|
||||
'Blacklisted USB Flash GUID' => _('Blacklisted USB Flash GUID'),
|
||||
'BLACKLISTED' => _('BLACKLISTED'),
|
||||
'Calculating OS Update Eligibility…' => _('Calculating OS Update Eligibility…'),
|
||||
'Calculating trial expiration…' => _('Calculating trial expiration…'),
|
||||
'Callback redirect type not present or incorrect' => _('Callback redirect type not present or incorrect'),
|
||||
'Cancel {0}' => sprintf(_('Cancel %s'), '{0}'),
|
||||
'Cancel' => _('Cancel'),
|
||||
'Cannot access your USB Flash boot device' => _('Cannot access your USB Flash boot device'),
|
||||
'Cannot validate Unraid Trial key' => _('Cannot validate Unraid Trial key'),
|
||||
'Check for OS Updates' => _('Check for OS Updates'),
|
||||
'check for OS updates' => _('check for OS updates'),
|
||||
'Check for Prereleases' => _('Check for Prereleases'),
|
||||
'Checking WAN IPs…' => _('Checking WAN IPs…'),
|
||||
'Checking...' => _('Checking...'),
|
||||
'Checkout the Connect Documentation' => _('Checkout the Connect Documentation'),
|
||||
'Click to close modal' => _('Click to close modal'),
|
||||
'Click to Copy LAN IP {0}' => sprintf(_('Click to copy LAN IP %s'), '{0}'),
|
||||
'Close Dropdown' => _('Close Dropdown'),
|
||||
'Close Modal' => _('Close Modal'),
|
||||
'Close' => _('Close'),
|
||||
'Configure Connect Features' => _('Configure Connect Features'),
|
||||
'Confirm and start update' => _('Confirm and start update'),
|
||||
'Confirm to Install Unraid OS {0}' => sprintf(_('Confirm to Install Unraid OS %s'), '{0}'),
|
||||
'Connected' => _('Connected'),
|
||||
'Contact Support' => _('Contact Support'),
|
||||
'Continue' => _('Continue'),
|
||||
'Copied' => _('Copied'),
|
||||
'Copy Key URL' => _('Copy Key URL'),
|
||||
'Copy your Key URL: {0}' => sprintf(_('Copy your Key URL: %s'), '{0}'),
|
||||
'Create Flash Backup' => _('Create Flash Backup'),
|
||||
'Current Version {0}' => sprintf(_('Current Version %s'), '{0}'),
|
||||
'Current Version: Unraid {0}' => sprintf(_('Current Version: Unraid %s'), '{0}'),
|
||||
'Customizable Dashboard Tiles' => _('Customizable Dashboard Tiles'),
|
||||
'day' => sprintf(_('%s day'), '{n}') . ' | ' . sprintf(_('%s days'), '{n}'),
|
||||
'Deep Linking' => _('Deep Linking'),
|
||||
'DNS issue, unable to resolve wanip4.unraid.net' => _('DNS issue, unable to resolve wanip4.unraid.net'),
|
||||
'Downgrade Unraid OS to {0}' => sprintf(_('Downgrade Unraid OS to %s'), '{0}'),
|
||||
'Downgrade Unraid OS' => _('Downgrade Unraid OS'),
|
||||
'Downgrades are only recommended if you\'re unable to solve a critical issue.' => _('Downgrades are only recommended if you\'re unable to solve a critical issue.'),
|
||||
'Download Diagnostics' => _('Download Diagnostics'),
|
||||
'Download the Diagnostics zip then please open a bug report on our forums with a description of the issue along with your diagnostics.' => _('Download the Diagnostics zip then please open a bug report on our forums with a description of the issue along with your diagnostics.'),
|
||||
'Download unraid-api Logs' => _('Download unraid-api Logs'),
|
||||
'Dynamic Remote Access' => _('Dynamic Remote Access'),
|
||||
'Enable update notifications' => _('Enable update notifications'),
|
||||
'Enhance your experience with Unraid Connect' => _('Enhance your experience with Unraid Connect'),
|
||||
'Enhance your Unraid experience with Connect' => _('Enhance your Unraid experience with Connect'),
|
||||
'Enhance your Unraid experience' => _('Enhance your Unraid experience'),
|
||||
'Error creating a trial key. Please try again later.' => _('Error creating a trial key. Please try again later.'),
|
||||
'Error Parsing Changelog • {0}' => sprintf(_('Error Parsing Changelog • %s'), '{0}'),
|
||||
'Error' => _('Error'),
|
||||
'Expired {0}' => sprintf(_('Expired %s'), '{0}'),
|
||||
'Expired' => _('Expired'),
|
||||
'Expires at {0}' => sprintf(_('Expires at %s'), '{0}'),
|
||||
'Expires in {0}' => sprintf(_('Expires in %s'), '{0}'),
|
||||
'Extend License to Update' => _('Extend License to Update'),
|
||||
'Extend License' => _('Extend License'),
|
||||
'Extend Trial' => _('Extend Trial'),
|
||||
'Extending your free trial by 15 days' => _('Extending your free trial by 15 days'),
|
||||
'Extension Installed' => _('Extension Installed'),
|
||||
'Failed to {0} {1} Key' => sprintf(_('Failed to %1s %2s Key'), '{0}', '{1}'),
|
||||
'Failed to install key' => _('Failed to install key'),
|
||||
'Failed to update Connect account configuration' => _('Failed to update Connect account configuration'),
|
||||
'Fetching & parsing changelog…' => _('Fetching & parsing changelog…'),
|
||||
'Fix Error' => _('Fix Error'),
|
||||
'Flash Backup is not available. Navigate to {0}/Main/Settings/Flash to try again then come back to this page.' => sprintf(_('Flash Backup is not available. Navigate to %s/Main/Settings/Flash to try again then come back to this page.'), '{0}'),
|
||||
'Flash GUID Error' => _('Flash GUID Error'),
|
||||
'Flash GUID required to check replacement status' => _('Flash GUID required to check replacement status'),
|
||||
'Flash GUID' => _('Flash GUID'),
|
||||
'Flash Product' => _('Flash Product'),
|
||||
'Flash Vendor' => _('Flash Vendor'),
|
||||
'Get an overview of your server\'s state, storage space, apps and VMs status, and more.' => _('Get an overview of your server\'s state, storage space, apps and VMs status, and more.'),
|
||||
'Get Started' => _('Get Started'),
|
||||
'Go to Connect plugin settings' => _('Go to Connect plugin settings'),
|
||||
'Go to Connect' => _('Go to Connect'),
|
||||
'Go to Management Access Now' => _('Go to Management Access Now'),
|
||||
'Go to Settings > Notifications to enable automatic OS update notifications for future releases.' => _('Go to Settings > Notifications to enable automatic OS update notifications for future releases.'),
|
||||
'Go to Tools > Management Access to activate the Flash Backup feature and ensure your backup is up-to-date.' => _('Go to Tools > Management Access to activate the Flash Backup feature and ensure your backup is up-to-date.'),
|
||||
'Go to Tools > Management Access to ensure your backup is up-to-date.' => _('Go to Tools > Management Access to ensure your backup is up-to-date.'),
|
||||
'Go to Tools > Registration to fix' => _('Go to Tools > Registration to fix'),
|
||||
'Go to Tools > Registration to Learn More' => _('Go to Tools > Registration to Learn More'),
|
||||
'Go to Tools > Update OS for more options.' => _('Go to Tools > Update OS for more options.'),
|
||||
'Go to Tools > Update' => _('Go to Tools > Update'),
|
||||
'hour' => sprintf(_('%s hour'), '{n}') . ' | ' . sprintf(_('%s hours'), '{n}'),
|
||||
'I have made a Flash Backup' => _('I have made a Flash Backup'),
|
||||
'If you are asked to supply logs, please open a support request on our Contact Page and reply to the email message you receive with your logs attached.' => _('If you are asked to supply logs, please open a support request on our Contact Page and reply to the email message you receive with your logs attached.'),
|
||||
'Ignore this message if you are currently connected via Remote Access or VPN.' => _('Ignore this message if you are currently connected via Remote Access or VPN.'),
|
||||
'Ignore this release until next reboot' => _('Ignore this release until next reboot'),
|
||||
'Ignored Releases' => _('Ignored Releases'),
|
||||
'In the rare event you need to downgrade we ask that you please provide us with Diagnostics so we can investigate your issue.' => _('In the rare event you need to downgrade we ask that you please provide us with Diagnostics so we can investigate your issue.'),
|
||||
'Install Connect' => _('Install Connect'),
|
||||
'Install Recovered' => _('Install Recovered'),
|
||||
'Install Replaced' => _('Install Replaced'),
|
||||
'Install Unraid OS {0}' => sprintf(_('Install Unraid OS %s'), '{0}'),
|
||||
'Install' => _('Install'),
|
||||
'Installed' => _('Installed'),
|
||||
'Installing Extended Trial' => _('Installing Extended Trial'),
|
||||
'Installing Extended' => _('Installing Extended'),
|
||||
'Installing Recovered' => _('Installing Recovered'),
|
||||
'Installing Replaced' => _('Installing Replaced'),
|
||||
'Installing' => _('Installing'),
|
||||
'Introducing Unraid Connect' => _('Introducing Unraid Connect'),
|
||||
'Invalid API Key Format' => _('Invalid API Key Format'),
|
||||
'Invalid API Key' => _('Invalid API Key'),
|
||||
'Invalid installation' => _('Invalid installation'),
|
||||
'It\s highly recommended to review the changelog before continuing your update.' => _('It\'s highly recommended to review the changelog before continuing your update.'),
|
||||
'Key ineligible for {0}' => sprintf(_('Key ineligible for %s'), '{0}'),
|
||||
'Key ineligible for future releases' => _('Key ineligible for future releases'),
|
||||
'Keyfile required to check replacement status' => _('Keyfile required to check replacement status'),
|
||||
'LAN IP {0}' => sprintf(_('LAN IP %s'), '{0}'),
|
||||
'LAN IP Copied' => _('LAN IP Copied'),
|
||||
'LAN IP' => _('LAN IP'),
|
||||
'Last checked: {0}' => sprintf(_('Last checked: %s'), '{0}'),
|
||||
'Learn more about the error' => _('Learn more about the error'),
|
||||
'Learn more and fix' => _('Learn more and fix'),
|
||||
'Learn more and link your key to your account' => _('Learn more and link your key to your account'),
|
||||
'Learn More' => _('Learn More'),
|
||||
'Learn more' => _('Learn more'),
|
||||
'Let\'s Unleash your Hardware!' => _('Let\'s Unleash your Hardware!'),
|
||||
'License key actions' => _('License key actions'),
|
||||
'License key type' => _('License key type'),
|
||||
'License Management' => _('License Management'),
|
||||
'Link Key' => _('Link Key'),
|
||||
'Linked to Unraid.net account' => _('Linked to Unraidnet account'),
|
||||
'Loading' => _('Loading'),
|
||||
'Manage Unraid.net Account in new tab' => _('Manage Unraid.net Account in new tab'),
|
||||
'Manage Unraid.net Account' => _('Manage Unraid.net Account'),
|
||||
'Manage your license keys at any time via the My Keys section.' => _('Manage your license keys at any time via the My Keys section.'),
|
||||
'Manage Your Server Within Connect' => _('Manage Your Server Within Connect'),
|
||||
'minute' => sprintf(_('%s minute'), '{n}') . ' | ' . sprintf(_('%s minutes'), '{n}'),
|
||||
'Missing key file' => _('Missing key file'),
|
||||
'month' => sprintf(_('%s month'), '{n}') . ' | ' . sprintf(_('%s months'), '{n}'),
|
||||
'More options' => _('More options'),
|
||||
'Multiple License Keys Present' => _('Multiple License Keys Present'),
|
||||
'Never ever be left without a backup of your config. If you need to change flash drives, generate a backup from Connect and be up and running in minutes.' => _('Never ever be left without a backup of your config.') . ' ' . _('If you need to change flash drives, generate a backup from Connect and be up and running in minutes.'),
|
||||
'New Version: {0}' => sprintf(_('New Version: %s'), '{0}'),
|
||||
'No downgrade available' => _('No downgrade available'),
|
||||
'No Flash' => _('No Flash'),
|
||||
'No Keyfile' => _('No Keyfile'),
|
||||
'No thanks' => _('No thanks'),
|
||||
'No USB flash configuration data' => _('No USB flash configuration data'),
|
||||
'Not Linked' => _('Not Linked'),
|
||||
'On January 1st, 2023 SSL certificates for unraid.net were deprecated. You MUST provision a new SSL certificate to use our new myunraid.net domain. You can do this on the Settings > Management Access page.' => _('On January 1st, 2023 SSL certificates for unraid.net were deprecated. You MUST provision a new SSL certificate to use our new myunraid.net domain. You can do this on the Settings > Management Access page.'),
|
||||
'Online Flash Backup' => _('Online Flash Backup'),
|
||||
'Open a bug report' => _('Open a bug report'),
|
||||
'Open Dropdown' => _('Open Dropdown'),
|
||||
'Opens Connect in new tab' => _('Opens Connect in new tab'),
|
||||
'Original release date {0}' => sprintf(_('Original release date %s'), '{0}'),
|
||||
'OS Update Eligibility Expired' => _('OS Update Eligibility Expired'),
|
||||
'Performing actions' => _('Performing actions'),
|
||||
'Please confirm the update details below' => _('Please confirm the update details below'),
|
||||
'Please finish the initiated downgrade to enable updates.' => _('Please finish the initiated downgrade to enable updates.'),
|
||||
'Please finish the initiated update to enable a downgrade.' => _('Please finish the initiated update to enable a downgrade.'),
|
||||
'Please fix any errors and try again.' => _('Please fix any errors and try again.'),
|
||||
'Please keep this window open while we perform some actions' => _('Please keep this window open while we perform some actions'),
|
||||
'Please keep this window open' => _('Please keep this window open'),
|
||||
'Please sign out then sign back in to refresh your API key.' => _('Please sign out then sign back in to refresh your API key.'),
|
||||
'Please wait while the page reloads to install your trial key' => _('Please wait while the page reloads to install your trial key'),
|
||||
'Plus more on the way' => _('Plus more on the way'),
|
||||
'Plus' => _('Plus'),
|
||||
'Pro' => _('Pro'),
|
||||
'Purchase Key' => _('Purchase Key'),
|
||||
'Purchase' => _('Purchase'),
|
||||
'Ready to Install Key' => _('Ready to Install Key'),
|
||||
'Ready to update Connect account configuration' => _('Ready to update Connect account configuration'),
|
||||
'Real-time Monitoring' => _('Real-time Monitoring'),
|
||||
'Reboot Now to Downgrade to {0}' => sprintf(_('Reboot Now to Downgrade to %s'), '{0}'),
|
||||
'Reboot Now to Downgrade' => _('Reboot Now to Downgrade'),
|
||||
'Reboot Now to Update to {0}' => sprintf(_('Reboot Now to Update to %s'), '{0}'),
|
||||
'Reboot Now to Update' => _('Reboot Now to Update'),
|
||||
'Reboot Required for Downgrade to {0}' => sprintf(_('Reboot Required for Downgrade to %s'), '{0}'),
|
||||
'Reboot Required for Downgrade' => _('Reboot Required for Downgrade'),
|
||||
'Reboot Required for Update to {0}' => sprintf(_('Reboot Required for Update to %s'), '{0}'),
|
||||
'Reboot Required for Update' => _('Reboot Required for Update'),
|
||||
'Rebooting will likely solve this.' => _('Rebooting will likely solve this.'),
|
||||
'Receive the latest and greatest for Unraid OS. Whether it new features, security patches, or bug fixes – keeping your server up-to-date ensures the best experience that Unraid has to offer.' => _('Receive the latest and greatest for Unraid OS.') . ' ' . _('Whether it new features, security patches, or bug fixes – keeping your server up-to-date ensures the best experience that Unraid has to offer.'),
|
||||
'Recover Key' => _('Recover Key'),
|
||||
'Recovered' => _('Recovered'),
|
||||
'Redeem Activation Code' => _('Redeem Activation Code'),
|
||||
'Refresh' => _('Refresh'),
|
||||
'Registered on' => _('Registered on'),
|
||||
'Registered to' => _('Registered to'),
|
||||
'Registration key / USB Flash GUID mismatch' => _('Registration key / USB Flash GUID mismatch'),
|
||||
'Release date {0}' => sprintf(_('Release date %s'), '{0}'),
|
||||
'Release requires verification to update' => _('Release requires verification to update'),
|
||||
'Reload' => _('Reload'),
|
||||
'Remark: Unraid\'s WAN IPv4 {0} does not match your client\'s WAN IPv4 {1}.' => sprintf(_('Remark: Unraid\'s WAN IPv4 %1s does not match your client\'s WAN IPv4 %2s.'), '{0}', '{1}'),
|
||||
'Remark: your WAN IPv4 is {0}' => sprintf(_('Remark: your WAN IPv4 is %s'), '{0}'),
|
||||
'Remove from ignore list' => _('Remove from ignore list'),
|
||||
'Remove' => _('Remove'),
|
||||
'Replace Key' => _('Replace Key'),
|
||||
'Replaced' => _('Replaced'),
|
||||
'Requires the local unraid-api to be running successfully' => _('Requires the local unraid-api to be running successfully'),
|
||||
'Restarting unraid-api…' => _('Restarting unraid-api…'),
|
||||
'second' => sprintf(_('%s second'), '{n}') . ' | ' . sprintf(_('%s seconds'), '{n}'),
|
||||
'Server Up Since {0}' => sprintf(_('Server Up Since %s'), '{0}'),
|
||||
'Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI. Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window.' => _('Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI.') . ' ' . _('Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window.'),
|
||||
'Set custom server tiles how you like and automatically display your server\'s banner image on your Connect Dashboard.' => _('Set custom server tiles how you like and automatically display your server\'s banner image on your Connect Dashboard.'),
|
||||
'Settings' => _('Settings'),
|
||||
'Sign In Failed' => _('Sign In Failed'),
|
||||
'Sign In requires the local unraid-api to be running' => _('Sign In requires the local unraid-api to be running'),
|
||||
'Sign In to utilize Unraid Connect' => _('Sign In to utilize Unraid Connect'),
|
||||
'Sign In to your Unraid.net account to get started' => _('Sign In to your Unraid.net account to get started'),
|
||||
'Sign In with Unraid.net Account' => _('Sign In with Unraid.net Account'),
|
||||
'Sign In' => _('Sign In'),
|
||||
'Sign Out Failed' => _('Sign Out Failed'),
|
||||
'Sign Out of Unraid.net' => _('Sign Out of Unraid.net'),
|
||||
'Sign Out requires the local unraid-api to be running' => _('Sign Out requires the local unraid-api to be running'),
|
||||
'Signing in {0}…' => sprintf(_('Signing in %s…'), '{0}'),
|
||||
'Signing In' => _('Signing In'),
|
||||
'Signing out {0}…' => sprintf(_('Signing out %s…'), '{0}'),
|
||||
'Signing Out' => _('Signing Out'),
|
||||
'Something went wrong' => _('Something went wrong'),
|
||||
'SSL certificates for unraid.net deprecated' => _('SSL certificates for unraid.net deprecated'),
|
||||
'Stale Server' => _('Stale Server'),
|
||||
'Stale' => _('Stale'),
|
||||
'Start Free 30 Day Trial' => _('Start Free 30 Day Trial'),
|
||||
'Starting your free 30 day trial' => _('Starting your free 30 day trial'),
|
||||
'Success!' => _('Success!'),
|
||||
'Thank you for choosing Unraid OS!' => _('Thank you for choosing Unraid OS!'),
|
||||
'Thank you for installing Connect!' => _('Thank you for installing Connect!'),
|
||||
'Thank you for purchasing an Unraid {0} Key!' => sprintf(_('Thank you for purchasing an Unraid %s Key!'), '{0}'),
|
||||
'Thank you for upgrading to an Unraid {0} Key!' => sprintf(_('Thank you for upgrading to an Unraid %s Key!'), '{0}'),
|
||||
'The Connect dashboard links to relevant sections of the webgui, allowing quick access to those settings and server sections.' => _('The Connect dashboard links to relevant sections of the webgui, allowing quick access to those settings and server sections.'),
|
||||
'The logs may contain sensitive information so do not post them publicly.' => _('The logs may contain sensitive information so do not post them publicly.'),
|
||||
'The primary method of support for Unraid Connect is through our forums and Discord.' => _('The primary method of support for Unraid Connect is through our forums and Discord.'),
|
||||
'Then go to Tools > Registration to manually install it' => _('Then go to Tools > Registration to manually install it'),
|
||||
'This may indicate a complex network that will not work with this Remote Access solution.' => _('This may indicate a complex network that will not work with this Remote Access solution.'),
|
||||
'This update will require a reboot' => _('This update will require a reboot'),
|
||||
'Toggle on/off server accessibility with dynamic remote access. Automatically turn on UPnP and open a random WAN port on your router at the click of a button and close off access in seconds.' => _('Toggle on/off server accessibility with dynamic remote access.') . ' ' . _('Automatically turn on UPnP and open a random WAN port on your router at the click of a button and close off access in seconds.'),
|
||||
'Too Many Devices' => _('Too Many Devices'),
|
||||
'Transfer License to New Flash' => _('Transfer License to New Flash'),
|
||||
'Trial Expired, see options below' => _('Trial Expired, see options below'),
|
||||
'Trial Expired' => _('Trial Expired'),
|
||||
'Trial Key Created' => _('Trial Key Created'),
|
||||
'Trial Key Creation Failed' => _('Trial Key Creation Failed'),
|
||||
'Trial Key Expired {0}' => sprintf(_('Trial Key Expired %s'), '{0}'),
|
||||
'Trial Key Expired at {0}' => sprintf(_('Trial Key Expired at %s'), '{0}'),
|
||||
'Trial Key Expires at {0}' => sprintf(_('Trial Key Expires at %s'), '{0}'),
|
||||
'Trial Key Expires in {0}' => sprintf(_('Trial Key Expires in %s'), '{0}'),
|
||||
'Trial Requires Internet Connection' => _('Trial Requires Internet Connection'),
|
||||
'Trial' => _('Trial'),
|
||||
'Unable to check for OS updates' => _('Unable to check for OS updates'),
|
||||
'Unable to fetch client WAN IPv4' => _('Unable to fetch client WAN IPv4'),
|
||||
'Unable to open release notes' => _('Unable to open release notes'),
|
||||
'Unknown error' => _('Unknown error'),
|
||||
'Unknown' => _('Unknown'),
|
||||
'unlimited' => _('unlimited'),
|
||||
'Unraid {0} Available' => sprintf(_('Unraid %s Available'), '{0}'),
|
||||
'Unraid {0} Update Available' => sprintf(_('Unraid %s Update Available'), '{0}'),
|
||||
'Unraid {0}' => sprintf(_('Unraid %s'), '{0}'),
|
||||
'Unraid Connect Error' => _('Unraid Connect Error'),
|
||||
'Unraid Connect Forums' => _('Unraid Connect Forums'),
|
||||
'Unraid Connect Install Failed' => _('Unraid Connect Install Failed'),
|
||||
'Unraid Contact Page' => _('Unraid Contact Page'),
|
||||
'Unraid Discord' => _('Unraid Discord'),
|
||||
'Unraid logo animating with a wave like effect' => _('Unraid logo animating with a wave like effect'),
|
||||
'Unraid OS {0} Released' => sprintf(_('Unraid OS %s Released'), '{0}'),
|
||||
'Unraid OS {0} Update Available' => sprintf(_('Unraid OS %s Update Available'), '{0}'),
|
||||
'Unraid OS is up-to-date' => _('Unraid OS is up-to-date'),
|
||||
'Unraid OS Update Available' => _('Unraid OS Update Available'),
|
||||
'unraid-api is offline' => _('unraid-api is offline'),
|
||||
'Up-to-date with eligible releases' => _('Up-to-date with eligible releases'),
|
||||
'Up-to-date' => _('Up-to-date'),
|
||||
'Update Available' => _('Update Available'),
|
||||
'Update Released' => _('Update Released'),
|
||||
'Update Unraid OS confirmation required' => _('Update Unraid OS confirmation required'),
|
||||
'Update Unraid OS' => _('Update Unraid OS'),
|
||||
'Updating 3rd party drivers' => _('Updating 3rd party drivers'),
|
||||
'Upgrade Key' => _('Upgrade Key'),
|
||||
'Upgrade' => _('Upgrade'),
|
||||
'Uptime {0}' => sprintf(_('Uptime %s'), '{0}'),
|
||||
'USB Flash device error' => _('USB Flash device error'),
|
||||
'USB Flash has no serial number' => _('USB Flash has no serial number'),
|
||||
'Verify to Update' => _('Verify to Update'),
|
||||
'Version available for restore {0}' => sprintf(_('Version available for restore %s'), '{0}'),
|
||||
'Version: {0}' => sprintf(_('Version: %s'), '{0}'),
|
||||
'View Available Updates' => _('View Available Updates'),
|
||||
'View Changelog & Update' => _('View Changelog & Update'),
|
||||
'View Changelog for {0}' => sprintf(_('View Changelog for %s'), '{0}'),
|
||||
'View Changelog on Docs' => _('View Changelog on Docs'),
|
||||
'View Changelog to Start Update' => _('View Changelog to Start Update'),
|
||||
'View Changelog' => _('View Changelog'),
|
||||
'View on Docs' => _('View on Docs'),
|
||||
'View release notes' => _('View release notes'),
|
||||
'We recommend backing up your USB Flash Boot Device before starting the update.' => _('We recommend backing up your USB Flash Boot Device before starting the update.'),
|
||||
'year' => sprintf(_('%s year'), '{n}') . ' | ' . sprintf(_('%s years'), '{n}'),
|
||||
'You are still eligible to access OS updates that were published on or before {1}.' => sprintf(_('You are still eligible to access OS updates that were published on or before %s.'), '{1}'),
|
||||
'You can also manually create a new backup by clicking the Create Flash Backup button.' => _('You can also manually create a new backup by clicking the Create Flash Backup button.'),
|
||||
'You can manually create a backup by clicking the Create Flash Backup button.' => _('You can manually create a backup by clicking the Create Flash Backup button.'),
|
||||
'You have already activated the Flash Backup feature via the Unraid Connect plugin.' => _('You have already activated the Flash Backup feature via the Unraid Connect plugin.'),
|
||||
'You have exceeded the number of devices allowed for your license. Please remove a device before adding another.' => _('You have exceeded the number of devices allowed for your license. Please remove a device before adding another.'),
|
||||
'You have not activated the Flash Backup feature via the Unraid Connect plugin.' => _('You have not activated the Flash Backup feature via the Unraid Connect plugin.'),
|
||||
'You may still update to releases dated prior to your update expiration date.' => _('You may still update to releases dated prior to your update expiration date.'),
|
||||
'You\'re one step closer to enhancing your Unraid experience' => _('You\'re one step closer to enhancing your Unraid experience'),
|
||||
'Your {0} Key has been replaced!' => sprintf(_('Your %s Key has been replaced!'), '{0}'),
|
||||
'Your {0} license included one year of free updates at the time of purchase. You are now eligible to extend your license and access the latest OS updates. You are still eligible to access OS updates that were published on or before {1}.' => sprintf(_('Your %s license included one year of free updates at the time of purchase.'), '{0}') . ' ' . _('You are now eligible to extend your license and access the latest OS updates.') . ' ' . sprintf(_('You are still eligible to access OS updates that were published on or before %s.'), '{1}'),
|
||||
'Your {0} license included one year of free updates at the time of purchase. You are now eligible to extend your license and access the latest OS updates.' => sprintf(_('Your %s license included one year of free updates at the time of purchase.'), '{0}') . ' ' . _('You are now eligible to extend your license and access the latest OS updates.'),
|
||||
'Your free Trial key provides all the functionality of an Unleashed Registration key' => _('Your free Trial key provides all the functionality of an Unleashed Registration key'),
|
||||
'Your license key is not eligible for Unraid OS {0}' => sprintf(_('Your license key is not eligible for Unraid OS %s'), '{0}'),
|
||||
'Your Trial has expired' => _('Your Trial has expired'),
|
||||
'Your Trial key has been extended!' => _('Your Trial key has been extended!'),
|
||||
];
|
||||
}
|
||||
|
||||
public function getTranslations()
|
||||
{
|
||||
return $this->translations ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $urlEncode {bool}
|
||||
* @return string
|
||||
*/
|
||||
public function getTranslationsJson($urlEncode = false)
|
||||
{
|
||||
if ($urlEncode) {
|
||||
return rawurlencode(json_encode($this->getTranslations(), JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
return json_encode($this->getTranslations(), JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
}
|
||||
|
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/php
|
||||
<?PHP
|
||||
/* Copyright 2005-2021, Lime Technology
|
||||
* Copyright 2012-2021, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
function update($url, $payload) {
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch,CURLOPT_POST, true);
|
||||
curl_setopt($ch,CURLOPT_POSTFIELDS, $payload);
|
||||
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
|
||||
$result = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
$dyn_cfg = '/boot/config/plugins/dynamix/dynamix.cfg';
|
||||
$mys_cfg = '/boot/config/plugins/dynamix.my.servers/myservers.cfg';
|
||||
|
||||
if (file_exists($dyn_cfg) && !file_exists($mys_cfg)) {
|
||||
$orig = @parse_ini_file($dyn_cfg,true);
|
||||
$var = @(array)parse_ini_file('/usr/local/emhttp/state/var.ini',true);
|
||||
$url = "http://localhost:".$var['PORT']."/update.php";
|
||||
|
||||
// write [remote] section to myservers.cfg
|
||||
if(!empty($orig['remote'])) {
|
||||
$fields_mys_remote = [
|
||||
'csrf_token' => $var['csrf_token'],
|
||||
'#file' => $mys_cfg,
|
||||
'#section' => 'remote'
|
||||
];
|
||||
foreach($orig['remote'] as $key => $value) {
|
||||
$fields_mys_remote[$key] = $value;
|
||||
}
|
||||
update($url, http_build_query($fields_mys_remote));
|
||||
}
|
||||
/*
|
||||
// write [wizard] section to myservers.cfg
|
||||
if(!empty($orig['wizard'])) {
|
||||
$fields_mys_wizard = [
|
||||
'csrf_token' => $var['csrf_token'],
|
||||
'#file' => $mys_cfg,
|
||||
'#section' => 'wizard'
|
||||
];
|
||||
foreach($orig['wizard'] as $key => $value) {
|
||||
$fields_mys_wizard[$key] = $value;
|
||||
}
|
||||
update($url, http_build_query($fields_mys_wizard));
|
||||
}
|
||||
*/
|
||||
// remove [remote] section from dynamix.cfg
|
||||
if(!empty($orig['remote'])) {
|
||||
$fields_dyn_remote = [
|
||||
'csrf_token' => $var['csrf_token'],
|
||||
'#file' => $dyn_cfg,
|
||||
'#section' => 'remote',
|
||||
'#cleanup' => 'true'
|
||||
];
|
||||
foreach($orig['remote'] as $key => $value) {
|
||||
$fields_dyn_remote[$key] = '';
|
||||
}
|
||||
update($url, http_build_query($fields_dyn_remote));
|
||||
}
|
||||
// remove [wizard] section from dynamix.cfg
|
||||
if(!empty($orig['wizard'])) {
|
||||
$fields_dyn_wizard = [
|
||||
'csrf_token' => $var['csrf_token'],
|
||||
'#file' => $dyn_cfg,
|
||||
'#section' => 'wizard',
|
||||
'#cleanup' => 'true'
|
||||
];
|
||||
foreach($orig['wizard'] as $key => $value) {
|
||||
$fields_dyn_wizard[$key] = '';
|
||||
}
|
||||
update($url, http_build_query($fields_dyn_wizard));
|
||||
}
|
||||
// remove [remote] and [wizard] section headings from dyn_cfg file
|
||||
$oldtext = file_get_contents($dyn_cfg);
|
||||
$newtext = preg_replace ('/\[(remote|wizard)\]\n/', '', $oldtext);
|
||||
if (strcmp($oldtext, $newtext) !== 0) {
|
||||
file_put_contents($dyn_cfg, $newtext);
|
||||
}
|
||||
}
|
||||
if (!file_exists($mys_cfg)) touch($mys_cfg);
|
||||
|
||||
?>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,14 +1,12 @@
|
||||
{
|
||||
".nuxt/nuxt-custom-elements/entries/unraid-components.client.css": {
|
||||
"file": "_nuxt/unraid-components.client-d0bc5449.css",
|
||||
"src": ".nuxt/nuxt-custom-elements/entries/unraid-components.client.css"
|
||||
},
|
||||
".nuxt/nuxt-custom-elements/entries/unraid-components.client.mjs": {
|
||||
"css": [
|
||||
"_nuxt/unraid-components.client-d0bc5449.css"
|
||||
],
|
||||
"file": "_nuxt/unraid-components.client-3646d7f7.js",
|
||||
"file": "_nuxt/unraid-components.client-CQOXNcK4.js",
|
||||
"name": "unraid-components.client",
|
||||
"src": ".nuxt/nuxt-custom-elements/entries/unraid-components.client.mjs",
|
||||
"isEntry": true,
|
||||
"src": ".nuxt/nuxt-custom-elements/entries/unraid-components.client.mjs"
|
||||
}
|
||||
"css": [
|
||||
"_nuxt/unraid-components-p_3YF86n.css"
|
||||
]
|
||||
},
|
||||
"ts": 1723595088
|
||||
}
|
153
emhttp/plugins/dynamix.plugin.manager/Downgrade.page
Normal file
153
emhttp/plugins/dynamix.plugin.manager/Downgrade.page
Normal file
@@ -0,0 +1,153 @@
|
||||
Menu="About:20"
|
||||
Title="Downgrade OS"
|
||||
Icon="icon-update"
|
||||
Tag="upload"
|
||||
---
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
/**
|
||||
* @note icon-update is rotated via CSS in myservers1.php
|
||||
*/
|
||||
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php";
|
||||
// Create an instance of the RebootDetails class
|
||||
$rebootDetails = new RebootDetails();
|
||||
// Get the current reboot details if there are any
|
||||
$rebootDetails->setPrevious();
|
||||
|
||||
$serverNameEscaped = htmlspecialchars(str_replace(' ', '_', strtolower($var['NAME'])));
|
||||
?>
|
||||
|
||||
<script>
|
||||
const nchan_diagnostics = new NchanSubscriber('/sub/diagnostics', { subscriber: 'websocket' });
|
||||
const reportUrl = new URL('https://forums.unraid.net/bug-reports/');
|
||||
let diagnosticsFile = '';
|
||||
|
||||
nchan_diagnostics.on('message', function(data) {
|
||||
if (data == '_DONE_') {
|
||||
nchan_diagnostics.stop();
|
||||
$('.sweet-alert').hide('fast').removeClass('nchan');
|
||||
swal.close();
|
||||
$('div.spinner').show('slow');
|
||||
location = diagnosticsFile;
|
||||
|
||||
setTimeout(() => {
|
||||
cleanupDiagnostics();
|
||||
reportAfterDiagnosticsDownload();
|
||||
}, 2000);
|
||||
} else if (data) {
|
||||
let box = $('pre#swaltext');
|
||||
box.html(box.html() + '<br>' + data).scrollTop(box[0].scrollHeight);
|
||||
}
|
||||
});
|
||||
|
||||
function downloadDiagnostics() {
|
||||
const tzoffset = (new Date()).getTimezoneOffset() * 60000; // offset in milliseconds
|
||||
const localISOTime = (new Date(Date.now() - tzoffset));
|
||||
const year = localISOTime.getFullYear();
|
||||
const month = String(localISOTime.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(localISOTime.getDate()).padStart(2, '0');
|
||||
const hours = String(localISOTime.getHours()).padStart(2, '0');
|
||||
const minutes = String(localISOTime.getMinutes()).padStart(2, '0');
|
||||
const dateOutput = `${year}${month}${day}_${hours}${minutes}`;
|
||||
const zipName = '<?=$serverNameEscaped?>-diagnostics-' + dateOutput + '.zip';
|
||||
|
||||
nchan_diagnostics.start();
|
||||
|
||||
$.post(
|
||||
'/webGui/include/Download.php',
|
||||
{
|
||||
cmd: 'diag',
|
||||
file: zipName,
|
||||
anonymize: '',
|
||||
},
|
||||
function(zip) {
|
||||
if (!zip) {
|
||||
return nchan_diagnostics.stop();
|
||||
}
|
||||
|
||||
diagnosticsFile = zip;
|
||||
swal({
|
||||
title: "_(Downloading)_...",
|
||||
text: "/boot/logs" + zip + "<hr><pre id='swaltext'></pre>",
|
||||
html: true,
|
||||
animation: 'none',
|
||||
showConfirmButton: false,
|
||||
});
|
||||
$('.sweet-alert').addClass('nchan');
|
||||
$('button.confirm').prop('disabled', true);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function reportAfterDiagnosticsDownload() {
|
||||
$('div.spinner').hide('fast');
|
||||
swal({
|
||||
title: "_(Open a bug report)_",
|
||||
text: "_(Create a bug report on our forums with a description of the issue along with your diagsnotics)_",
|
||||
html: true,
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "<?= _('Create Bug Report') ?>",
|
||||
cancelButtonText: "<?= _('Close') ?>",
|
||||
}, function(confirm) {
|
||||
if (!confirm) {
|
||||
return false;
|
||||
}
|
||||
window.open(reportUrl, '_blank');
|
||||
});
|
||||
}
|
||||
|
||||
function cleanupDiagnostics() {
|
||||
if (document.hasFocus()) {
|
||||
return $.post('/webGui/include/Download.php', { cmd: 'delete', file: diagnosticsFile });
|
||||
}
|
||||
setTimeout(cleanupDiagnostics, 2000);
|
||||
}
|
||||
|
||||
function startDowngrade() {
|
||||
$('div.spinner').show('slow');
|
||||
|
||||
$.get(
|
||||
'/plugins/dynamix.plugin.manager/include/Downgrade.php',
|
||||
{
|
||||
version: '<?= $rebootDetails->previousVersion ?>',
|
||||
},
|
||||
function() {
|
||||
refresh();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function confirmDowngrade() {
|
||||
swal({
|
||||
title: "_(Confirm Downgrade)_",
|
||||
text: "<?= $rebootDetails->previousVersion ?><br>_(A reboot will be required)_",
|
||||
html: true,
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "<?= _('Confirm') ?>",
|
||||
cancelButtonText: "<?= _('Cancel') ?>",
|
||||
}, function(confirm) {
|
||||
if (!confirm) {
|
||||
return false;
|
||||
}
|
||||
startDowngrade();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<unraid-i18n-host>
|
||||
<unraid-downgrade-os
|
||||
reboot-version="<?= $rebootDetails->rebootVersion ?>"
|
||||
restore-version="<?= $rebootDetails->previousVersion ?>"
|
||||
restore-release-date="<?= $rebootDetails->previousReleaseDate ?>"></unraid-downgrade-os>
|
||||
</unraid-i18n-host>
|
@@ -13,14 +13,6 @@ Link='nav-user'
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<style>
|
||||
/* Additional CSS for when user supplies element */
|
||||
.ca_element_notice{padding-right:20px;width:100%;height:40px;line-height:40px;color:#e68a00;background:#feefb3;border-bottom:#e68a00 1px solid;text-align:center;font-size:1.4rem;z-index:900;}
|
||||
a.ca_PluginUpdateInstall{cursor:pointer;}
|
||||
span.ca_PluginUpdateDismiss{float:right;margin-right:20px;cursor:pointer;}
|
||||
span.bannerInfo {cursor:pointer;text-decoration:none;margin:0 12px 0 6px;}
|
||||
span.bannerInfo::before {content:"\f05a";font-family:fontAwesome;color:#e68a00;}
|
||||
</style>
|
||||
<script>
|
||||
const ca_args = {};
|
||||
|
||||
|
@@ -3,8 +3,8 @@ Title="Install Plugin"
|
||||
Tag="download"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2022, Lime Technology
|
||||
* Copyright 2012-2022, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
|
@@ -6,8 +6,8 @@ Tabs="true"
|
||||
Code="e944"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2022, Lime Technology
|
||||
* Copyright 2012-2022, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -19,16 +19,12 @@ Code="e944"
|
||||
?>
|
||||
<?
|
||||
// Remove stale /tmp/plugin/*.plg entries (check that script 'plugin' is not running to avoid clashes)
|
||||
if (!exec("pgrep -f $docroot/plugins/dynamix.plugin.manager/scripts/plugin")) {
|
||||
if (!exec('pgrep --ns $$ -f '."$docroot/plugins/dynamix.plugin.manager/scripts/plugin")) {
|
||||
foreach (glob("/tmp/plugins/*.{plg,txt}", GLOB_NOSORT+GLOB_BRACE) as $entry) if (!file_exists("/var/log/plugins/".basename($entry))) @unlink($entry);
|
||||
}
|
||||
$check = $notify['version'] ? 0 : 1;
|
||||
?>
|
||||
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.filetree.css')?>">
|
||||
<style>
|
||||
#plugin_tree{width:33%;height:200px;overflow-y:scroll}
|
||||
table tbody td{line-height:normal}
|
||||
</style>
|
||||
|
||||
<script src="<?autov('/webGui/javascript/jquery.filetree.js')?>" charset="utf-8"></script>
|
||||
<script>
|
||||
@@ -155,7 +151,7 @@ $(function() {
|
||||
$('.tabs').append("<span id='removeall' class='status vhshift' style='display:none;margin-left:12px'><input type='button' value=\"_(Remove Selected Plugins)_\" onclick='removeList()'></span>");
|
||||
});
|
||||
</script>
|
||||
<table class='tablesorter plugins shift' id='plugin_table'>
|
||||
<table class='unraid tablesorter plugins shift' id='plugin_table'>
|
||||
<thead><tr><th></th><th>_(Plugin)_</th><th>_(Author)_</th><th>_(Version)_</th><th>_(Status)_</th><th>_(Uninstall)_</th></tr></thead>
|
||||
<tbody id="plugin_list"><tr><td colspan="6"></td><tr></tbody>
|
||||
</table>
|
||||
|
@@ -4,8 +4,8 @@ Tag="puzzle-piece"
|
||||
Cond="glob('/boot/config/plugins-error/*.plg')"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2021, Lime Technology
|
||||
* Copyright 2012-2021, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
|
@@ -4,8 +4,8 @@ Tag="puzzle-piece"
|
||||
Cond="glob('/boot/config/plugins-stale/*.plg')"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2021, Lime Technology
|
||||
* Copyright 2012-2021, Bergware International.
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
|
@@ -1,11 +1,10 @@
|
||||
Menu="About"
|
||||
Menu="About:10"
|
||||
Title="Update OS"
|
||||
Icon="icon-update"
|
||||
Tag="upload"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2022, Lime Technology
|
||||
* Copyright 2012-2022, Bergware International.
|
||||
<?php
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -14,186 +13,38 @@ Tag="upload"
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php";
|
||||
$rebootDetails = new RebootDetails();
|
||||
?>
|
||||
<?
|
||||
$version = $branch = $date = _('unknown');
|
||||
$bzroot = file_exists('/boot/previous/bzroot');
|
||||
$check = $notify['unraidos'] ? 0 : 1;
|
||||
$changes = '/boot/previous/changes.txt';
|
||||
$zip = htmlspecialchars(str_replace(' ','_',strtolower($var['NAME'])));
|
||||
|
||||
if (file_exists($changes)) {
|
||||
exec("head -n4 $changes",$rows);
|
||||
foreach ($rows as $row) {
|
||||
$i = stripos($row,'version');
|
||||
if ($i !== false) {
|
||||
[$version,$date] = explode(' ',trim(substr($row,$i+7)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
$branch = strpos($version,'rc')!==false ? _('Next') : (strpos($version,'beta')!==false ? _('Beta') : _('Stable'));
|
||||
}
|
||||
$reboot = preg_match("/^\*\*(REBOOT REQUIRED|DOWNGRADE)/",@file_get_contents("$docroot/plugins/unRAIDServer/README.md",false,null,0,20));
|
||||
?>
|
||||
<style>
|
||||
ul,li{margin:0;padding-top:0;padding-bottom:0}
|
||||
pre.pre{margin:30px 0}
|
||||
pre>p{margin:0;padding:0}
|
||||
pre#swaltext{height:600px!important}
|
||||
@media (max-width:960px){pre#swaltext{height:400px!important}}
|
||||
@media (max-width:960px){.sweet-alert.nchan{height:600px;width:900px;margin-left:-470px}}
|
||||
@media (max-height:768px){pre#swaltext{height:400px!important}}
|
||||
@media (max-height:768px){.sweet-alert.nchan{height:600px;width:900px;margin-left:-470px}}
|
||||
input[value="_(Install)_"],input[value="_(Update)_"],input[value="_(Restore)_"]{margin:0}
|
||||
<?if ($themes1):?>
|
||||
span.vhshift{margin-top:13px!important}
|
||||
<?endif;?>
|
||||
</style>
|
||||
|
||||
<script>
|
||||
var diagnosticsFile = "";
|
||||
var nchan_diagnostics = new NchanSubscriber('/sub/diagnostics',{subscriber:'websocket'});
|
||||
var original = null;
|
||||
const args = {};
|
||||
|
||||
nchan_diagnostics.on('message', function(data) {
|
||||
if (data == '_DONE_') {
|
||||
nchan_diagnostics.stop();
|
||||
$('.sweet-alert').hide('fast').removeClass('nchan');
|
||||
swal.close();
|
||||
location = diagnosticsFile;
|
||||
setTimeout(cleanUp,4000);
|
||||
} else if (data) {
|
||||
let box = $('pre#swaltext');
|
||||
box.html(box.html()+'<br>'+data).scrollTop(box[0].scrollHeight);
|
||||
}
|
||||
});
|
||||
|
||||
function openInstall(cmd,title,plg) {
|
||||
if (cmd == null) {
|
||||
openPlugin(args.cmd,args.title,args.plg);
|
||||
return;
|
||||
}
|
||||
args.cmd = cmd;
|
||||
args.title = title;
|
||||
args.plg = plg;
|
||||
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{cmd:'alert'},function(data) {
|
||||
if (data==0) {
|
||||
// no alert message - proceed with update
|
||||
setTimeout(openInstall);
|
||||
} else {
|
||||
// show alert message and ask for confirmation
|
||||
openAlert("showchanges <?=$alerts?>","_(Alert Message)_",'openInstall');
|
||||
}
|
||||
});
|
||||
}
|
||||
function update_table(branch) {
|
||||
if (original) {
|
||||
if (branch != original) branch = '';
|
||||
} else {
|
||||
if (branch) original = branch;
|
||||
}
|
||||
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{system:true,branch:branch},function(data) {
|
||||
data = data.split('\0');
|
||||
updateInfo(data[0]);
|
||||
$('#os_table').trigger('update');
|
||||
});
|
||||
}
|
||||
function downgrade() {
|
||||
swal({title:"_(Diagnostics)_",text:"_(Please provide diagnostics when experiencing problems)_<br>_(Post these in the forums)_",html:true,type:'warning',showCancelButton:true,confirmButtonText:"<?=_('Diagnostics')?>",cancelButtonText:"<?=_('Restore')?>"},function(diag){
|
||||
if (diag) {
|
||||
// get diagnostics and then downgrade
|
||||
setTimeout(function(){diagnostics(zipfile());},250);
|
||||
} else {
|
||||
// downgrade immediately
|
||||
$.get('/plugins/dynamix.plugin.manager/include/Downgrade.php',{version:'<?=$version?>'},function(){refresh();});
|
||||
}
|
||||
});
|
||||
}
|
||||
function updateInfo(data) {
|
||||
var updates = data.split('\n');
|
||||
for (var n=0,update; update=updates[n]; n++) {
|
||||
var fields = update.split('\r');
|
||||
for (var i=0,field; field=fields[i]; i++) {
|
||||
var row = field.split('::');
|
||||
$('#'+row[0]).attr('data',row[1]).html(row[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
function initlist() {
|
||||
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{init:true,system:true,check:<?=$check?>},function(data) {
|
||||
$('#os_list').html(data);
|
||||
<?if ($bzroot):?>
|
||||
$('#previous').show();
|
||||
<?endif;?>
|
||||
loadlist();
|
||||
});
|
||||
}
|
||||
function warning (data) {
|
||||
$('#change_branch').prop('disabled',true);
|
||||
return data.replace('green','orange').replace("<?=_('up-to-date')?>","<?=_('Reboot')?>").replace('checking','warning');
|
||||
}
|
||||
function loadlist(id,check) {
|
||||
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{system:true,audit:id,check:check||<?=$check?>},function(data) {
|
||||
var list = $('#os_list');
|
||||
if (id) {
|
||||
var cmd = id.split(':');
|
||||
var tr = 'tr#'+cmd[0].replace(/[\. _]/g,'');
|
||||
switch (cmd[1]) {
|
||||
case 'update' : data = warning(data);
|
||||
case 'return' : updateInfo(data); break;
|
||||
case 'install': list.find(tr).remove(); list.append(warning(data)); break;
|
||||
}
|
||||
} else {
|
||||
<?if (!$reboot):?>
|
||||
updateInfo(data);
|
||||
<?else:?>
|
||||
updateInfo(warning(data));
|
||||
<?endif;?>
|
||||
}
|
||||
$('#os_table').trigger('update');
|
||||
$('#checkos').prop('disabled',false);
|
||||
<?if ($reboot):?>
|
||||
$('#change_branch').prop('disabled',true);
|
||||
<?endif;?>
|
||||
});
|
||||
}
|
||||
function cleanUp() {
|
||||
function cleanUpFlashBackup(zip) {
|
||||
if (document.hasFocus()) {
|
||||
$.post('/webGui/include/Download.php',{cmd:'delete',file:diagnosticsFile},function(){
|
||||
$.get('/plugins/dynamix.plugin.manager/include/Downgrade.php',{version:'<?=$version?>'},function(){refresh();});
|
||||
});
|
||||
$('input[value="_(Creating Flash backup)_..."]').val("_(Flash backup)_").prop('disabled',false);
|
||||
$('div.spinner').hide('slow');
|
||||
$('#pleaseWait').hide('slow');
|
||||
$.post('/webGui/include/Download.php',{cmd:'unlink',file:zip});
|
||||
} else {
|
||||
setTimeout(cleanUp,2000);
|
||||
setTimeout(function(){cleanUpFlashBackup(zip);},2000);
|
||||
}
|
||||
}
|
||||
function zipfile(){
|
||||
var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
|
||||
var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0,-1);
|
||||
return '<?=$zip?>-diagnostics-'+localISOTime.substr(0,16).replace(/[-:]/g,'').replace('T','-')+'.zip';
|
||||
}
|
||||
function diagnostics(file) {
|
||||
nchan_diagnostics.start();
|
||||
$.post('/webGui/include/Download.php',{cmd:'diag',file:file,anonymize:''},function(zip) {
|
||||
function flashBackup() {
|
||||
$('input[value="_(Flash backup)_"]').val('_(Creating Flash backup)_...').prop('disabled',true);
|
||||
$('div.spinner').show('slow');
|
||||
$('#pleaseWait').show('slow');
|
||||
$.post('/webGui/include/Download.php',{cmd:'backup'},function(zip) {
|
||||
if (zip) {
|
||||
diagnosticsFile = zip;
|
||||
swal({title:"_(Downloading)_...",text:"/boot/logs"+zip+"<hr><pre id='swaltext'></pre>",html:true,animation:'none',showConfirmButton:false});
|
||||
$('.sweet-alert').addClass('nchan');
|
||||
$('button.confirm').prop('disabled',true);
|
||||
location = '/'+zip;
|
||||
setTimeout(function(){cleanUpFlashBackup(zip);},6000);
|
||||
} else {
|
||||
nchan_diagnostics.stop();
|
||||
$('input[value="_(Creating Flash backup)_..."]').val("_(Flash backup)_");
|
||||
$('div.spinner').hide('slow');
|
||||
$('#pleaseWait').hide('slow');
|
||||
swal({title:"_(Creation error)_",text:"_(Insufficient free disk space available)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
|
||||
}
|
||||
});
|
||||
}
|
||||
$(function() {
|
||||
initlist();
|
||||
$('.tabs').append("<span class='status vhshift'><input type='button' id='checkos' value=\"_(Check for Updates)_\" onclick='openPlugin(\"plugin checkos\",\"_(System Update Check)_\",\":return\")' disabled></span>");
|
||||
});
|
||||
</script>
|
||||
<table class='tablesorter plugins shift' id='os_table'>
|
||||
<thead><tr><th></th><th>_(Component)_</th><th>_(Author)_</th><th>_(Version)_</th><th>_(Status)_</th><th>_(Branch)_</th></tr></thead>
|
||||
<tbody id="os_list"><tr><td colspan="6"></td></tr></tbody>
|
||||
<?if ($bzroot):?>
|
||||
<tbody id="previous" style="display:none"><tr><td><img src="/plugins/unRAIDServer/images/unRAIDServer.png" class="list"></td><td><b>_(Unraid OS)_ (_(previous)_)</b></td><td>LimeTech</td><td><?=$version?></td><td><input type="button" value="_(Restore)_" onclick="downgrade()"></td><td><?=$branch?></td></tbody>
|
||||
<?endif;?>
|
||||
</table>
|
||||
|
||||
<unraid-i18n-host>
|
||||
<unraid-update-os reboot-version="<?= $rebootDetails->rebootVersion ?>"></unraid-update-os>
|
||||
</unraid-i18n-host>
|
||||
|
@@ -11,8 +11,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/webGui/include/Secure.php";
|
||||
|
||||
|
@@ -11,6 +11,9 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
|
||||
// Invoke the plugin command with indicated method
|
||||
function plugin($method, $arg = '') {
|
||||
global $docroot;
|
||||
@@ -27,7 +30,7 @@ function language($method, $arg = '') {
|
||||
|
||||
function check_plugin($arg, &$ncsi) {
|
||||
// Get network connection status indicator (NCSI)
|
||||
if ($ncsi===null) $ncsi = exec("wget --spider --no-check-certificate -nv -T10 -t1 https://www.msftncsi.com/ncsi.txt 2>&1|grep -o 'OK'");
|
||||
if ($ncsi===null) $ncsi = check_network_connectivity();
|
||||
return $ncsi ? plugin('check',$arg) : false;
|
||||
}
|
||||
|
||||
|
@@ -11,8 +11,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
|
||||
|
@@ -11,8 +11,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Helpers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
|
||||
|
261
emhttp/plugins/dynamix.plugin.manager/include/UnraidCheck.php
Normal file
261
emhttp/plugins/dynamix.plugin.manager/include/UnraidCheck.php
Normal file
@@ -0,0 +1,261 @@
|
||||
<?php
|
||||
/* Copyright 2005-2024, Lime Technology
|
||||
* Copyright 2012-2024, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
/**
|
||||
* Abstracting this code into a separate file allows us to use it in multiple places without duplicating code.
|
||||
* 1. unraidcheck script can call this
|
||||
* require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
|
||||
* $unraidOsCheck = new UnraidOsCheck();
|
||||
* $unraidOsCheck->checkForUpdate();
|
||||
*
|
||||
* 2. Unraid webgui web components can GET this file with action params to get updates, ignore updates, etc.
|
||||
* - EX: Unraid webgui web components can check for updates via a GET request and receive a response with the json file directly
|
||||
* - this is useful for the UPC to check for updates and display a model based on the value
|
||||
* - `/plugins/dynamix.plugin.manager/scripts/unraidcheck.php?json=true`
|
||||
* - note the json=true query param to receive a json response
|
||||
*
|
||||
* @param action {'check'|'removeAllIgnored'|'removeIgnoredVersion'|'ignoreVersion'} - the action to perform
|
||||
* @param version {string} - the version to ignore or remove
|
||||
* @param json {string} - if set to true, will return the json response from the external request
|
||||
* @param altUrl {URL} - if set, will use this url instead of the default
|
||||
*/
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
|
||||
class UnraidOsCheck
|
||||
{
|
||||
private const BASE_RELEASES_URL = 'https://releases.unraid.net/os';
|
||||
private const JSON_FILE_IGNORED = '/tmp/unraidcheck/ignored.json';
|
||||
private const JSON_FILE_IGNORED_KEY = 'updateOsIgnoredReleases';
|
||||
private const JSON_FILE_RESULT = '/tmp/unraidcheck/result.json';
|
||||
private const PLG_PATH = '/usr/local/emhttp/plugins/unRAIDServer/unRAIDServer.plg';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
|
||||
$getHasAction = $_GET !== null && !empty($_GET) && isset($_GET['action']);
|
||||
|
||||
if ($isGetRequest && $getHasAction) {
|
||||
$this->handleGetRequestWithActions();
|
||||
}
|
||||
}
|
||||
|
||||
private function handleGetRequestWithActions()
|
||||
{
|
||||
switch ($_GET['action']) {
|
||||
case 'check':
|
||||
$this->checkForUpdate();
|
||||
break;
|
||||
|
||||
case 'removeAllIgnored':
|
||||
$this->removeAllIgnored();
|
||||
break;
|
||||
|
||||
case 'removeIgnoredVersion':
|
||||
if (isset($_GET['version'])) {
|
||||
$this->removeIgnoredVersion($_GET['version']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ignoreVersion':
|
||||
if (isset($_GET['version'])) {
|
||||
$this->ignoreVersion($_GET['version']);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->respondWithError(400, "Unhandled action");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function getUnraidOSCheckResult()
|
||||
{
|
||||
if (file_exists(self::JSON_FILE_RESULT)) {
|
||||
return $this->readJsonFile(self::JSON_FILE_RESULT);
|
||||
}
|
||||
}
|
||||
|
||||
public function getIgnoredReleases()
|
||||
{
|
||||
if (!file_exists(self::JSON_FILE_IGNORED)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$ignoredData = $this->readJsonFile(self::JSON_FILE_IGNORED);
|
||||
|
||||
if (is_array($ignoredData) && array_key_exists(self::JSON_FILE_IGNORED_KEY, $ignoredData)) {
|
||||
return $ignoredData[self::JSON_FILE_IGNORED_KEY];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/** @todo clean up this method to be more extensible */
|
||||
public function checkForUpdate()
|
||||
{
|
||||
// Multi-language support
|
||||
if (!function_exists('_')) {
|
||||
function _($text) {return $text;}
|
||||
}
|
||||
|
||||
// this command will set the $notify array
|
||||
extract(parse_plugin_cfg('dynamix', true));
|
||||
|
||||
$var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
|
||||
|
||||
$params = [];
|
||||
$params['branch'] = plugin('category', self::PLG_PATH, 'stable');
|
||||
$params['current_version'] = plugin('version', self::PLG_PATH) ?: _var($var,'version');
|
||||
if (_var($var,'regExp')) $params['update_exp'] = date('Y-m-d', _var($var,'regExp')*1);
|
||||
$defaultUrl = self::BASE_RELEASES_URL;
|
||||
// pass a param of altUrl to use the provided url instead of the default
|
||||
$parsedAltUrl = (array_key_exists('altUrl',$_GET) && $_GET['altUrl']) ? $_GET['altUrl'] : null;
|
||||
// if $parsedAltUrl pass to params
|
||||
if ($parsedAltUrl) $params['altUrl'] = $parsedAltUrl;
|
||||
|
||||
$urlbase = $parsedAltUrl ?? $defaultUrl;
|
||||
$url = $urlbase.'?'.http_build_query($params);
|
||||
$curlinfo = [];
|
||||
$response = http_get_contents($url,[],$curlinfo);
|
||||
if (array_key_exists('error', $curlinfo)) {
|
||||
$response = json_encode(array('error' => $curlinfo['error']), JSON_PRETTY_PRINT);
|
||||
}
|
||||
$responseMutated = json_decode($response, true);
|
||||
if (!$responseMutated) {
|
||||
$response = json_encode(array('error' => 'Invalid response from '.$urlbase), JSON_PRETTY_PRINT);
|
||||
$responseMutated = json_decode($response, true);
|
||||
}
|
||||
|
||||
// add params that were used for debugging
|
||||
$responseMutated['params'] = $params;
|
||||
|
||||
// store locally for UPC to access
|
||||
$this->writeJsonFile(self::JSON_FILE_RESULT, $responseMutated);
|
||||
|
||||
// if we have a query param of json=true then just output the json
|
||||
if (array_key_exists('json',$_GET) && $_GET['json']) {
|
||||
header('Content-Type: application/json');
|
||||
echo $response;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// send notification if a newer version is available and not ignored
|
||||
$isNewerVersion = array_key_exists('isNewer',$responseMutated) ? $responseMutated['isNewer'] : false;
|
||||
$isReleaseIgnored = array_key_exists('version',$responseMutated) ? in_array($responseMutated['version'], $this->getIgnoredReleases()) : false;
|
||||
|
||||
if ($responseMutated && $isNewerVersion && !$isReleaseIgnored) {
|
||||
$output = _var($notify,'plugin');
|
||||
$server = strtoupper(_var($var,'NAME','server'));
|
||||
$newver = (array_key_exists('version',$responseMutated) && $responseMutated['version']) ? $responseMutated['version'] : 'unknown';
|
||||
$script = '/usr/local/emhttp/webGui/scripts/notify';
|
||||
$event = "System - Unraid [$newver]";
|
||||
$subject = "Notice [$server] - Version update $newver";
|
||||
$description = "A new version of Unraid is available";
|
||||
exec("$script -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Tools/Update' -x");
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
private function removeAllIgnored()
|
||||
{
|
||||
if (file_exists(self::JSON_FILE_IGNORED)) {
|
||||
$this->deleteJsonFile(self::JSON_FILE_IGNORED);
|
||||
$this->respondWithSuccess([]);
|
||||
}
|
||||
// fail silently if file doesn't exist
|
||||
}
|
||||
|
||||
private function removeIgnoredVersion($removeVersion)
|
||||
{
|
||||
if ($this->isValidSemVerFormat($removeVersion)) {
|
||||
if (file_exists(self::JSON_FILE_IGNORED)) {
|
||||
$existingData = $this->readJsonFile(self::JSON_FILE_IGNORED);
|
||||
|
||||
if (isset($existingData[self::JSON_FILE_IGNORED_KEY])) {
|
||||
$existingData[self::JSON_FILE_IGNORED_KEY] = array_diff($existingData[self::JSON_FILE_IGNORED_KEY], [$removeVersion]);
|
||||
$this->writeJsonFile(self::JSON_FILE_IGNORED, $existingData);
|
||||
$this->respondWithSuccess($existingData);
|
||||
} else {
|
||||
$this->respondWithError(400, "No versions to remove in the JSON file");
|
||||
}
|
||||
} else {
|
||||
$this->respondWithError(400, "No JSON file found");
|
||||
}
|
||||
} else {
|
||||
$this->respondWithError(400, "Invalid removeVersion format");
|
||||
}
|
||||
}
|
||||
|
||||
private function ignoreVersion($version)
|
||||
{
|
||||
if ($this->isValidSemVerFormat($version)) {
|
||||
$newData = [$this::JSON_FILE_IGNORED_KEY => [$version]];
|
||||
$existingData = file_exists(self::JSON_FILE_IGNORED) ? $this->readJsonFile(self::JSON_FILE_IGNORED) : [];
|
||||
|
||||
if (isset($existingData[self::JSON_FILE_IGNORED_KEY])) {
|
||||
$existingData[self::JSON_FILE_IGNORED_KEY][] = $version;
|
||||
} else {
|
||||
$existingData[self::JSON_FILE_IGNORED_KEY] = [$version];
|
||||
}
|
||||
|
||||
$this->writeJsonFile(self::JSON_FILE_IGNORED, $existingData);
|
||||
$this->respondWithSuccess($existingData);
|
||||
} else {
|
||||
$this->respondWithError(400, "Invalid version format");
|
||||
}
|
||||
}
|
||||
|
||||
private function isValidSemVerFormat($version)
|
||||
{
|
||||
return preg_match('/^\d+\.\d+(\.\d+)?(-.+)?$/', $version);
|
||||
}
|
||||
|
||||
private function readJsonFile($file)
|
||||
{
|
||||
return @json_decode(@file_get_contents($file), true) ?? [];
|
||||
}
|
||||
|
||||
private function writeJsonFile($file, $data)
|
||||
{
|
||||
if (!is_dir(dirname($file))) { // prevents errors when directory doesn't exist
|
||||
mkdir(dirname($file));
|
||||
}
|
||||
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
|
||||
private function deleteJsonFile($file)
|
||||
{
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
private function respondWithError($statusCode, $message)
|
||||
{
|
||||
http_response_code($statusCode);
|
||||
echo $message;
|
||||
}
|
||||
|
||||
private function respondWithSuccess($data)
|
||||
{
|
||||
http_response_code(200);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($data, JSON_PRETTY_PRINT);
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate and handle the request for GET requests with actions – vars are duplicated here for multi-use of this file
|
||||
$isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
|
||||
$getHasAction = $_GET !== null && !empty($_GET) && isset($_GET['action']);
|
||||
if ($isGetRequest && $getHasAction) {
|
||||
new UnraidOsCheck();
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
class UnraidUpdateCancel
|
||||
{
|
||||
private $PLG_FILENAME;
|
||||
private $PLG_BOOT;
|
||||
private $PLG_VAR;
|
||||
private $USR_LOCAL_PLUGIN_UNRAID_PATH;
|
||||
|
||||
public function __construct() {
|
||||
$this->PLG_FILENAME = "unRAIDServer.plg";
|
||||
$this->PLG_BOOT = "/boot/config/plugins/{$this->PLG_FILENAME}";
|
||||
$this->PLG_VAR = "/var/log/plugins/{$this->PLG_FILENAME}";
|
||||
$this->USR_LOCAL_PLUGIN_UNRAID_PATH = "/usr/local/emhttp/plugins/unRAIDServer";
|
||||
|
||||
// Handle the cancellation
|
||||
$revertResult = $this->revertFiles();
|
||||
// Return JSON response for front-end client
|
||||
$statusCode = $revertResult['success'] ? 200 : 500;
|
||||
http_response_code($statusCode);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($revertResult);
|
||||
}
|
||||
|
||||
public function revertFiles() {
|
||||
try {
|
||||
$command = '/sbin/mount | grep -q "/boot/previous/bz"';
|
||||
exec($command, $output, $returnCode);
|
||||
|
||||
if ($returnCode !== 0) {
|
||||
return ['success' => true]; // Nothing to revert
|
||||
}
|
||||
|
||||
// Clear the results of previous unraidcheck run
|
||||
@unlink("/tmp/unraidcheck/result.json");
|
||||
|
||||
// Revert changes made by unRAIDServer.plg
|
||||
shell_exec("mv -f /boot/previous/* /boot");
|
||||
unlink($this->PLG_BOOT);
|
||||
unlink($this->PLG_VAR);
|
||||
symlink("{$this->USR_LOCAL_PLUGIN_UNRAID_PATH}/{$this->PLG_FILENAME}", $this->PLG_VAR);
|
||||
|
||||
// Restore README.md by echoing the content into the file
|
||||
$readmeFile = "{$this->USR_LOCAL_PLUGIN_UNRAID_PATH}/README.md";
|
||||
$readmeContent = "**Unraid OS**\n\n";
|
||||
$readmeContent .= "Unraid OS by [Lime Technology, Inc.](https://lime-technology.com).\n";
|
||||
file_put_contents($readmeFile, $readmeContent);
|
||||
|
||||
return ['success' => true]; // Upgrade handled successfully
|
||||
} catch (\Throwable $th) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => $th->getMessage(),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Self instantiate the class and handle the cancellation
|
||||
new UnraidUpdateCancel();
|
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: "/usr/local/emhttp";
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
|
||||
function readJson($file) {
|
||||
@@ -24,7 +24,7 @@ function newurl($url) {
|
||||
return str_replace($oldURL,$newURL,$url);
|
||||
}
|
||||
function searchLink(&$db,$url) {
|
||||
if ($url) for ($i = 0; $i < count($db); $i++) if ($db[$i]['PluginURL']==$url) return $db[$i]['Support'];
|
||||
if ($url) for ($i = 0; $i < count($db); $i++) if ( ($db[$i]['PluginURL']??null)==$url) return $db[$i]['Support']??null;
|
||||
}
|
||||
|
||||
$type = $argv[1]??''; // plugin or language
|
||||
|
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: "/usr/local/emhttp";
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
|
||||
$type = $argv[1]??''; // plugin or language
|
||||
|
@@ -10,12 +10,13 @@
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
require_once "$docroot/plugins/dynamix/include/Secure.php";
|
||||
|
||||
//add translations
|
||||
$_SERVER['REQUEST_URI'] = "plugins";
|
||||
require_once "$docroot/plugins/dynamix/include/Translations.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
require_once "$docroot/plugins/dynamix/include/Secure.php";
|
||||
|
||||
function download_url($url, $path = "") {
|
||||
$ch = curl_init();
|
||||
@@ -39,21 +40,17 @@ switch ($_POST['action']) {
|
||||
case 'checkPlugin':
|
||||
$options = $_POST['options'] ?? '';
|
||||
$plugin = $options['plugin'] ?? '';
|
||||
|
||||
$name = unbundle($options['name'] ?? $plugin);
|
||||
$file = "/boot/config/plugins/$plugin";
|
||||
$file = realpath($file)==$file ? $file : "";
|
||||
|
||||
if ( ! $plugin || ! file_exists($file) ) {
|
||||
echo json_encode(["updateAvailable"=>false]);
|
||||
break;
|
||||
}
|
||||
|
||||
exec("mkdir -p /tmp/plugins");
|
||||
@unlink("/tmp/plugins/$plugin");
|
||||
$url = plugin("pluginURL","/boot/config/plugins/$plugin");
|
||||
download_url($url,"/tmp/plugins/$plugin");
|
||||
|
||||
$changes = plugin("changes","/tmp/plugins/$plugin");
|
||||
$alerts = plugin("alert","/tmp/plugins/$plugin");
|
||||
$version = plugin("version","/tmp/plugins/$plugin");
|
||||
@@ -69,7 +66,6 @@ switch ($_POST['action']) {
|
||||
} else {
|
||||
@unlink('/tmp/plugins/my_alerts.txt');
|
||||
}
|
||||
|
||||
$update = false;
|
||||
if ( strcmp($version,$installedVersion) > 0 ) {
|
||||
$unraid = parse_ini_file("/etc/unraid-version");
|
||||
@@ -77,17 +73,14 @@ switch ($_POST['action']) {
|
||||
}
|
||||
$updateMessage = sprintf(_("%s: An update is available."),$name);
|
||||
$linkMessage = sprintf(_("Click here to install version %s"),$version);
|
||||
|
||||
echo json_encode(["updateAvailable"=>$update, "version"=>$version, "min"=>$min, "alert"=>$alerts, "changes"=>$changes, "installedVersion"=>$installedVersion, "updateMessage"=>$updateMessage, "linkMessage"=>$linkMessage]);
|
||||
break;
|
||||
|
||||
case 'addRebootNotice':
|
||||
$message = htmlspecialchars(trim($_POST['message']));
|
||||
if ( ! $message ) break;
|
||||
|
||||
$existing = @file("/tmp/reboot_notifications",FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [];
|
||||
if (!$message) break;
|
||||
$existing = (array)@file("/tmp/reboot_notifications",FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
$existing[] = $message;
|
||||
|
||||
file_put_contents("/tmp/reboot_notifications",implode("\n",array_unique($existing)));
|
||||
break;
|
||||
|
||||
|
@@ -12,8 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
|
||||
@@ -45,7 +44,7 @@ function write(...$messages){
|
||||
}
|
||||
|
||||
write(_("Checking connectivity")." ...\n");
|
||||
if (exec("wget --spider --no-check-certificate -nv -T10 -t1 https://www.msftncsi.com/ncsi.txt 2>&1|grep -om1 'OK'")) {
|
||||
if (check_network_connectivity()) {
|
||||
$check = popen('plugin checkall','r');
|
||||
while (!feof($check)) write(fgets($check));
|
||||
pclose($check);
|
||||
|
@@ -6,6 +6,10 @@
|
||||
// Program updates made by Bergware International (April 2020)
|
||||
// Program updates made by Bergware International (June 2022)
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
$logger = 'language-manager';
|
||||
|
||||
$usage = <<<EOF
|
||||
Process language files.
|
||||
|
||||
@@ -148,12 +152,6 @@ function download($url, $name, &$error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Deal with logging message.
|
||||
//
|
||||
function logger($message) {
|
||||
exec("logger -t 'language-manager' -- \"$message\"");
|
||||
}
|
||||
|
||||
// Interpret a language file
|
||||
// Returns TRUE if success, else FALSE and fills in error string.
|
||||
//
|
||||
@@ -314,7 +312,7 @@ if ($method == 'install') {
|
||||
copy($xml_file, $lang_file);
|
||||
symlink($lang_file, $link_file);
|
||||
write("language: $lang language pack installed\n");
|
||||
logger("$lang language pack installed");
|
||||
my_logger("$lang language pack installed", $logger);
|
||||
// run hook scripts for post processing
|
||||
post_hooks();
|
||||
done(0);
|
||||
@@ -396,7 +394,7 @@ if ($method == 'update') {
|
||||
copy($xml_file, $lang_file);
|
||||
symlink($lang_file, $link_file);
|
||||
write("language: $lang language pack updated\n");
|
||||
logger("$lang language pack updated");
|
||||
my_logger("$lang language pack updated", $logger);
|
||||
// run hook scripts for post processing
|
||||
post_hooks();
|
||||
done(0);
|
||||
@@ -423,7 +421,7 @@ if ($method == 'remove') {
|
||||
done(1);
|
||||
}
|
||||
write("language: $lang language pack removed\n");
|
||||
logger("$lang language pack removed");
|
||||
my_logger("$lang language pack removed", $logger);
|
||||
// run hook scripts for post processing
|
||||
post_hooks();
|
||||
done(0);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* Copyright 2005-2024, Lime Technology
|
||||
* Copyright 2012-2024, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -12,10 +12,10 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
// this command will set the $notify array
|
||||
extract(parse_plugin_cfg('dynamix', true));
|
||||
|
||||
// Multi-language support
|
||||
@@ -23,7 +23,7 @@ $_SERVER['REQUEST_URI'] = "scripts";
|
||||
$login_locale = _var($display,'locale');
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
$var = @parse_ini_file('/var/local/emhttp/var.ini') ?: [];
|
||||
$var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
|
||||
|
||||
function apos($text) {
|
||||
// So that "'" doesn't show up in email
|
||||
|
@@ -1,11 +1,15 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
// Copyright 2005-2022, Lime Technology
|
||||
// Copyright 2005-2023, Lime Technology
|
||||
// License: GPLv2 only
|
||||
//
|
||||
// Program updates made by Bergware International (April 2020)
|
||||
// Program updates made by Bergware International (June 2022)
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
$logger = 'plugin-manager';
|
||||
|
||||
$usage = <<<EOF
|
||||
Process plugin files.
|
||||
|
||||
@@ -154,7 +158,7 @@ function error_desc($code) {
|
||||
case 2: return 'Parse error';
|
||||
case 3: return 'File I/O error';
|
||||
case 4: return 'Network failure';
|
||||
case 5: return 'SSL verification failure';
|
||||
case 5: return 'SSL verification failure - Check the date and time of your server in Settings - Date And Time';
|
||||
case 6: return 'Username/password authentication failure';
|
||||
case 7: return 'Protocol errors';
|
||||
case 8: return 'Invalid URL / Server error response';
|
||||
@@ -275,18 +279,12 @@ function filter_url($url) {
|
||||
if (strpos($url, '.cdn') !== false) {
|
||||
$new_url = str_replace('"', '', $url);
|
||||
$new_url = str_replace('.cdn', '', $new_url);
|
||||
} else {
|
||||
} else {
|
||||
$new_url = "";
|
||||
}
|
||||
return($new_url);
|
||||
}
|
||||
|
||||
// Deal with logging message.
|
||||
//
|
||||
function logger($message) {
|
||||
exec("logger -t 'plugin-manager' -- \"$message\"");
|
||||
}
|
||||
|
||||
// Interpret a plugin file
|
||||
// Returns TRUE if success, else FALSE and fills in error string.
|
||||
//
|
||||
@@ -295,7 +293,7 @@ function logger($message) {
|
||||
// is processed for any of those methods.
|
||||
//
|
||||
function plugin($method, $plugin_file, &$error) {
|
||||
global $unraid;
|
||||
global $unraid, $logger;
|
||||
$methods = ['install', 'remove'];
|
||||
|
||||
// parse plugin definition XML file
|
||||
@@ -357,7 +355,7 @@ function plugin($method, $plugin_file, &$error) {
|
||||
if (isset($file->attributes()->Method)) {
|
||||
if (!in_array($method, explode(" ", $file->attributes()->Method))) continue;
|
||||
} elseif ($method != 'install') continue;
|
||||
$name = $file->attributes()->Name;
|
||||
$name = $file->attributes()->Name ?: '';
|
||||
// bergware - check Unraid version dependency (if present)
|
||||
$min = $file->attributes()->Min;
|
||||
if ($min && version_compare($unraid['version'],$min,'<')) {
|
||||
@@ -382,12 +380,12 @@ function plugin($method, $plugin_file, &$error) {
|
||||
// If file already exists, check the SHA256/MD5 (if supplied)
|
||||
if (file_exists($name)) {
|
||||
if ($file->SHA256) {
|
||||
logger("checking: $name - SHA256");
|
||||
my_logger("checking: $name - SHA256", $logger);
|
||||
if (hash_file('sha256', $name) != $file->SHA256) {
|
||||
unlink($name);
|
||||
}
|
||||
} elseif ($file->MD5) {
|
||||
logger("checking: $name - MD5");
|
||||
my_logger("checking: $name - MD5", $logger);
|
||||
if (md5_file($name) != $file->MD5) {
|
||||
unlink($name);
|
||||
}
|
||||
@@ -396,12 +394,12 @@ function plugin($method, $plugin_file, &$error) {
|
||||
// If file already exists, do not overwrite
|
||||
//
|
||||
if (file_exists($name)) {
|
||||
logger("skipping: $name already exists");
|
||||
my_logger("skipping: $name already exists", $logger);
|
||||
} elseif ($file->LOCAL) {
|
||||
// Create the file
|
||||
//
|
||||
// for local file, just copy it
|
||||
logger("creating: $name - copying LOCAL file $file->LOCAL");
|
||||
my_logger("creating: $name - copying LOCAL file $file->LOCAL", $logger);
|
||||
if (!copy($file->LOCAL, $name)) {
|
||||
$error = "unable to copy LOCAL file: $name";
|
||||
@unlink($name);
|
||||
@@ -409,10 +407,10 @@ function plugin($method, $plugin_file, &$error) {
|
||||
}
|
||||
} elseif ($file->INLINE) {
|
||||
// for inline file, create with inline contents
|
||||
logger("creating: $name - from INLINE content");
|
||||
my_logger("creating: $name - from INLINE content", $logger);
|
||||
$contents = trim($file->INLINE).PHP_EOL;
|
||||
if ($file->attributes()->Type == 'base64') {
|
||||
logger("decoding: $name as base64");
|
||||
my_logger("decoding: $name as base64", $logger);
|
||||
$contents = base64_decode($contents);
|
||||
if ($contents === false) {
|
||||
$error = "unable to decode inline base64: $name";
|
||||
@@ -426,20 +424,20 @@ function plugin($method, $plugin_file, &$error) {
|
||||
}
|
||||
} elseif ($file->URL) {
|
||||
// for download file, download and maybe verify the file MD5
|
||||
logger("creating: $name - downloading from URL $file->URL");
|
||||
my_logger("creating: $name - downloading from URL $file->URL", $logger);
|
||||
if ( (download($file->URL, $name, $error) === false) && (download(filter_url($file->URL), $name, $error) === false) ) {
|
||||
@unlink($name);
|
||||
return false;
|
||||
}
|
||||
if ($file->SHA256) {
|
||||
logger("checking: $name - SHA256");
|
||||
my_logger("checking: $name - SHA256", $logger);
|
||||
if (hash_file('sha256', $name) != $file->SHA256) {
|
||||
$error = "bad file SHA256: $name";
|
||||
unlink($name);
|
||||
return false;
|
||||
}
|
||||
} elseif ($file->MD5) {
|
||||
logger("checking: $name - MD5");
|
||||
my_logger("checking: $name - MD5", $logger);
|
||||
if (md5_file($name) != $file->MD5) {
|
||||
$error = "bad file MD5: $name";
|
||||
unlink($name);
|
||||
@@ -452,7 +450,7 @@ function plugin($method, $plugin_file, &$error) {
|
||||
if ($file->attributes()->Mode) {
|
||||
// if file has 'Mode' attribute, apply it
|
||||
$mode = $file->attributes()->Mode;
|
||||
logger("setting: $name - mode to $mode");
|
||||
my_logger("setting: $name - mode to $mode", $logger);
|
||||
if (!chmod($name, octdec($mode))) {
|
||||
$error = "chmod failure: $name";
|
||||
return false;
|
||||
@@ -464,13 +462,13 @@ function plugin($method, $plugin_file, &$error) {
|
||||
if ($file->attributes()->Run) {
|
||||
$command = $file->attributes()->Run;
|
||||
if ($name) {
|
||||
logger("running: $command $name");
|
||||
my_logger("running: $command $name", $logger);
|
||||
$retval = run("$command $name");
|
||||
} elseif ($file->LOCAL) {
|
||||
logger("running: $command $file->LOCAL");
|
||||
my_logger("running: $command $file->LOCAL", $logger);
|
||||
$retval = run("$command $file->LOCAL");
|
||||
} elseif ($file->INLINE) {
|
||||
logger("running: 'anonymous'");
|
||||
my_logger("running: 'anonymous'", $logger);
|
||||
$name = '/tmp/inline.sh';
|
||||
file_put_contents($name, $file->INLINE);
|
||||
$retval = run("$command $name");
|
||||
@@ -691,7 +689,7 @@ if ($method == 'install') {
|
||||
$event = "Install error";
|
||||
$subject = "plugin: ".basename($plugin_file);
|
||||
$description = "Plugin failed to install";
|
||||
exec("$notify -e $event -s $subject -d $description) -i 2");
|
||||
exec("$notify -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i 'warning'");
|
||||
// run hook scripts for post processing
|
||||
post_hooks($error);
|
||||
done(1);
|
||||
@@ -718,10 +716,10 @@ if ($method == 'install') {
|
||||
if ($target != $plugin_file) copy($plugin_file, $target);
|
||||
symlink($target, $symlink);
|
||||
write("plugin: $plugin installed\n");
|
||||
logger("$plugin installed");
|
||||
my_logger("$plugin installed", $logger);
|
||||
} else {
|
||||
write("script: $plugin executed\n");
|
||||
logger("script: $plugin executed");
|
||||
my_logger("script: $plugin executed", $logger);
|
||||
}
|
||||
// run hook scripts for post processing
|
||||
post_hooks();
|
||||
@@ -835,7 +833,7 @@ if ($method == 'update') {
|
||||
copy($plugin_file, $target);
|
||||
symlink($target, $symlink);
|
||||
write("plugin: $plugin updated\n");
|
||||
logger("$plugin updated");
|
||||
my_logger("$plugin updated", $logger);
|
||||
// run hook scripts for post processing
|
||||
post_hooks();
|
||||
done(0);
|
||||
@@ -867,7 +865,7 @@ if ($method == 'remove') {
|
||||
// remove the plugin file
|
||||
move($installed_plugin_file, "$boot-removed");
|
||||
write("plugin: $plugin removed\n");
|
||||
logger("$plugin removed");
|
||||
my_logger("$plugin removed", $logger);
|
||||
exec("/usr/local/sbin/update_cron");
|
||||
// run hook scripts for post processing
|
||||
post_hooks();
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/php -q
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
* Copyright 2012-2023, Bergware International.
|
||||
/* Copyright 2005-2024, Lime Technology
|
||||
* Copyright 2012-2024, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
@@ -12,11 +12,10 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
|
||||
// this command will set the $notify array
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
|
||||
// Multi-language support
|
||||
@@ -24,7 +23,7 @@ $_SERVER['REQUEST_URI'] = "scripts";
|
||||
$login_locale = _var($display,'locale');
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
$var = @parse_ini_file('/var/local/emhttp/var.ini') ?: [];
|
||||
$var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
|
||||
|
||||
function apos($text) {
|
||||
// So that "'" doesn't show up in email
|
||||
|
@@ -12,8 +12,7 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
extract(parse_plugin_cfg('dynamix',true));
|
||||
|
||||
@@ -23,7 +22,7 @@ $login_locale = _var($display,'locale');
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
$file = realpath($argv[1]??'');
|
||||
$valid = ['/var/tmp/','/tmp/plugins/'];
|
||||
$valid = ['/var/tmp/','/tmp/plugins/','/boot/previous'];
|
||||
$good = false;
|
||||
|
||||
foreach ($valid as $check) if (strncmp($file,$check,strlen($check))===0) $good = true;
|
||||
|
@@ -12,35 +12,8 @@
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
|
||||
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
|
||||
|
||||
require_once "$docroot/webGui/include/Wrappers.php";
|
||||
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
|
||||
|
||||
// Multi-language support
|
||||
if (!function_exists('_')) {
|
||||
function _($text) {return $text;}
|
||||
}
|
||||
|
||||
extract(parse_plugin_cfg('dynamix', true));
|
||||
|
||||
$var = @parse_ini_file('/var/local/emhttp/var.ini') ?: [];
|
||||
$script = "$docroot/webGui/scripts/notify";
|
||||
$server = strtoupper(_var($var,'NAME','server'));
|
||||
$output = _var($notify,'plugin');
|
||||
$builtin = ['unRAIDServer'];
|
||||
|
||||
foreach ($builtin as $name) {
|
||||
$plg = "$name.plg";
|
||||
plugin('check',$plg);
|
||||
$file = "/tmp/plugins/$plg";
|
||||
$old = plugin('version', "/var/log/plugins/$plg");
|
||||
$new = plugin('version', $file);
|
||||
|
||||
// silently suppress bad download of PLG file
|
||||
if (version_compare($new,$old,'>')) {
|
||||
exec("$script -e ".escapeshellarg("System - $name [$new]")." -s ".escapeshellarg("Notice [$server] - Version update $new")." -d ".escapeshellarg("A new version of $name is available")." -i ".escapeshellarg("normal $output")." -l '/Tools/Update' -x");
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
?>
|
||||
$unraidOsCheck = new UnraidOsCheck();
|
||||
$unraidOsCheck->checkForUpdate();
|
||||
|
@@ -0,0 +1,5 @@
|
||||
.ca_element_notice{padding-right:20px;width:100%;height:40px;line-height:40px;color:#e68a00;background:#feefb3;border-bottom:#e68a00 1px solid;text-align:center;font-size:1.4rem;z-index:900}
|
||||
a.ca_PluginUpdateInstall{cursor:pointer}
|
||||
span.ca_PluginUpdateDismiss{float:right;margin-right:20px;cursor:pointer}
|
||||
span.bannerInfo {cursor:pointer;text-decoration:none;margin:0 12px 0 6px}
|
||||
span.bannerInfo::before {content:"\f05a";font-family:fontAwesome;color:#e68a00}
|
2
emhttp/plugins/dynamix.plugin.manager/sheets/Plugins.css
Normal file
2
emhttp/plugins/dynamix.plugin.manager/sheets/Plugins.css
Normal file
@@ -0,0 +1,2 @@
|
||||
#plugin_tree{width:33%;height:200px;overflow-y:scroll}
|
||||
table tbody td{line-height:normal}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user